From 5f8de423f190bbb79a62f804151bc24824fa32d8 Mon Sep 17 00:00:00 2001 From: "Matt A. Tobin" Date: Fri, 2 Feb 2018 04:16:08 -0500 Subject: Add m-esr52 at 52.6.0 --- toolkit/crashreporter/CrashReports.jsm | 91 + toolkit/crashreporter/CrashSubmit.jsm | 570 ++ toolkit/crashreporter/InjectCrashReporter.cpp | 84 + toolkit/crashreporter/InjectCrashReporter.h | 28 + toolkit/crashreporter/KeyValueParser.jsm | 54 + toolkit/crashreporter/LoadLibraryRemote.cpp | 454 + toolkit/crashreporter/LoadLibraryRemote.h | 24 + .../breakpad-patches/00-arm-exidx-rollup.patch | 1347 +++ toolkit/crashreporter/breakpad-patches/README | 4 + .../breakpad-windows-libxul/moz.build | 32 + .../breakpad-windows-standalone/moz.build | 26 + toolkit/crashreporter/client/Makefile.in | 20 + toolkit/crashreporter/client/Throbber-small.avi | Bin 0 -> 3584 bytes toolkit/crashreporter/client/crashreporter.cpp | 759 ++ .../client/crashreporter.exe.manifest | 38 + toolkit/crashreporter/client/crashreporter.h | 158 + toolkit/crashreporter/client/crashreporter.ico | Bin 0 -> 25214 bytes toolkit/crashreporter/client/crashreporter.rc | 148 + .../client/crashreporter_gtk_common.cpp | 453 + .../client/crashreporter_gtk_common.h | 50 + .../crashreporter/client/crashreporter_linux.cpp | 576 ++ toolkit/crashreporter/client/crashreporter_osx.h | 107 + toolkit/crashreporter/client/crashreporter_osx.mm | 922 ++ .../client/crashreporter_unix_common.cpp | 85 + toolkit/crashreporter/client/crashreporter_win.cpp | 1568 ++++ .../client/macbuild/Contents/Info.plist | 32 + .../crashreporter/client/macbuild/Contents/PkgInfo | 2 + .../Resources/English.lproj/InfoPlist.strings.in | 8 + .../English.lproj/MainMenu.nib/classes.nib | 102 + .../Resources/English.lproj/MainMenu.nib/info.nib | 18 + .../English.lproj/MainMenu.nib/keyedobjects.nib | Bin 0 -> 25518 bytes .../English.lproj/MainMenuRTL.nib/classes.nib | 102 + .../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 | 78 + toolkit/crashreporter/client/resource.h | 37 + toolkit/crashreporter/content/crashes.js | 179 + toolkit/crashreporter/content/crashes.xhtml | 123 + toolkit/crashreporter/crashreporter.mozbuild | 27 + toolkit/crashreporter/docs/index.rst | 195 + toolkit/crashreporter/google-breakpad/.gitignore | 83 + toolkit/crashreporter/google-breakpad/AUTHORS | 1 + toolkit/crashreporter/google-breakpad/ChangeLog | 0 toolkit/crashreporter/google-breakpad/DEPS | 75 + 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 | 1510 ++++ toolkit/crashreporter/google-breakpad/Makefile.in | 8221 +++++++++++++++++ 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 | 1297 +++ .../google-breakpad/android/common-functions.sh | 372 + .../android/google_breakpad/Android.mk | 103 + .../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/autotools/compile | 347 + .../google-breakpad/autotools/config.guess | 1447 +++ .../google-breakpad/autotools/config.sub | 1813 ++++ .../google-breakpad/autotools/depcomp | 791 ++ .../google-breakpad/autotools/install-sh | 501 ++ .../google-breakpad/autotools/ltmain.sh | 8406 ++++++++++++++++++ .../google-breakpad/autotools/missing | 215 + .../google-breakpad/autotools/test-driver | 148 + .../google-breakpad/breakpad-client.pc.in | 10 + .../crashreporter/google-breakpad/breakpad.pc.in | 10 + .../google-breakpad/codereview.settings | 4 + toolkit/crashreporter/google-breakpad/configure | 9255 ++++++++++++++++++++ toolkit/crashreporter/google-breakpad/configure.ac | 204 + .../crashreporter/google-breakpad/m4/ax_pthread.m4 | 283 + .../crashreporter/google-breakpad/m4/libtool.m4 | 7377 ++++++++++++++++ .../crashreporter/google-breakpad/m4/ltoptions.m4 | 368 + .../crashreporter/google-breakpad/m4/ltsugar.m4 | 123 + .../crashreporter/google-breakpad/m4/ltversion.m4 | 23 + .../google-breakpad/m4/lt~obsolete.m4 | 92 + .../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.gypi | 90 + .../src/client/apple/Framework/BreakpadDefines.h | 73 + .../google-breakpad/src/client/ios/Breakpad.h | 246 + .../google-breakpad/src/client/ios/Breakpad.mm | 916 ++ .../client/ios/Breakpad.xcodeproj/project.pbxproj | 578 ++ .../src/client/ios/BreakpadController.h | 141 + .../src/client/ios/BreakpadController.mm | 354 + .../src/client/ios/Breakpad_Prefix.pch | 7 + .../ios/handler/ios_exception_minidump_generator.h | 74 + .../handler/ios_exception_minidump_generator.mm | 210 + .../client/linux/crash_generation/client_info.h | 53 + .../crash_generation/crash_generation_client.cc | 105 + .../crash_generation/crash_generation_client.h | 65 + .../crash_generation/crash_generation_server.cc | 333 + .../crash_generation/crash_generation_server.h | 135 + .../src/client/linux/data/linux-gate-amd.sym | 3 + .../src/client/linux/data/linux-gate-intel.sym | 3 + .../client/linux/dump_writer_common/mapping_info.h | 61 + .../linux/dump_writer_common/raw_context_cpu.h | 53 + .../client/linux/dump_writer_common/thread_info.cc | 305 + .../client/linux/dump_writer_common/thread_info.h | 91 + .../linux/dump_writer_common/ucontext_reader.cc | 259 + .../linux/dump_writer_common/ucontext_reader.h | 64 + .../src/client/linux/handler/exception_handler.cc | 789 ++ .../src/client/linux/handler/exception_handler.h | 278 + .../linux/handler/exception_handler_unittest.cc | 1179 +++ .../client/linux/handler/microdump_extra_info.h | 52 + .../client/linux/handler/minidump_descriptor.cc | 87 + .../src/client/linux/handler/minidump_descriptor.h | 149 + .../google-breakpad/src/client/linux/log/log.cc | 84 + .../google-breakpad/src/client/linux/log/log.h | 55 + .../linux/microdump_writer/microdump_writer.cc | 609 ++ .../linux/microdump_writer/microdump_writer.h | 65 + .../microdump_writer/microdump_writer_unittest.cc | 257 + .../src/client/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 + .../src/client/linux/minidump_writer/line_reader.h | 131 + .../linux/minidump_writer/line_reader_unittest.cc | 169 + .../linux/minidump_writer/linux_core_dumper.cc | 258 + .../linux/minidump_writer/linux_core_dumper.h | 125 + .../minidump_writer/linux_core_dumper_unittest.cc | 128 + .../client/linux/minidump_writer/linux_dumper.cc | 776 ++ .../client/linux/minidump_writer/linux_dumper.h | 265 + .../linux_dumper_unittest_helper.cc | 94 + .../linux/minidump_writer/linux_ptrace_dumper.cc | 355 + .../linux/minidump_writer/linux_ptrace_dumper.h | 92 + .../linux_ptrace_dumper_unittest.cc | 470 + .../linux/minidump_writer/minidump_writer.cc | 1376 +++ .../client/linux/minidump_writer/minidump_writer.h | 124 + .../minidump_writer/minidump_writer_unittest.cc | 775 ++ .../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 + .../google-breakpad/src/client/linux/moz.build | 38 + .../linux/sender/google_crash_report_sender.cc | 104 + .../client/mac/Breakpad.xcodeproj/project.pbxproj | 2788 ++++++ .../src/client/mac/Framework/Breakpad.h | 285 + .../src/client/mac/Framework/Breakpad.mm | 1043 +++ .../src/client/mac/Framework/Breakpad_Prefix.pch | 8 + .../src/client/mac/Framework/Info.plist | 26 + .../src/client/mac/Framework/OnDemandServer.h | 145 + .../src/client/mac/Framework/OnDemandServer.mm | 189 + .../src/client/mac/UnitTests-Info.plist | 20 + .../src/client/mac/crash_generation/ConfigFile.h | 83 + .../src/client/mac/crash_generation/ConfigFile.mm | 167 + .../src/client/mac/crash_generation/Inspector.h | 162 + .../src/client/mac/crash_generation/Inspector.mm | 362 + .../client/mac/crash_generation/InspectorMain.mm | 65 + .../src/client/mac/crash_generation/client_info.h | 47 + .../crash_generation/crash_generation_client.cc | 72 + .../mac/crash_generation/crash_generation_client.h | 65 + .../crash_generation/crash_generation_server.cc | 166 + .../mac/crash_generation/crash_generation_server.h | 150 + .../src/client/mac/crash_generation/moz.build | 19 + .../src/client/mac/handler/breakpad_nlist_64.cc | 402 + .../src/client/mac/handler/breakpad_nlist_64.h | 47 + .../src/client/mac/handler/dynamic_images.cc | 573 ++ .../src/client/mac/handler/dynamic_images.h | 319 + .../src/client/mac/handler/exception_handler.cc | 854 ++ .../src/client/mac/handler/exception_handler.h | 281 + .../src/client/mac/handler/mach_vm_compat.h | 48 + .../src/client/mac/handler/minidump_generator.cc | 1604 ++++ .../src/client/mac/handler/minidump_generator.h | 236 + .../minidump_test.xcodeproj/project.pbxproj | 841 ++ .../client/mac/handler/minidump_tests32-Info.plist | 20 + .../client/mac/handler/minidump_tests64-Info.plist | 22 + .../src/client/mac/handler/moz.build | 22 + .../client/mac/handler/obj-cTestCases-Info.plist | 20 + .../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 + .../src/client/mac/handler/testcases/dwarftests.h | 46 + .../src/client/mac/handler/testcases/dwarftests.mm | 60 + .../testcases/testdata/dump_syms_dwarf_data | Bin 0 -> 702795 bytes .../testcases/testdata/dump_syms_i386_breakpad.sym | 5300 +++++++++++ .../src/client/mac/handler/ucontext_compat.h | 47 + .../src/client/mac/sender/Breakpad.xib | 1140 +++ .../mac/sender/English.lproj/InfoPlist.strings | Bin 0 -> 156 bytes .../mac/sender/English.lproj/Localizable.strings | Bin 0 -> 2428 bytes .../src/client/mac/sender/ReporterIcon.graffle | 2489 ++++++ .../mac/sender/crash_report_sender-Info.plist | 32 + .../src/client/mac/sender/crash_report_sender.h | 117 + .../src/client/mac/sender/crash_report_sender.icns | Bin 0 -> 170816 bytes .../src/client/mac/sender/crash_report_sender.m | 755 ++ .../client/mac/sender/da.lproj/InfoPlist.strings | Bin 0 -> 156 bytes .../client/mac/sender/da.lproj/Localizable.strings | Bin 0 -> 2428 bytes .../client/mac/sender/de.lproj/InfoPlist.strings | Bin 0 -> 192 bytes .../client/mac/sender/de.lproj/Localizable.strings | Bin 0 -> 2746 bytes .../client/mac/sender/es.lproj/InfoPlist.strings | Bin 0 -> 184 bytes .../client/mac/sender/es.lproj/Localizable.strings | Bin 0 -> 2578 bytes .../client/mac/sender/fr.lproj/InfoPlist.strings | Bin 0 -> 156 bytes .../client/mac/sender/fr.lproj/Localizable.strings | Bin 0 -> 2694 bytes .../src/client/mac/sender/goArrow.png | Bin 0 -> 3591 bytes .../client/mac/sender/it.lproj/InfoPlist.strings | Bin 0 -> 156 bytes .../client/mac/sender/it.lproj/Localizable.strings | Bin 0 -> 2590 bytes .../client/mac/sender/ja.lproj/InfoPlist.strings | Bin 0 -> 156 bytes .../client/mac/sender/ja.lproj/Localizable.strings | Bin 0 -> 1792 bytes .../client/mac/sender/nl.lproj/InfoPlist.strings | Bin 0 -> 156 bytes .../client/mac/sender/nl.lproj/Localizable.strings | Bin 0 -> 2546 bytes .../client/mac/sender/no.lproj/InfoPlist.strings | Bin 0 -> 156 bytes .../client/mac/sender/no.lproj/Localizable.strings | Bin 0 -> 2484 bytes .../client/mac/sender/sl.lproj/InfoPlist.strings | Bin 0 -> 184 bytes .../client/mac/sender/sl.lproj/Localizable.strings | Bin 0 -> 2632 bytes .../client/mac/sender/sv.lproj/InfoPlist.strings | Bin 0 -> 156 bytes .../client/mac/sender/sv.lproj/Localizable.strings | Bin 0 -> 2588 bytes .../client/mac/sender/tr.lproj/InfoPlist.strings | Bin 0 -> 168 bytes .../client/mac/sender/tr.lproj/Localizable.strings | Bin 0 -> 2430 bytes .../src/client/mac/sender/uploader.h | 89 + .../src/client/mac/sender/uploader.mm | 636 ++ .../src/client/mac/testapp/Controller.h | 65 + .../src/client/mac/testapp/Controller.m | 261 + .../mac/testapp/English.lproj/InfoPlist.strings | Bin 0 -> 192 bytes .../client/mac/testapp/English.lproj/MainMenu.xib | 3748 ++++++++ .../src/client/mac/testapp/Info.plist | 55 + .../src/client/mac/testapp/TestClass.h | 37 + .../src/client/mac/testapp/TestClass.mm | 95 + .../src/client/mac/testapp/bomb.icns | Bin 0 -> 23659 bytes .../src/client/mac/testapp/crashInMain | Bin 0 -> 12588 bytes .../src/client/mac/testapp/crashduringload | Bin 0 -> 12588 bytes .../google-breakpad/src/client/mac/testapp/main.m | 34 + .../src/client/mac/tests/BreakpadFramework_Test.mm | 217 + .../mac/tests/crash_generation_server_test.cc | 398 + .../src/client/mac/tests/exception_handler_test.cc | 713 ++ .../client/mac/tests/minidump_generator_test.cc | 319 + .../mac/tests/minidump_generator_test_helper.cc | 74 + .../src/client/mac/tests/spawn_child_process.h | 149 + .../src/client/mac/tests/testlogging.h | 9 + .../src/client/minidump_file_writer-inl.h | 97 + .../src/client/minidump_file_writer.cc | 350 + .../src/client/minidump_file_writer.h | 272 + .../src/client/minidump_file_writer_unittest.cc | 179 + .../google-breakpad/src/client/moz.build | 18 + .../src/client/solaris/handler/Makefile | 78 + .../client/solaris/handler/exception_handler.cc | 258 + .../src/client/solaris/handler/exception_handler.h | 201 + .../solaris/handler/exception_handler_test.cc | 119 + .../client/solaris/handler/minidump_generator.cc | 786 ++ .../client/solaris/handler/minidump_generator.h | 70 + .../src/client/solaris/handler/minidump_test.cc | 75 + .../src/client/solaris/handler/moz.build | 18 + .../src/client/solaris/handler/solaris_lwp.cc | 436 + .../src/client/solaris/handler/solaris_lwp.h | 160 + .../src/client/windows/breakpad_client.gyp | 66 + .../client/windows/common/auto_critical_section.h | 81 + .../src/client/windows/common/ipc_protocol.h | 181 + .../src/client/windows/crash_generation/ReadMe.txt | 58 + .../client/windows/crash_generation/client_info.cc | 223 + .../client/windows/crash_generation/client_info.h | 177 + .../windows/crash_generation/crash_generation.gyp | 63 + .../crash_generation/crash_generation_client.cc | 405 + .../crash_generation/crash_generation_client.h | 182 + .../crash_generation/crash_generation_server.cc | 931 ++ .../crash_generation/crash_generation_server.h | 299 + .../windows/crash_generation/minidump_generator.cc | 579 ++ .../windows/crash_generation/minidump_generator.h | 199 + .../client/windows/crash_generation/objs.mozbuild | 17 + .../client/windows/handler/exception_handler.cc | 1073 +++ .../client/windows/handler/exception_handler.gyp | 47 + .../src/client/windows/handler/exception_handler.h | 524 ++ .../src/client/windows/handler/objs.mozbuild | 14 + .../client/windows/sender/crash_report_sender.cc | 142 + .../client/windows/sender/crash_report_sender.gyp | 46 + .../client/windows/sender/crash_report_sender.h | 125 + .../src/client/windows/sender/objs.mozbuild | 14 + .../tests/crash_generation_app/abstract_class.cc | 53 + .../tests/crash_generation_app/abstract_class.h | 57 + .../crash_generation_app/crash_generation_app.cc | 522 ++ .../crash_generation_app/crash_generation_app.gyp | 63 + .../crash_generation_app/crash_generation_app.h | 35 + .../crash_generation_app/crash_generation_app.ico | Bin 0 -> 23558 bytes .../crash_generation_app/crash_generation_app.rc | 144 + .../windows/tests/crash_generation_app/resource.h | 73 + .../windows/tests/crash_generation_app/small.ico | Bin 0 -> 23558 bytes .../src/client/windows/unittests/client_tests.gyp | 80 + .../unittests/crash_generation_server_test.cc | 305 + .../src/client/windows/unittests/dump_analysis.cc | 184 + .../src/client/windows/unittests/dump_analysis.h | 102 + .../unittests/exception_handler_death_test.cc | 582 ++ .../unittests/exception_handler_nesting_test.cc | 327 + .../windows/unittests/exception_handler_test.cc | 501 ++ .../windows/unittests/exception_handler_test.h | 61 + .../src/client/windows/unittests/minidump_test.cc | 333 + .../src/client/windows/unittests/testing.gyp | 83 + .../google-breakpad/src/common/Makefile.in | 9 + .../src/common/android/breakpad_getcontext.S | 489 ++ .../common/android/breakpad_getcontext_unittest.cc | 186 + .../src/common/android/include/elf.h | 168 + .../src/common/android/include/link.h | 73 + .../src/common/android/include/sgidefs.h | 41 + .../src/common/android/include/stab.h | 100 + .../src/common/android/include/sys/procfs.h | 124 + .../src/common/android/include/sys/signal.h | 35 + .../src/common/android/include/sys/user.h | 85 + .../src/common/android/include/ucontext.h | 56 + .../src/common/android/testing/include/wchar.h | 76 + .../src/common/android/testing/mkdtemp.h | 110 + .../src/common/android/testing/pthread_fixes.h | 99 + .../src/common/android/ucontext_constants.h | 144 + .../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 | 250 + .../google-breakpad/src/common/convert_UTF.c | 554 ++ .../google-breakpad/src/common/convert_UTF.h | 164 + .../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 | 198 + .../src/common/dwarf/cfi_assembler.h | 269 + .../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 | 675 ++ .../src/common/dwarf/dwarf2reader.cc | 2734 ++++++ .../src/common/dwarf/dwarf2reader.h | 1288 +++ .../src/common/dwarf/dwarf2reader_cfi_unittest.cc | 2468 ++++++ .../src/common/dwarf/dwarf2reader_die_unittest.cc | 487 + .../src/common/dwarf/dwarf2reader_test_common.h | 149 + .../google-breakpad/src/common/dwarf/elf_reader.cc | 1273 +++ .../google-breakpad/src/common/dwarf/elf_reader.h | 166 + .../src/common/dwarf/functioninfo.cc | 231 + .../src/common/dwarf/functioninfo.h | 188 + .../src/common/dwarf/line_state_machine.h | 61 + .../google-breakpad/src/common/dwarf/moz.build | 35 + .../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 | 1075 +++ .../src/common/dwarf_cu_to_module.h | 320 + .../src/common/dwarf_cu_to_module_unittest.cc | 1804 ++++ .../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 + .../google-breakpad/src/common/language.cc | 83 + .../google-breakpad/src/common/language.h | 88 + .../google-breakpad/src/common/linux/crc32.cc | 70 + .../google-breakpad/src/common/linux/crc32.h | 53 + .../src/common/linux/dump_symbols.cc | 1159 +++ .../src/common/linux/dump_symbols.h | 86 + .../src/common/linux/dump_symbols_unittest.cc | 204 + .../src/common/linux/eintr_wrapper.h | 58 + .../src/common/linux/elf_core_dump.cc | 179 + .../src/common/linux/elf_core_dump.h | 148 + .../src/common/linux/elf_core_dump_unittest.cc | 256 + .../src/common/linux/elf_gnu_compat.h | 46 + .../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 | 194 + .../google-breakpad/src/common/linux/elfutils.h | 126 + .../google-breakpad/src/common/linux/file_id.cc | 202 + .../google-breakpad/src/common/linux/file_id.h | 87 + .../src/common/linux/file_id_unittest.cc | 338 + .../src/common/linux/google_crashdump_uploader.cc | 202 + .../src/common/linux/google_crashdump_uploader.h | 107 + .../common/linux/google_crashdump_uploader_test.cc | 170 + .../src/common/linux/guid_creator.cc | 104 + .../src/common/linux/guid_creator.h | 48 + .../src/common/linux/http_upload.cc | 230 + .../google-breakpad/src/common/linux/http_upload.h | 90 + .../google-breakpad/src/common/linux/ignore_ret.h | 40 + .../src/common/linux/libcurl_wrapper.cc | 241 + .../src/common/linux/libcurl_wrapper.h | 93 + .../src/common/linux/linux_libc_support.cc | 237 + .../src/common/linux/linux_libc_support.h | 96 + .../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 | 56 + .../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_upload.cc | 155 + .../src/common/linux/symbol_upload.h | 59 + .../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 | 322 + .../src/common/linux/tests/crash_generator.h | 117 + .../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 | 456 + .../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 | 269 + .../google-breakpad/src/common/mac/MachIPC.h | 301 + .../google-breakpad/src/common/mac/MachIPC.mm | 306 + .../src/common/mac/arch_utilities.cc | 211 + .../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 | 646 ++ .../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 | 539 ++ .../google-breakpad/src/common/mac/macho_reader.h | 460 + .../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 | 268 + .../google-breakpad/src/common/mac/macho_walker.h | 119 + .../google-breakpad/src/common/mac/moz.build | 52 + .../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/md5.cc | 251 + .../crashreporter/google-breakpad/src/common/md5.h | 27 + .../google-breakpad/src/common/memory.h | 249 + .../google-breakpad/src/common/memory_range.h | 145 + .../src/common/memory_range_unittest.cc | 193 + .../google-breakpad/src/common/memory_unittest.cc | 124 + .../src/common/minidump_type_helper.h | 56 + .../google-breakpad/src/common/module.cc | 348 + .../google-breakpad/src/common/module.h | 351 + .../google-breakpad/src/common/module_unittest.cc | 616 ++ .../google-breakpad/src/common/moz.build | 72 + .../google-breakpad/src/common/scoped_ptr.h | 404 + .../src/common/simple_string_dictionary.cc | 45 + .../src/common/simple_string_dictionary.h | 260 + .../common/simple_string_dictionary_unittest.cc | 308 + .../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/solaris/moz.build | 34 + .../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 | 197 + .../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 + .../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 | 105 + .../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 | 420 + .../src/common/windows/http_upload.h | 129 + .../src/common/windows/objs.mozbuild | 15 + .../google-breakpad/src/common/windows/omap.cc | 694 ++ .../google-breakpad/src/common/windows/omap.h | 72 + .../src/common/windows/omap_internal.h | 137 + .../src/common/windows/omap_unittest.cc | 330 + .../src/common/windows/pdb_source_line_writer.cc | 1369 +++ .../src/common/windows/pdb_source_line_writer.h | 257 + .../src/common/windows/string_utils-inl.h | 142 + .../src/common/windows/string_utils.cc | 133 + .../crashreporter/google-breakpad/src/config.h.in | 79 + .../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 | 140 + .../src/google_breakpad/common/minidump_cpu_mips.h | 176 + .../src/google_breakpad/common/minidump_cpu_ppc.h | 168 + .../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_linux.h | 87 + .../common/minidump_exception_mac.h | 205 + .../common/minidump_exception_ps3.h | 67 + .../common/minidump_exception_solaris.h | 94 + .../common/minidump_exception_win32.h | 2264 +++++ .../src/google_breakpad/common/minidump_format.h | 1045 +++ .../src/google_breakpad/common/minidump_size.h | 113 + .../processor/basic_source_line_resolver.h | 144 + .../src/google_breakpad/processor/call_stack.h | 87 + .../src/google_breakpad/processor/code_module.h | 101 + .../src/google_breakpad/processor/code_modules.h | 111 + .../src/google_breakpad/processor/dump_context.h | 116 + .../src/google_breakpad/processor/dump_object.h | 53 + .../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 | 132 + .../processor/microdump_processor.h | 63 + .../src/google_breakpad/processor/minidump.h | 1171 +++ .../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 | 198 + .../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 | 108 + .../src/google_breakpad/processor/stackwalker.h | 235 + .../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 | 116 + .../src/processor/basic_code_modules.cc | 155 + .../src/processor/basic_code_modules.h | 98 + .../src/processor/basic_source_line_resolver.cc | 612 ++ .../processor/basic_source_line_resolver_types.h | 177 + .../basic_source_line_resolver_unittest.cc | 682 ++ .../google-breakpad/src/processor/call_stack.cc | 54 + .../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/disassembler_x86.cc | 240 + .../src/processor/disassembler_x86.h | 127 + .../src/processor/disassembler_x86_unittest.cc | 233 + .../google-breakpad/src/processor/dump_context.cc | 659 ++ .../google-breakpad/src/processor/dump_object.cc | 39 + .../src/processor/exploitability.cc | 119 + .../src/processor/exploitability_linux.cc | 625 ++ .../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 | 491 ++ .../google-breakpad/src/processor/linked_ptr.h | 193 + .../google-breakpad/src/processor/logging.cc | 111 + .../google-breakpad/src/processor/logging.h | 186 + .../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 | 385 + .../src/processor/microdump_processor.cc | 100 + .../src/processor/microdump_processor_unittest.cc | 273 + .../src/processor/microdump_stackwalk.cc | 151 + .../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 | 4989 +++++++++++ .../google-breakpad/src/processor/minidump_dump.cc | 213 + .../src/processor/minidump_dump_test | 36 + .../src/processor/minidump_processor.cc | 1577 ++++ .../src/processor/minidump_processor_unittest.cc | 645 ++ .../src/processor/minidump_stackwalk.cc | 162 + .../minidump_stackwalk_machine_readable_test | 37 + .../src/processor/minidump_stackwalk_test | 37 + .../src/processor/minidump_unittest.cc | 1521 ++++ .../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 | 66 + .../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 | 69 + .../google-breakpad/src/processor/processor.gyp | 184 + .../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 | 272 + .../google-breakpad/src/processor/range_map.h | 161 + .../processor/range_map_shrink_down_unittest.cc | 355 + .../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 | 158 + .../src/processor/stack_frame_cpu.cc | 79 + .../src/processor/stack_frame_symbolizer.cc | 138 + .../src/processor/stackwalk_common.cc | 950 ++ .../src/processor/stackwalk_common.h | 49 + .../google-breakpad/src/processor/stackwalker.cc | 296 + .../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 | 340 + .../src/processor/stackwalker_amd64.h | 116 + .../src/processor/stackwalker_amd64_unittest.cc | 932 ++ .../src/processor/stackwalker_arm.cc | 296 + .../src/processor/stackwalker_arm.h | 107 + .../src/processor/stackwalker_arm64.cc | 278 + .../src/processor/stackwalker_arm64.h | 104 + .../src/processor/stackwalker_arm64_unittest.cc | 880 ++ .../src/processor/stackwalker_arm_unittest.cc | 974 ++ .../src/processor/stackwalker_mips.cc | 448 + .../src/processor/stackwalker_mips.h | 85 + .../src/processor/stackwalker_mips_unittest.cc | 707 ++ .../src/processor/stackwalker_ppc.cc | 146 + .../src/processor/stackwalker_ppc.h | 79 + .../src/processor/stackwalker_ppc64.cc | 137 + .../src/processor/stackwalker_ppc64.h | 77 + .../src/processor/stackwalker_selftest.cc | 433 + .../src/processor/stackwalker_selftest_sol.s | 111 + .../src/processor/stackwalker_sparc.cc | 139 + .../src/processor/stackwalker_sparc.h | 78 + .../src/processor/stackwalker_unittest_utils.h | 224 + .../src/processor/stackwalker_x86.cc | 672 ++ .../src/processor/stackwalker_x86.h | 117 + .../src/processor/stackwalker_x86_unittest.cc | 2128 +++++ .../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 | 6418 ++++++++++++++ .../src/processor/symbolic_constants_win.h | 50 + .../src/processor/synth_minidump.cc | 391 + .../google-breakpad/src/processor/synth_minidump.h | 372 + .../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 | 1936 ++++ .../src/third_party/curl/curlbuild.h | 202 + .../src/third_party/curl/curlrules.h | 249 + .../google-breakpad/src/third_party/curl/curlver.h | 70 + .../google-breakpad/src/third_party/curl/easy.h | 103 + .../google-breakpad/src/third_party/curl/mprintf.h | 82 + .../google-breakpad/src/third_party/curl/multi.h | 346 + .../src/third_party/curl/stdcheaders.h | 34 + .../src/third_party/curl/typecheck-gcc.h | 551 ++ .../google-breakpad/src/third_party/curl/types.h | 1 + .../src/third_party/libdisasm/Makefile.am | 43 + .../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 + .../src/third_party/linux/include/gflags/gflags.h | 533 ++ .../linux/include/gflags/gflags_completions.h | 121 + .../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 | 346 + .../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 | 2827 ++++++ .../src/tools/linux/core2md/core2md.cc | 72 + .../src/tools/linux/dump_syms/dump_syms.cc | 113 + .../src/tools/linux/dump_syms/moz.build | 33 + .../src/tools/linux/md2core/minidump-2-core.cc | 1276 +++ .../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 | 112 + .../src/tools/linux/tools_linux.gypi | 83 + .../src/tools/mac/crash_report/crash_report.mm | 408 + .../crash_report.xcodeproj/project.pbxproj | 587 ++ .../mac/crash_report/on_demand_symbol_supplier.h | 111 + .../mac/crash_report/on_demand_symbol_supplier.mm | 316 + .../dump_syms/dump_syms.xcodeproj/project.pbxproj | 1839 ++++ .../src/tools/mac/dump_syms/dump_syms_tool.cc | 264 + .../src/tools/mac/dump_syms/macho_dump.cc | 203 + .../src/tools/mac/dump_syms/moz.build | 40 + .../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 | 61 + .../tools/mac/upload_system_symbols/arch_reader.go | 65 + .../upload_system_symbols/upload_system_symbols.go | 420 + .../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/moz.build | 29 + .../src/tools/solaris/dump_syms/run_regtest.sh | 51 + .../dump_syms/testdata/dump_syms_regtest.cc | 64 + .../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 -> 130048 bytes .../src/tools/windows/binaries/symupload.exe | Bin 0 -> 195072 bytes .../converter/ms_symbol_server_converter.cc | 576 ++ .../converter/ms_symbol_server_converter.gyp | 46 + .../windows/converter/ms_symbol_server_converter.h | 219 + .../src/tools/windows/dump_syms/dump_syms.cc | 61 + .../src/tools/windows/dump_syms/dump_syms.gyp | 64 + .../tools/windows/dump_syms/dump_syms_unittest.cc | 204 + .../src/tools/windows/dump_syms/moz.build | 31 + .../src/tools/windows/dump_syms/run_regtest.sh | 53 + .../src/tools/windows/refresh_binaries.bat | 27 + .../src/tools/windows/symupload/symupload.cc | 259 + .../src/tools/windows/symupload/symupload.gyp | 45 + toolkit/crashreporter/injector/injector.cpp | 40 + toolkit/crashreporter/injector/moz.build | 26 + toolkit/crashreporter/jar.mn | 7 + toolkit/crashreporter/jsoncpp/AUTHORS | 1 + toolkit/crashreporter/jsoncpp/GIT-INFO | 1 + toolkit/crashreporter/jsoncpp/LICENSE | 55 + toolkit/crashreporter/jsoncpp/NEWS.txt | 175 + toolkit/crashreporter/jsoncpp/README.md | 214 + .../crashreporter/jsoncpp/include/json/allocator.h | 94 + .../jsoncpp/include/json/assertions.h | 54 + .../crashreporter/jsoncpp/include/json/autolink.h | 25 + .../crashreporter/jsoncpp/include/json/config.h | 178 + .../crashreporter/jsoncpp/include/json/features.h | 57 + .../crashreporter/jsoncpp/include/json/forwards.h | 37 + toolkit/crashreporter/jsoncpp/include/json/json.h | 15 + .../crashreporter/jsoncpp/include/json/reader.h | 404 + toolkit/crashreporter/jsoncpp/include/json/value.h | 867 ++ .../crashreporter/jsoncpp/include/json/version.h | 20 + .../crashreporter/jsoncpp/include/json/writer.h | 331 + .../jsoncpp/src/lib_json/json_reader.cpp | 2039 +++++ .../crashreporter/jsoncpp/src/lib_json/json_tool.h | 111 + .../jsoncpp/src/lib_json/json_value.cpp | 1604 ++++ .../jsoncpp/src/lib_json/json_valueiterator.inl | 167 + .../jsoncpp/src/lib_json/json_writer.cpp | 1218 +++ .../crashreporter/jsoncpp/src/lib_json/moz.build | 34 + toolkit/crashreporter/mac_utils.h | 14 + toolkit/crashreporter/mac_utils.mm | 41 + .../minidump-analyzer/minidump-analyzer.cpp | 437 + toolkit/crashreporter/minidump-analyzer/moz.build | 34 + toolkit/crashreporter/moz.build | 122 + toolkit/crashreporter/nsExceptionHandler.cpp | 4147 +++++++++ toolkit/crashreporter/nsExceptionHandler.h | 279 + toolkit/crashreporter/test/CrashTestUtils.jsm | 72 + toolkit/crashreporter/test/browser/.eslintrc.js | 7 + toolkit/crashreporter/test/browser/browser.ini | 8 + .../test/browser/browser_aboutCrashes.js | 27 + .../test/browser/browser_aboutCrashesResubmit.js | 152 + .../test/browser/browser_bug471404.js | 41 + .../test/browser/browser_clearReports.js | 124 + toolkit/crashreporter/test/browser/crashreport.sjs | 180 + toolkit/crashreporter/test/browser/head.js | 139 + toolkit/crashreporter/test/dumputils.cpp | 99 + toolkit/crashreporter/test/moz.build | 40 + toolkit/crashreporter/test/nsTestCrasher.cpp | 126 + toolkit/crashreporter/test/unit/.eslintrc.js | 7 + .../test/unit/crasher_subprocess_head.js | 33 + .../test/unit/crasher_subprocess_tail.js | 15 + .../crashreporter/test/unit/head_crashreporter.js | 173 + .../test/unit/test_crash_AsyncShutdown.js | 102 + .../crashreporter/test/unit/test_crash_abort.js | 16 + ...test_crash_after_js_large_allocation_failure.js | 21 + ..._after_js_large_allocation_failure_reporting.js | 27 + .../test/unit/test_crash_after_js_oom_recovered.js | 20 + .../test/unit/test_crash_after_js_oom_reported.js | 34 + .../unit/test_crash_after_js_oom_reported_2.js | 26 + .../test/unit/test_crash_moz_crash.js | 16 + toolkit/crashreporter/test/unit/test_crash_oom.js | 19 + .../test/unit/test_crash_purevirtual.js | 24 + .../test/unit/test_crash_runtimeabort.js | 21 + .../test/unit/test_crash_terminator.js | 40 + .../test/unit/test_crash_with_memory_report.js | 55 + .../crashreporter/test/unit/test_crashreporter.js | 85 + .../test/unit/test_crashreporter_appmem.js | 12 + .../test/unit/test_crashreporter_crash.js | 51 + .../unit/test_crashreporter_crash_profile_lock.js | 26 + .../crashreporter/test/unit/test_event_files.js | 56 + .../test/unit/test_oom_annotation_windows.js | 27 + .../test/unit/test_override_exception_handler.js | 12 + toolkit/crashreporter/test/unit/xpcshell.ini | 37 + toolkit/crashreporter/test/unit_ipc/.eslintrc.js | 7 + .../test/unit_ipc/test_content_annotation.js | 22 + .../test_content_exception_time_annotation.js | 17 + .../test/unit_ipc/test_content_memory_list.js | 23 + .../test_content_oom_annotation_windows.js | 23 + toolkit/crashreporter/test/unit_ipc/xpcshell.ini | 15 + toolkit/crashreporter/tools/symbolstore.py | 1078 +++ toolkit/crashreporter/tools/unit-symbolstore.py | 583 ++ toolkit/crashreporter/tools/upload_symbols.py | 102 + .../crashreporter/tools/win32/dump_syms_vc1600.exe | Bin 0 -> 55296 bytes .../crashreporter/tools/win32/dump_syms_vc1700.exe | Bin 0 -> 52736 bytes .../crashreporter/tools/win32/dump_syms_vc1800.exe | Bin 0 -> 51200 bytes toolkit/crashreporter/update-breakpad.sh | 65 + toolkit/crashreporter/update-jsoncpp.sh | 62 + 880 files changed, 268788 insertions(+) create mode 100644 toolkit/crashreporter/CrashReports.jsm create mode 100644 toolkit/crashreporter/CrashSubmit.jsm create mode 100644 toolkit/crashreporter/InjectCrashReporter.cpp create mode 100644 toolkit/crashreporter/InjectCrashReporter.h create mode 100644 toolkit/crashreporter/KeyValueParser.jsm create mode 100644 toolkit/crashreporter/LoadLibraryRemote.cpp create mode 100644 toolkit/crashreporter/LoadLibraryRemote.h create mode 100644 toolkit/crashreporter/breakpad-patches/00-arm-exidx-rollup.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/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/resource.h create mode 100644 toolkit/crashreporter/content/crashes.js create mode 100644 toolkit/crashreporter/content/crashes.xhtml create mode 100644 toolkit/crashreporter/crashreporter.mozbuild create mode 100644 toolkit/crashreporter/docs/index.rst 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 100755 toolkit/crashreporter/google-breakpad/autotools/compile create mode 100755 toolkit/crashreporter/google-breakpad/autotools/config.guess create mode 100755 toolkit/crashreporter/google-breakpad/autotools/config.sub create mode 100755 toolkit/crashreporter/google-breakpad/autotools/depcomp create mode 100755 toolkit/crashreporter/google-breakpad/autotools/install-sh create mode 100755 toolkit/crashreporter/google-breakpad/autotools/ltmain.sh create mode 100755 toolkit/crashreporter/google-breakpad/autotools/missing create mode 100755 toolkit/crashreporter/google-breakpad/autotools/test-driver 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/m4/ax_pthread.m4 create mode 100644 toolkit/crashreporter/google-breakpad/m4/libtool.m4 create mode 100644 toolkit/crashreporter/google-breakpad/m4/ltoptions.m4 create mode 100644 toolkit/crashreporter/google-breakpad/m4/ltsugar.m4 create mode 100644 toolkit/crashreporter/google-breakpad/m4/ltversion.m4 create mode 100644 toolkit/crashreporter/google-breakpad/m4/lt~obsolete.m4 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.gypi create mode 100644 toolkit/crashreporter/google-breakpad/src/client/apple/Framework/BreakpadDefines.h create mode 100644 toolkit/crashreporter/google-breakpad/src/client/ios/Breakpad.h create mode 100644 toolkit/crashreporter/google-breakpad/src/client/ios/Breakpad.mm create mode 100644 toolkit/crashreporter/google-breakpad/src/client/ios/Breakpad.xcodeproj/project.pbxproj create mode 100644 toolkit/crashreporter/google-breakpad/src/client/ios/BreakpadController.h create mode 100644 toolkit/crashreporter/google-breakpad/src/client/ios/BreakpadController.mm create mode 100644 toolkit/crashreporter/google-breakpad/src/client/ios/Breakpad_Prefix.pch create mode 100644 toolkit/crashreporter/google-breakpad/src/client/ios/handler/ios_exception_minidump_generator.h create mode 100644 toolkit/crashreporter/google-breakpad/src/client/ios/handler/ios_exception_minidump_generator.mm create mode 100644 toolkit/crashreporter/google-breakpad/src/client/linux/crash_generation/client_info.h create mode 100644 toolkit/crashreporter/google-breakpad/src/client/linux/crash_generation/crash_generation_client.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/client/linux/crash_generation/crash_generation_client.h create mode 100644 toolkit/crashreporter/google-breakpad/src/client/linux/crash_generation/crash_generation_server.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/client/linux/crash_generation/crash_generation_server.h create mode 100644 toolkit/crashreporter/google-breakpad/src/client/linux/data/linux-gate-amd.sym create mode 100644 toolkit/crashreporter/google-breakpad/src/client/linux/data/linux-gate-intel.sym create mode 100644 toolkit/crashreporter/google-breakpad/src/client/linux/dump_writer_common/mapping_info.h create mode 100644 toolkit/crashreporter/google-breakpad/src/client/linux/dump_writer_common/raw_context_cpu.h create mode 100644 toolkit/crashreporter/google-breakpad/src/client/linux/dump_writer_common/thread_info.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/client/linux/dump_writer_common/thread_info.h create mode 100644 toolkit/crashreporter/google-breakpad/src/client/linux/dump_writer_common/ucontext_reader.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/client/linux/dump_writer_common/ucontext_reader.h create mode 100644 toolkit/crashreporter/google-breakpad/src/client/linux/handler/exception_handler.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/client/linux/handler/exception_handler.h create mode 100644 toolkit/crashreporter/google-breakpad/src/client/linux/handler/exception_handler_unittest.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/client/linux/handler/microdump_extra_info.h create mode 100644 toolkit/crashreporter/google-breakpad/src/client/linux/handler/minidump_descriptor.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/client/linux/handler/minidump_descriptor.h create mode 100644 toolkit/crashreporter/google-breakpad/src/client/linux/log/log.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/client/linux/log/log.h create mode 100644 toolkit/crashreporter/google-breakpad/src/client/linux/microdump_writer/microdump_writer.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/client/linux/microdump_writer/microdump_writer.h create mode 100644 toolkit/crashreporter/google-breakpad/src/client/linux/microdump_writer/microdump_writer_unittest.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/client/linux/minidump_writer/cpu_set.h create mode 100644 toolkit/crashreporter/google-breakpad/src/client/linux/minidump_writer/cpu_set_unittest.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/client/linux/minidump_writer/directory_reader.h create mode 100644 toolkit/crashreporter/google-breakpad/src/client/linux/minidump_writer/directory_reader_unittest.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/client/linux/minidump_writer/line_reader.h create mode 100644 toolkit/crashreporter/google-breakpad/src/client/linux/minidump_writer/line_reader_unittest.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/client/linux/minidump_writer/linux_core_dumper.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/client/linux/minidump_writer/linux_core_dumper.h create mode 100644 toolkit/crashreporter/google-breakpad/src/client/linux/minidump_writer/linux_core_dumper_unittest.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/client/linux/minidump_writer/linux_dumper.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/client/linux/minidump_writer/linux_dumper.h create mode 100644 toolkit/crashreporter/google-breakpad/src/client/linux/minidump_writer/linux_dumper_unittest_helper.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/client/linux/minidump_writer/linux_ptrace_dumper.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/client/linux/minidump_writer/linux_ptrace_dumper.h create mode 100644 toolkit/crashreporter/google-breakpad/src/client/linux/minidump_writer/linux_ptrace_dumper_unittest.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/client/linux/minidump_writer/minidump_writer.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/client/linux/minidump_writer/minidump_writer.h create mode 100644 toolkit/crashreporter/google-breakpad/src/client/linux/minidump_writer/minidump_writer_unittest.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/client/linux/minidump_writer/minidump_writer_unittest_utils.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/client/linux/minidump_writer/minidump_writer_unittest_utils.h create mode 100644 toolkit/crashreporter/google-breakpad/src/client/linux/minidump_writer/proc_cpuinfo_reader.h create mode 100644 toolkit/crashreporter/google-breakpad/src/client/linux/minidump_writer/proc_cpuinfo_reader_unittest.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/client/linux/moz.build create mode 100644 toolkit/crashreporter/google-breakpad/src/client/linux/sender/google_crash_report_sender.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/client/mac/Breakpad.xcodeproj/project.pbxproj create mode 100644 toolkit/crashreporter/google-breakpad/src/client/mac/Framework/Breakpad.h create mode 100644 toolkit/crashreporter/google-breakpad/src/client/mac/Framework/Breakpad.mm create mode 100644 toolkit/crashreporter/google-breakpad/src/client/mac/Framework/Breakpad_Prefix.pch create mode 100644 toolkit/crashreporter/google-breakpad/src/client/mac/Framework/Info.plist create mode 100644 toolkit/crashreporter/google-breakpad/src/client/mac/Framework/OnDemandServer.h create mode 100644 toolkit/crashreporter/google-breakpad/src/client/mac/Framework/OnDemandServer.mm create mode 100644 toolkit/crashreporter/google-breakpad/src/client/mac/UnitTests-Info.plist create mode 100644 toolkit/crashreporter/google-breakpad/src/client/mac/crash_generation/ConfigFile.h create mode 100644 toolkit/crashreporter/google-breakpad/src/client/mac/crash_generation/ConfigFile.mm create mode 100644 toolkit/crashreporter/google-breakpad/src/client/mac/crash_generation/Inspector.h create mode 100644 toolkit/crashreporter/google-breakpad/src/client/mac/crash_generation/Inspector.mm create mode 100644 toolkit/crashreporter/google-breakpad/src/client/mac/crash_generation/InspectorMain.mm create mode 100644 toolkit/crashreporter/google-breakpad/src/client/mac/crash_generation/client_info.h create mode 100644 toolkit/crashreporter/google-breakpad/src/client/mac/crash_generation/crash_generation_client.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/client/mac/crash_generation/crash_generation_client.h create mode 100644 toolkit/crashreporter/google-breakpad/src/client/mac/crash_generation/crash_generation_server.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/client/mac/crash_generation/crash_generation_server.h create mode 100644 toolkit/crashreporter/google-breakpad/src/client/mac/crash_generation/moz.build create mode 100644 toolkit/crashreporter/google-breakpad/src/client/mac/handler/breakpad_nlist_64.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/client/mac/handler/breakpad_nlist_64.h create mode 100644 toolkit/crashreporter/google-breakpad/src/client/mac/handler/dynamic_images.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/client/mac/handler/dynamic_images.h create mode 100644 toolkit/crashreporter/google-breakpad/src/client/mac/handler/exception_handler.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/client/mac/handler/exception_handler.h create mode 100644 toolkit/crashreporter/google-breakpad/src/client/mac/handler/mach_vm_compat.h create mode 100644 toolkit/crashreporter/google-breakpad/src/client/mac/handler/minidump_generator.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/client/mac/handler/minidump_generator.h create mode 100644 toolkit/crashreporter/google-breakpad/src/client/mac/handler/minidump_test.xcodeproj/project.pbxproj create mode 100644 toolkit/crashreporter/google-breakpad/src/client/mac/handler/minidump_tests32-Info.plist create mode 100644 toolkit/crashreporter/google-breakpad/src/client/mac/handler/minidump_tests64-Info.plist create mode 100644 toolkit/crashreporter/google-breakpad/src/client/mac/handler/moz.build create mode 100644 toolkit/crashreporter/google-breakpad/src/client/mac/handler/obj-cTestCases-Info.plist create mode 100644 toolkit/crashreporter/google-breakpad/src/client/mac/handler/protected_memory_allocator.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/client/mac/handler/protected_memory_allocator.h create mode 100644 toolkit/crashreporter/google-breakpad/src/client/mac/handler/testcases/DynamicImagesTests.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/client/mac/handler/testcases/DynamicImagesTests.h create mode 100644 toolkit/crashreporter/google-breakpad/src/client/mac/handler/testcases/breakpad_nlist_test.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/client/mac/handler/testcases/breakpad_nlist_test.h create mode 100644 toolkit/crashreporter/google-breakpad/src/client/mac/handler/testcases/dwarftests.h create mode 100644 toolkit/crashreporter/google-breakpad/src/client/mac/handler/testcases/dwarftests.mm create mode 100644 toolkit/crashreporter/google-breakpad/src/client/mac/handler/testcases/testdata/dump_syms_dwarf_data create mode 100644 toolkit/crashreporter/google-breakpad/src/client/mac/handler/testcases/testdata/dump_syms_i386_breakpad.sym create mode 100644 toolkit/crashreporter/google-breakpad/src/client/mac/handler/ucontext_compat.h create mode 100644 toolkit/crashreporter/google-breakpad/src/client/mac/sender/Breakpad.xib create mode 100644 toolkit/crashreporter/google-breakpad/src/client/mac/sender/English.lproj/InfoPlist.strings create mode 100644 toolkit/crashreporter/google-breakpad/src/client/mac/sender/English.lproj/Localizable.strings create mode 100644 toolkit/crashreporter/google-breakpad/src/client/mac/sender/ReporterIcon.graffle create mode 100644 toolkit/crashreporter/google-breakpad/src/client/mac/sender/crash_report_sender-Info.plist create mode 100644 toolkit/crashreporter/google-breakpad/src/client/mac/sender/crash_report_sender.h create mode 100644 toolkit/crashreporter/google-breakpad/src/client/mac/sender/crash_report_sender.icns create mode 100644 toolkit/crashreporter/google-breakpad/src/client/mac/sender/crash_report_sender.m create mode 100644 toolkit/crashreporter/google-breakpad/src/client/mac/sender/da.lproj/InfoPlist.strings create mode 100644 toolkit/crashreporter/google-breakpad/src/client/mac/sender/da.lproj/Localizable.strings create mode 100644 toolkit/crashreporter/google-breakpad/src/client/mac/sender/de.lproj/InfoPlist.strings create mode 100644 toolkit/crashreporter/google-breakpad/src/client/mac/sender/de.lproj/Localizable.strings create mode 100644 toolkit/crashreporter/google-breakpad/src/client/mac/sender/es.lproj/InfoPlist.strings create mode 100644 toolkit/crashreporter/google-breakpad/src/client/mac/sender/es.lproj/Localizable.strings create mode 100644 toolkit/crashreporter/google-breakpad/src/client/mac/sender/fr.lproj/InfoPlist.strings create mode 100644 toolkit/crashreporter/google-breakpad/src/client/mac/sender/fr.lproj/Localizable.strings create mode 100644 toolkit/crashreporter/google-breakpad/src/client/mac/sender/goArrow.png create mode 100644 toolkit/crashreporter/google-breakpad/src/client/mac/sender/it.lproj/InfoPlist.strings create mode 100644 toolkit/crashreporter/google-breakpad/src/client/mac/sender/it.lproj/Localizable.strings create mode 100644 toolkit/crashreporter/google-breakpad/src/client/mac/sender/ja.lproj/InfoPlist.strings create mode 100644 toolkit/crashreporter/google-breakpad/src/client/mac/sender/ja.lproj/Localizable.strings create mode 100644 toolkit/crashreporter/google-breakpad/src/client/mac/sender/nl.lproj/InfoPlist.strings create mode 100644 toolkit/crashreporter/google-breakpad/src/client/mac/sender/nl.lproj/Localizable.strings create mode 100644 toolkit/crashreporter/google-breakpad/src/client/mac/sender/no.lproj/InfoPlist.strings create mode 100644 toolkit/crashreporter/google-breakpad/src/client/mac/sender/no.lproj/Localizable.strings create mode 100644 toolkit/crashreporter/google-breakpad/src/client/mac/sender/sl.lproj/InfoPlist.strings create mode 100644 toolkit/crashreporter/google-breakpad/src/client/mac/sender/sl.lproj/Localizable.strings create mode 100644 toolkit/crashreporter/google-breakpad/src/client/mac/sender/sv.lproj/InfoPlist.strings create mode 100644 toolkit/crashreporter/google-breakpad/src/client/mac/sender/sv.lproj/Localizable.strings create mode 100644 toolkit/crashreporter/google-breakpad/src/client/mac/sender/tr.lproj/InfoPlist.strings create mode 100644 toolkit/crashreporter/google-breakpad/src/client/mac/sender/tr.lproj/Localizable.strings create mode 100644 toolkit/crashreporter/google-breakpad/src/client/mac/sender/uploader.h create mode 100644 toolkit/crashreporter/google-breakpad/src/client/mac/sender/uploader.mm create mode 100644 toolkit/crashreporter/google-breakpad/src/client/mac/testapp/Controller.h create mode 100644 toolkit/crashreporter/google-breakpad/src/client/mac/testapp/Controller.m create mode 100644 toolkit/crashreporter/google-breakpad/src/client/mac/testapp/English.lproj/InfoPlist.strings create mode 100644 toolkit/crashreporter/google-breakpad/src/client/mac/testapp/English.lproj/MainMenu.xib create mode 100644 toolkit/crashreporter/google-breakpad/src/client/mac/testapp/Info.plist create mode 100644 toolkit/crashreporter/google-breakpad/src/client/mac/testapp/TestClass.h create mode 100644 toolkit/crashreporter/google-breakpad/src/client/mac/testapp/TestClass.mm create mode 100644 toolkit/crashreporter/google-breakpad/src/client/mac/testapp/bomb.icns create mode 100755 toolkit/crashreporter/google-breakpad/src/client/mac/testapp/crashInMain create mode 100755 toolkit/crashreporter/google-breakpad/src/client/mac/testapp/crashduringload create mode 100644 toolkit/crashreporter/google-breakpad/src/client/mac/testapp/main.m create mode 100644 toolkit/crashreporter/google-breakpad/src/client/mac/tests/BreakpadFramework_Test.mm create mode 100644 toolkit/crashreporter/google-breakpad/src/client/mac/tests/crash_generation_server_test.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/client/mac/tests/exception_handler_test.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/client/mac/tests/minidump_generator_test.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/client/mac/tests/minidump_generator_test_helper.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/client/mac/tests/spawn_child_process.h create mode 100644 toolkit/crashreporter/google-breakpad/src/client/mac/tests/testlogging.h create mode 100644 toolkit/crashreporter/google-breakpad/src/client/minidump_file_writer-inl.h create mode 100644 toolkit/crashreporter/google-breakpad/src/client/minidump_file_writer.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/client/minidump_file_writer.h create mode 100644 toolkit/crashreporter/google-breakpad/src/client/minidump_file_writer_unittest.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/client/moz.build create mode 100644 toolkit/crashreporter/google-breakpad/src/client/solaris/handler/Makefile create mode 100644 toolkit/crashreporter/google-breakpad/src/client/solaris/handler/exception_handler.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/client/solaris/handler/exception_handler.h create mode 100644 toolkit/crashreporter/google-breakpad/src/client/solaris/handler/exception_handler_test.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/client/solaris/handler/minidump_generator.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/client/solaris/handler/minidump_generator.h create mode 100644 toolkit/crashreporter/google-breakpad/src/client/solaris/handler/minidump_test.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/client/solaris/handler/moz.build create mode 100644 toolkit/crashreporter/google-breakpad/src/client/solaris/handler/solaris_lwp.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/client/solaris/handler/solaris_lwp.h create mode 100644 toolkit/crashreporter/google-breakpad/src/client/windows/breakpad_client.gyp create mode 100644 toolkit/crashreporter/google-breakpad/src/client/windows/common/auto_critical_section.h create mode 100644 toolkit/crashreporter/google-breakpad/src/client/windows/common/ipc_protocol.h create mode 100644 toolkit/crashreporter/google-breakpad/src/client/windows/crash_generation/ReadMe.txt create mode 100644 toolkit/crashreporter/google-breakpad/src/client/windows/crash_generation/client_info.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/client/windows/crash_generation/client_info.h create mode 100644 toolkit/crashreporter/google-breakpad/src/client/windows/crash_generation/crash_generation.gyp create mode 100644 toolkit/crashreporter/google-breakpad/src/client/windows/crash_generation/crash_generation_client.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/client/windows/crash_generation/crash_generation_client.h create mode 100644 toolkit/crashreporter/google-breakpad/src/client/windows/crash_generation/crash_generation_server.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/client/windows/crash_generation/crash_generation_server.h create mode 100644 toolkit/crashreporter/google-breakpad/src/client/windows/crash_generation/minidump_generator.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/client/windows/crash_generation/minidump_generator.h create mode 100644 toolkit/crashreporter/google-breakpad/src/client/windows/crash_generation/objs.mozbuild create mode 100644 toolkit/crashreporter/google-breakpad/src/client/windows/handler/exception_handler.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/client/windows/handler/exception_handler.gyp create mode 100644 toolkit/crashreporter/google-breakpad/src/client/windows/handler/exception_handler.h create mode 100644 toolkit/crashreporter/google-breakpad/src/client/windows/handler/objs.mozbuild create mode 100644 toolkit/crashreporter/google-breakpad/src/client/windows/sender/crash_report_sender.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/client/windows/sender/crash_report_sender.gyp create mode 100644 toolkit/crashreporter/google-breakpad/src/client/windows/sender/crash_report_sender.h create mode 100644 toolkit/crashreporter/google-breakpad/src/client/windows/sender/objs.mozbuild create mode 100644 toolkit/crashreporter/google-breakpad/src/client/windows/tests/crash_generation_app/abstract_class.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/client/windows/tests/crash_generation_app/abstract_class.h create mode 100644 toolkit/crashreporter/google-breakpad/src/client/windows/tests/crash_generation_app/crash_generation_app.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/client/windows/tests/crash_generation_app/crash_generation_app.gyp create mode 100644 toolkit/crashreporter/google-breakpad/src/client/windows/tests/crash_generation_app/crash_generation_app.h create mode 100644 toolkit/crashreporter/google-breakpad/src/client/windows/tests/crash_generation_app/crash_generation_app.ico create mode 100644 toolkit/crashreporter/google-breakpad/src/client/windows/tests/crash_generation_app/crash_generation_app.rc create mode 100644 toolkit/crashreporter/google-breakpad/src/client/windows/tests/crash_generation_app/resource.h create mode 100644 toolkit/crashreporter/google-breakpad/src/client/windows/tests/crash_generation_app/small.ico create mode 100644 toolkit/crashreporter/google-breakpad/src/client/windows/unittests/client_tests.gyp create mode 100644 toolkit/crashreporter/google-breakpad/src/client/windows/unittests/crash_generation_server_test.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/client/windows/unittests/dump_analysis.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/client/windows/unittests/dump_analysis.h create mode 100644 toolkit/crashreporter/google-breakpad/src/client/windows/unittests/exception_handler_death_test.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/client/windows/unittests/exception_handler_nesting_test.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/client/windows/unittests/exception_handler_test.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/client/windows/unittests/exception_handler_test.h create mode 100644 toolkit/crashreporter/google-breakpad/src/client/windows/unittests/minidump_test.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/client/windows/unittests/testing.gyp create mode 100644 toolkit/crashreporter/google-breakpad/src/common/Makefile.in create mode 100644 toolkit/crashreporter/google-breakpad/src/common/android/breakpad_getcontext.S create mode 100644 toolkit/crashreporter/google-breakpad/src/common/android/breakpad_getcontext_unittest.cc 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/sgidefs.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/signal.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/include/ucontext.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/android/ucontext_constants.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.c 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/moz.build 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/language.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/common/language.h 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_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/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/md5.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/common/md5.h create mode 100644 toolkit/crashreporter/google-breakpad/src/common/memory.h 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/memory_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/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/solaris/moz.build 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/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/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/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/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_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/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/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_shrink_down_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_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/curlbuild.h create mode 100644 toolkit/crashreporter/google-breakpad/src/third_party/curl/curlrules.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/mprintf.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/stdcheaders.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/types.h create mode 100644 toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/Makefile.am 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/linux/include/gflags/gflags.h create mode 100644 toolkit/crashreporter/google-breakpad/src/third_party/linux/include/gflags/gflags_completions.h 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/dump_syms/moz.build 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/dump_syms/moz.build 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 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/moz.build 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.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/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_unittest.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/tools/windows/dump_syms/moz.build 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/injector/injector.cpp create mode 100644 toolkit/crashreporter/injector/moz.build create mode 100644 toolkit/crashreporter/jar.mn create mode 100644 toolkit/crashreporter/jsoncpp/AUTHORS create mode 100644 toolkit/crashreporter/jsoncpp/GIT-INFO create mode 100644 toolkit/crashreporter/jsoncpp/LICENSE create mode 100644 toolkit/crashreporter/jsoncpp/NEWS.txt create mode 100644 toolkit/crashreporter/jsoncpp/README.md create mode 100644 toolkit/crashreporter/jsoncpp/include/json/allocator.h create mode 100644 toolkit/crashreporter/jsoncpp/include/json/assertions.h create mode 100644 toolkit/crashreporter/jsoncpp/include/json/autolink.h create mode 100644 toolkit/crashreporter/jsoncpp/include/json/config.h create mode 100644 toolkit/crashreporter/jsoncpp/include/json/features.h create mode 100644 toolkit/crashreporter/jsoncpp/include/json/forwards.h create mode 100644 toolkit/crashreporter/jsoncpp/include/json/json.h create mode 100644 toolkit/crashreporter/jsoncpp/include/json/reader.h create mode 100644 toolkit/crashreporter/jsoncpp/include/json/value.h create mode 100644 toolkit/crashreporter/jsoncpp/include/json/version.h create mode 100644 toolkit/crashreporter/jsoncpp/include/json/writer.h create mode 100644 toolkit/crashreporter/jsoncpp/src/lib_json/json_reader.cpp create mode 100644 toolkit/crashreporter/jsoncpp/src/lib_json/json_tool.h create mode 100644 toolkit/crashreporter/jsoncpp/src/lib_json/json_value.cpp create mode 100644 toolkit/crashreporter/jsoncpp/src/lib_json/json_valueiterator.inl create mode 100644 toolkit/crashreporter/jsoncpp/src/lib_json/json_writer.cpp create mode 100644 toolkit/crashreporter/jsoncpp/src/lib_json/moz.build create mode 100644 toolkit/crashreporter/mac_utils.h create mode 100644 toolkit/crashreporter/mac_utils.mm create mode 100644 toolkit/crashreporter/minidump-analyzer/minidump-analyzer.cpp create mode 100644 toolkit/crashreporter/minidump-analyzer/moz.build create mode 100644 toolkit/crashreporter/moz.build create mode 100644 toolkit/crashreporter/nsExceptionHandler.cpp create mode 100644 toolkit/crashreporter/nsExceptionHandler.h create mode 100644 toolkit/crashreporter/test/CrashTestUtils.jsm create mode 100644 toolkit/crashreporter/test/browser/.eslintrc.js create mode 100644 toolkit/crashreporter/test/browser/browser.ini 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/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/.eslintrc.js 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/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_moz_crash.js create mode 100644 toolkit/crashreporter/test/unit/test_crash_oom.js create mode 100644 toolkit/crashreporter/test/unit/test_crash_purevirtual.js create mode 100644 toolkit/crashreporter/test/unit/test_crash_runtimeabort.js create mode 100644 toolkit/crashreporter/test/unit/test_crash_terminator.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_crashreporter_crash_profile_lock.js create mode 100644 toolkit/crashreporter/test/unit/test_event_files.js create mode 100644 toolkit/crashreporter/test/unit/test_oom_annotation_windows.js create mode 100644 toolkit/crashreporter/test/unit/test_override_exception_handler.js create mode 100644 toolkit/crashreporter/test/unit/xpcshell.ini create mode 100644 toolkit/crashreporter/test/unit_ipc/.eslintrc.js 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_memory_list.js create mode 100644 toolkit/crashreporter/test/unit_ipc/test_content_oom_annotation_windows.js create mode 100644 toolkit/crashreporter/test/unit_ipc/xpcshell.ini create mode 100755 toolkit/crashreporter/tools/symbolstore.py create mode 100644 toolkit/crashreporter/tools/unit-symbolstore.py create mode 100644 toolkit/crashreporter/tools/upload_symbols.py create mode 100755 toolkit/crashreporter/tools/win32/dump_syms_vc1600.exe create mode 100644 toolkit/crashreporter/tools/win32/dump_syms_vc1700.exe create mode 100644 toolkit/crashreporter/tools/win32/dump_syms_vc1800.exe create mode 100755 toolkit/crashreporter/update-breakpad.sh create mode 100644 toolkit/crashreporter/update-jsoncpp.sh (limited to 'toolkit/crashreporter') diff --git a/toolkit/crashreporter/CrashReports.jsm b/toolkit/crashreporter/CrashReports.jsm new file mode 100644 index 000000000..d34d6795e --- /dev/null +++ b/toolkit/crashreporter/CrashReports.jsm @@ -0,0 +1,91 @@ +/* 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/. */ + +Components.utils.import("resource://gre/modules/Services.jsm"); + +this.EXPORTED_SYMBOLS = [ + "CrashReports" +]; + +this.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.getNext().QueryInterface(Components.interfaces.nsIFile); + 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.getNext().QueryInterface(Components.interfaces.nsIFile); + let leaf = file.leafName; + let id = leaf.slice(0, -4); + if (leaf.endsWith(".dmp") && uuidRegex.test(id)) { + let entry = { + id: 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", Components.interfaces.nsIFile); + pendingDir.append("Crash Reports"); + pendingDir.append("pending"); + return pendingDir; +} + +function CrashReports_reportsDir() +{ + let reportsDir = Services.dirsvc.get("UAppData", Components.interfaces.nsIFile); + reportsDir.append("Crash Reports"); + return reportsDir; +} + +function CrashReports_submittedDir() +{ + let submittedDir = Services.dirsvc.get("UAppData", Components.interfaces.nsIFile); + submittedDir.append("Crash Reports"); + submittedDir.append("submitted"); + return submittedDir; +} + +this.CrashReports.pendingDir = CrashReports_pendingDir(); +this.CrashReports.reportsDir = CrashReports_reportsDir(); +this.CrashReports.submittedDir = CrashReports_submittedDir(); diff --git a/toolkit/crashreporter/CrashSubmit.jsm b/toolkit/crashreporter/CrashSubmit.jsm new file mode 100644 index 000000000..76eafbdad --- /dev/null +++ b/toolkit/crashreporter/CrashSubmit.jsm @@ -0,0 +1,570 @@ +/* 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/. */ + +const {classes: Cc, interfaces: Ci, utils: Cu} = Components; + +Cu.import("resource://gre/modules/Services.jsm"); +Cu.import("resource://gre/modules/KeyValueParser.jsm"); +Cu.import("resource://gre/modules/XPCOMUtils.jsm"); +Cu.importGlobalProperties(['File']); + +XPCOMUtils.defineLazyModuleGetter(this, "PromiseUtils", + "resource://gre/modules/PromiseUtils.jsm"); +XPCOMUtils.defineLazyModuleGetter(this, "OS", + "resource://gre/modules/osfile.jsm"); +XPCOMUtils.defineLazyModuleGetter(this, "Task", + "resource://gre/modules/Task.jsm"); + +this.EXPORTED_SYMBOLS = [ + "CrashSubmit" +]; + +const STATE_START = Ci.nsIWebProgressListener.STATE_START; +const STATE_STOP = Ci.nsIWebProgressListener.STATE_STOP; + +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; + +function parseINIStrings(file) { + var factory = Cc["@mozilla.org/xpcom/ini-parser-factory;1"]. + getService(Ci.nsIINIParserFactory); + var parser = factory.createINIParser(file); + var obj = {}; + var en = parser.getKeys("Strings"); + while (en.hasMore()) { + var key = en.getNext(); + obj[key] = parser.getString("Strings", key); + } + return obj; +} + +// Since we're basically re-implementing part of the crashreporter +// client here, we'll just steal the strings we need from crashreporter.ini +function getL10nStrings() { + let dirSvc = Cc["@mozilla.org/file/directory_service;1"]. + getService(Ci.nsIProperties); + let path = dirSvc.get("GreD", Ci.nsIFile); + path.append("crashreporter.ini"); + if (!path.exists()) { + // see if we're on a mac + path = path.parent; + path = path.parent; + path.append("MacOS"); + path.append("crashreporter.app"); + path.append("Contents"); + path.append("Resources"); + path.append("crashreporter.ini"); + if (!path.exists()) { + // very bad, but I don't know how to recover + return null; + } + } + let crstrings = parseINIStrings(path); + let strings = { + 'crashid': crstrings.CrashID, + 'reporturl': crstrings.CrashDetailsURL + }; + + path = dirSvc.get("XCurProcD", Ci.nsIFile); + path.append("crashreporter-override.ini"); + if (path.exists()) { + crstrings = parseINIStrings(path); + if ('CrashID' in crstrings) + strings['crashid'] = crstrings.CrashID; + if ('CrashDetailsURL' in crstrings) + strings['reporturl'] = crstrings.CrashDetailsURL; + } + return strings; +} + +XPCOMUtils.defineLazyGetter(this, "strings", getL10nStrings); + +function getDir(name) { + let directoryService = Cc["@mozilla.org/file/directory_service;1"]. + getService(Ci.nsIProperties); + let dir = directoryService.get("UAppData", Ci.nsIFile); + dir.append("Crash Reports"); + dir.append(name); + return dir; +} + +function writeFile(dirName, fileName, data) { + let path = getDir(dirName); + if (!path.exists()) + path.create(Ci.nsIFile.DIRECTORY_TYPE, parseInt('0700', 8)); + path.append(fileName); + var fs = Cc["@mozilla.org/network/file-output-stream;1"]. + createInstance(Ci.nsIFileOutputStream); + // open, write, truncate + fs.init(path, -1, -1, 0); + var os = Cc["@mozilla.org/intl/converter-output-stream;1"]. + createInstance(Ci.nsIConverterOutputStream); + os.init(fs, "UTF-8", 0, 0x0000); + os.writeString(data); + os.close(); + fs.close(); +} + +function getPendingMinidump(id) { + let pendingDir = getDir("pending"); + let dump = pendingDir.clone(); + let extra = pendingDir.clone(); + let memory = pendingDir.clone(); + dump.append(id + ".dmp"); + extra.append(id + ".extra"); + memory.append(id + ".memory.json.gz"); + return [dump, extra, memory]; +} + +function getAllPendingMinidumpsIDs() { + let minidumps = []; + let pendingDir = getDir("pending"); + + if (!(pendingDir.exists() && pendingDir.isDirectory())) + return []; + let entries = pendingDir.directoryEntries; + + while (entries.hasMoreElements()) { + let entry = entries.getNext().QueryInterface(Ci.nsIFile); + if (entry.isFile()) { + let matches = entry.leafName.match(/(.+)\.extra$/); + if (matches) + minidumps.push(matches[1]); + } + } + + return minidumps; +} + +function pruneSavedDumps() { + const KEEP = 10; + + let pendingDir = getDir("pending"); + if (!(pendingDir.exists() && pendingDir.isDirectory())) + return; + let entries = pendingDir.directoryEntries; + let entriesArray = []; + + while (entries.hasMoreElements()) { + let entry = entries.getNext().QueryInterface(Ci.nsIFile); + if (entry.isFile()) { + let matches = entry.leafName.match(/(.+)\.extra$/); + if (matches) + entriesArray.push(entry); + } + } + + entriesArray.sort(function(a, b) { + let dateA = a.lastModifiedTime; + let dateB = b.lastModifiedTime; + if (dateA < dateB) + return -1; + if (dateB < dateA) + return 1; + return 0; + }); + + if (entriesArray.length > KEEP) { + for (let i = 0; i < entriesArray.length - KEEP; ++i) { + let extra = entriesArray[i]; + let matches = extra.leafName.match(/(.+)\.extra$/); + if (matches) { + let dump = extra.clone(); + dump.leafName = matches[1] + '.dmp'; + dump.remove(false); + + let memory = extra.clone(); + memory.leafName = matches[1] + '.memory.json.gz'; + if (memory.exists()) { + memory.remove(false); + } + + extra.remove(false); + } + } + } +} + +function addFormEntry(doc, form, name, value) { + var input = doc.createElement("input"); + input.type = "hidden"; + input.name = name; + input.value = value; + form.appendChild(input); +} + +function writeSubmittedReport(crashID, viewURL) { + var data = strings.crashid.replace("%s", crashID); + if (viewURL) + data += "\n" + strings.reporturl.replace("%s", viewURL); + + writeFile("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 || {}; + this.deferredSubmit = PromiseUtils.defer(); +} + +Submitter.prototype = { + submitSuccess: function Submitter_submitSuccess(ret) + { + // Write out the details file to submitted/ + writeSubmittedReport(ret.CrashID, ret.ViewURL); + + // Delete from pending dir + try { + this.dump.remove(false); + this.extra.remove(false); + + if (this.memory) { + this.memory.remove(false); + } + + for (let i of this.additionalDumps) { + i.dump.remove(false); + } + } + catch (ex) { + // report an error? not much the user can do here. + } + + 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); + }, + + submitForm: function Submitter_submitForm() + { + if (!('ServerURL' in this.extraKeyVals)) { + return false; + } + let serverURL = this.extraKeyVals.ServerURL; + + // Override the submission URL from the environment + + var envOverride = Cc['@mozilla.org/process/environment;1']. + getService(Ci.nsIEnvironment).get("MOZ_CRASHREPORTER_URL"); + if (envOverride != '') { + serverURL = envOverride; + } + + let xhr = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"] + .createInstance(Ci.nsIXMLHttpRequest); + xhr.open("POST", serverURL, true); + + let formData = Cc["@mozilla.org/files/formdata;1"] + .createInstance(Ci.nsIDOMFormData); + // add the data + for (let [name, value] of Object.entries(this.extraKeyVals)) { + if (name != "ServerURL") { + formData.append(name, value); + } + } + if (this.noThrottle) { + // tell the server not to throttle this, since it was manually submitted + formData.append("Throttleable", "0"); + } + // add the minidumps + formData.append("upload_file_minidump", File.createFromFileName(this.dump.path)); + if (this.memory) { + formData.append("memory_report", File.createFromFileName(this.memory.path)); + } + if (this.additionalDumps.length > 0) { + let names = []; + for (let i of this.additionalDumps) { + names.push(i.name); + formData.append("upload_file_minidump_"+i.name, + File.createFromFileName(i.dump.path)); + } + } + + let manager = Services.crashmanager; + let submissionID = manager.generateSubmissionID(); + + xhr.addEventListener("readystatechange", (evt) => { + if (xhr.readyState == 4) { + let ret = + xhr.status == 200 ? parseKeyValuePairs(xhr.responseText) : {}; + let submitted = !!ret.CrashID; + + if (this.recordSubmission) { + let result = submitted ? manager.SUBMISSION_RESULT_OK : + manager.SUBMISSION_RESULT_FAILED; + manager.addSubmissionResult(this.id, submissionID, new Date(), + result); + if (submitted) { + manager.setRemoteCrashID(this.id, ret.CrashID); + } + } + + if (submitted) { + this.submitSuccess(ret); + } + else { + this.notifyStatus(FAILED); + this.cleanup(); + } + } + }, false); + + if (this.recordSubmission) { + manager.addSubmissionAttempt(this.id, submissionID, new Date()); + } + 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.deferredSubmit.resolve(ret.CrashID); + break; + case FAILED: + this.deferredSubmit.reject(); + break; + default: + // no callbacks invoked. + } + }, + + submit: function Submitter_submit() + { + let [dump, extra, memory] = getPendingMinidump(this.id); + + if (!dump.exists() || !extra.exists()) { + this.notifyStatus(FAILED); + this.cleanup(); + return this.deferredSubmit.promise; + } + this.dump = dump; + this.extra = extra; + + // The memory file may or may not exist + if (memory.exists()) { + this.memory = memory; + } + + let extraKeyVals = parseKeyValuePairsFromFile(extra); + for (let key in extraKeyVals) { + if (!(key in this.extraKeyVals)) { + this.extraKeyVals[key] = extraKeyVals[key]; + } + } + + let additionalDumps = []; + if ("additional_minidumps" in this.extraKeyVals) { + let names = this.extraKeyVals.additional_minidumps.split(','); + for (let name of names) { + let [dump, extra, memory] = getPendingMinidump(this.id + "-" + name); + if (!dump.exists()) { + this.notifyStatus(FAILED); + this.cleanup(); + return this.deferredSubmit.promise; + } + additionalDumps.push({'name': name, 'dump': dump}); + } + } + + this.notifyStatus(SUBMITTING); + + this.additionalDumps = additionalDumps; + + if (!this.submitForm()) { + this.notifyStatus(FAILED); + this.cleanup(); + } + return this.deferredSubmit.promise; + } +}; + +// =================================== +// External API goes here +this.CrashSubmit = { + /** + * Submit the crash report named id.dmp from the "pending" directory. + * + * @param id + * Filename (minus .dmp extension) of the minidump to submit. + * @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 + * an extra parameter of "Throttleable=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, params) + { + params = params || {}; + let recordSubmission = false; + let submitSuccess = null; + let submitError = null; + let noThrottle = false; + let extraExtraKeyVals = null; + + if ('recordSubmission' in params) + recordSubmission = params.recordSubmission; + if ('noThrottle' in params) + noThrottle = params.noThrottle; + if ('extraExtraKeyVals' in params) + extraExtraKeyVals = params.extraExtraKeyVals; + + 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. + */ + delete: function CrashSubmit_delete(id) { + let [dump, extra, memory] = getPendingMinidump(id); + dump.remove(false); + extra.remove(false); + if (memory.exists()) { + memory.remove(false); + } + }, + + /** + * 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 + */ + + ignore: function CrashSubmit_ignore(id) { + let [dump, extra, mem] = getPendingMinidump(id); + return OS.File.open(dump.path + ".ignore", {create: true}, + {unixFlags: OS.Constants.libc.O_CREAT}) + .then((file) => { file.close(); }); + }, + + /** + * Get the list of pending crash IDs. + * + * @return an array of string, each being an ID as + * expected to be passed to submit() + */ + pendingIDs: function CrashSubmit_pendingIDs() { + return getAllPendingMinidumpsIDs(); + }, + + /** + * Get the list of pending crash IDs, excluding those marked to be ignored + * @param maxFileDate + * 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() + */ + pendingIDsAsync: Task.async(function* CrashSubmit_pendingIDsAsync(maxFileDate) { + let ids = []; + let info = null; + try { + info = yield OS.File.stat(getDir("pending").path) + } catch (ex) { + /* pending dir doesn't exist, ignore */ + return ids; + } + + if (info.isDir) { + let iterator = new OS.File.DirectoryIterator(getDir("pending").path); + try { + yield iterator.forEach( + function onEntry(file) { + if (file.name.endsWith(".dmp")) { + return OS.File.exists(file.path + ".ignore") + .then(ignoreExists => { + if (!ignoreExists) { + let id = file.name.slice(0, -4); + if (UUID_REGEX.test(id)) { + return OS.File.stat(file.path) + .then(info => { + if (info.lastAccessDate.valueOf() > + maxFileDate.valueOf()) { + ids.push(id); + } + }); + } + } + return null; + }); + } + return null; + } + ); + } catch (ex) { + Cu.reportError(ex); + } finally { + iterator.close(); + } + } + return ids; + }), + + /** + * Prune the saved dumps. + */ + pruneSavedDumps: function CrashSubmit_pruneSavedDumps() { + pruneSavedDumps(); + }, + + // List of currently active submit objects + _activeSubmissions: [] +}; diff --git a/toolkit/crashreporter/InjectCrashReporter.cpp b/toolkit/crashreporter/InjectCrashReporter.cpp new file mode 100644 index 000000000..1b79f2cd1 --- /dev/null +++ b/toolkit/crashreporter/InjectCrashReporter.cpp @@ -0,0 +1,84 @@ +/* -*- 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 "client/windows/crash_generation/crash_generation_client.h" +#include "nsExceptionHandler.h" +#include "LoadLibraryRemote.h" +#include "nsWindowsHelpers.h" + +using google_breakpad::CrashGenerationClient; +using CrashReporter::GetChildNotificationPipe; + +namespace mozilla { + +InjectCrashRunnable::InjectCrashRunnable(DWORD pid) + : mPID(pid) +{ + nsCOMPtr dll; + nsresult rv = NS_GetSpecialDirectory(NS_GRE_DIR, getter_AddRefs(dll)); + if (NS_SUCCEEDED(rv)) { + dll->Append(NS_LITERAL_STRING("breakpadinjector.dll")); + 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 000000000..5b40b49e3 --- /dev/null +++ b/toolkit/crashreporter/InjectCrashReporter.h @@ -0,0 +1,28 @@ +/* -*- 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: + InjectCrashRunnable(DWORD pid); + + NS_IMETHOD Run(); + +private: + DWORD mPID; + nsString mInjectorPath; +}; + +} // Namespace mozilla + +#endif diff --git a/toolkit/crashreporter/KeyValueParser.jsm b/toolkit/crashreporter/KeyValueParser.jsm new file mode 100644 index 000000000..ec45354f3 --- /dev/null +++ b/toolkit/crashreporter/KeyValueParser.jsm @@ -0,0 +1,54 @@ +/* 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/. */ + +Components.utils.import("resource://gre/modules/Services.jsm"); + +this.EXPORTED_SYMBOLS = [ + "parseKeyValuePairsFromLines", + "parseKeyValuePairs", + "parseKeyValuePairsFromFile" +]; + +const Cc = Components.classes; +const Ci = Components.interfaces; + +this.parseKeyValuePairsFromLines = function(lines) { + let data = {}; + for (let line of lines) { + if (line == '') + continue; + + // can't just .split() because the value might contain = characters + let eq = line.indexOf('='); + if (eq != -1) { + let [key, value] = [line.substring(0, eq), + line.substring(eq + 1)]; + if (key && value) + data[key] = value.replace(/\\n/g, "\n").replace(/\\\\/g, "\\"); + } + } + return data; +} + +this.parseKeyValuePairs = function parseKeyValuePairs(text) { + let lines = text.split('\n'); + return parseKeyValuePairsFromLines(lines); +}; + +this.parseKeyValuePairsFromFile = function parseKeyValuePairsFromFile(file) { + let fstream = Cc["@mozilla.org/network/file-input-stream;1"]. + createInstance(Ci.nsIFileInputStream); + fstream.init(file, -1, 0, 0); + let is = Cc["@mozilla.org/intl/converter-input-stream;1"]. + createInstance(Ci.nsIConverterInputStream); + is.init(fstream, "UTF-8", 1024, Ci.nsIConverterInputStream.DEFAULT_REPLACEMENT_CHARACTER); + let str = {}; + let contents = ''; + while (is.readString(4096, str) != 0) { + contents += str.value; + } + is.close(); + fstream.close(); + return parseKeyValuePairs(contents); +} diff --git a/toolkit/crashreporter/LoadLibraryRemote.cpp b/toolkit/crashreporter/LoadLibraryRemote.cpp new file mode 100644 index 000000000..f22a6220f --- /dev/null +++ b/toolkit/crashreporter/LoadLibraryRemote.cpp @@ -0,0 +1,454 @@ +/* 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; iheaders->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; iCharacteristics & 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; iNumberOfNames; 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 000000000..7beeaf4a5 --- /dev/null +++ b/toolkit/crashreporter/LoadLibraryRemote.h @@ -0,0 +1,24 @@ +/* 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-patches/00-arm-exidx-rollup.patch b/toolkit/crashreporter/breakpad-patches/00-arm-exidx-rollup.patch new file mode 100644 index 000000000..3ca5815d1 --- /dev/null +++ b/toolkit/crashreporter/breakpad-patches/00-arm-exidx-rollup.patch @@ -0,0 +1,1347 @@ +diff --git a/Makefile.am b/Makefile.am +index 42386be..e8f7402 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -524,6 +524,8 @@ src_tools_linux_dump_syms_dump_syms_SOURCES = \ + src/common/dwarf/bytereader.cc \ + src/common/dwarf/dwarf2diehandler.cc \ + src/common/dwarf/dwarf2reader.cc \ ++ src/common/arm_ex_reader.cc \ ++ src/common/arm_ex_to_module.cc \ + src/common/linux/crc32.cc \ + src/common/linux/dump_symbols.cc \ + src/common/linux/elf_symbols_to_module.cc \ +@@ -573,6 +575,8 @@ src_tools_mac_dump_syms_dump_syms_CXXFLAGS= \ + -DHAVE_MACH_O_NLIST_H + + 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/dwarf_cfi_to_module.cc \ + src/common/dwarf_cfi_to_module_unittest.cc \ +@@ -1336,6 +1340,10 @@ EXTRA_DIST = \ + src/common/linux/crc32.cc \ + src/common/linux/dump_symbols.cc \ + src/common/linux/dump_symbols.h \ ++ 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/linux/elf_symbols_to_module.cc \ + src/common/linux/elf_symbols_to_module.h \ + src/common/linux/elfutils.cc \ +diff --git a/src/common/arm_ex_reader.cc b/src/common/arm_ex_reader.cc +new file mode 100644 +index 0000000..2d1ed98 +--- /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 0000000..9b54e8a +--- /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 0000000..c326744 +--- /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 0000000..f413a16 +--- /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 1e96ca6..4222ce3 100644 +--- a/src/common/linux/dump_symbols.cc ++++ b/src/common/linux/dump_symbols.cc +@@ -52,6 +52,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" +@@ -71,6 +72,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 { + +@@ -373,6 +379,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); +@@ -756,6 +808,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 fa798f4..ca52f9f 100644 +--- a/src/common/module.cc ++++ b/src/common/module.cc +@@ -63,7 +63,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; + } +@@ -119,8 +119,14 @@ void Module::AddFunctions(vector::iterator begin, + AddFunction(*it); + } + +-void Module::AddStackFrameEntry(StackFrameEntry *stack_frame_entry) { +- stack_frame_entries_.push_back(stack_frame_entry); ++void Module::AddStackFrameEntry(StackFrameEntry* 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) { +@@ -180,8 +186,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() { +@@ -286,7 +309,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 65b5595..299bc38 100644 +--- a/src/common/module.h ++++ b/src/common/module.h +@@ -176,6 +176,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, +@@ -256,6 +263,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 +@@ -316,6 +327,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. +@@ -324,7 +338,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 0b64327..bf72736 100644 +--- a/src/common/module_unittest.cc ++++ b/src/common/module_unittest.cc +@@ -326,11 +326,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" +@@ -338,7 +333,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. +@@ -346,10 +346,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); +@@ -361,18 +369,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) { +@@ -544,3 +544,62 @@ TEST(Construct, FunctionsAndThumbExternsWithSameAddress) { + "PUBLIC cc00 0 arm_func\n", + contents.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/README b/toolkit/crashreporter/breakpad-patches/README new file mode 100644 index 000000000..b3f23b255 --- /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 000000000..347ad36ae --- /dev/null +++ b/toolkit/crashreporter/breakpad-windows-libxul/moz.build @@ -0,0 +1,32 @@ +# -*- 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 += [ + '../google-breakpad/src/common/windows/http_upload.cc', +] + +Library('google_breakpad_libxul_s') + +FINAL_LIBRARY = 'xul' + +for var in ('UNICODE', 'UNICODE_', 'BREAKPAD_NO_TERMINATE_THREAD'): + DEFINES[var] = True + +LOCAL_INCLUDES += [ + '/toolkit/crashreporter/google-breakpad/src', +] + +include('/toolkit/crashreporter/google-breakpad/src/common/windows/objs.mozbuild') +include('/toolkit/crashreporter/google-breakpad/src/client/windows/handler/objs.mozbuild') +include('/toolkit/crashreporter/google-breakpad/src/client/windows/sender/objs.mozbuild') +include('/toolkit/crashreporter/google-breakpad/src/client/windows/crash_generation/objs.mozbuild') + +SOURCES += objs_common +SOURCES += objs_crash_generation +SOURCES += objs_handler +SOURCES += objs_sender + +DISABLE_STL_WRAPPING = True diff --git a/toolkit/crashreporter/breakpad-windows-standalone/moz.build b/toolkit/crashreporter/breakpad-windows-standalone/moz.build new file mode 100644 index 000000000..a732ff99f --- /dev/null +++ b/toolkit/crashreporter/breakpad-windows-standalone/moz.build @@ -0,0 +1,26 @@ +# -*- 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/google-breakpad/src', +] + +include('/toolkit/crashreporter/google-breakpad/src/common/windows/objs.mozbuild') +include('/toolkit/crashreporter/google-breakpad/src/client/windows/handler/objs.mozbuild') +include('/toolkit/crashreporter/google-breakpad/src/client/windows/crash_generation/objs.mozbuild') + +SOURCES += objs_common +SOURCES += objs_crash_generation +SOURCES += objs_handler + +USE_STATIC_LIBS = True + +DISABLE_STL_WRAPPING = True diff --git a/toolkit/crashreporter/client/Makefile.in b/toolkit/crashreporter/client/Makefile.in new file mode 100644 index 000000000..88be52dff --- /dev/null +++ b/toolkit/crashreporter/client/Makefile.in @@ -0,0 +1,20 @@ +# 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 + sed -e 's/%APP_NAME%/$(MOZ_APP_DISPLAYNAME)/' $(srcdir)/macbuild/Contents/Resources/English.lproj/InfoPlist.strings.in | \ + iconv -f UTF-8 -t UTF-16 > $(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 000000000..640ea62c0 Binary files /dev/null and b/toolkit/crashreporter/client/Throbber-small.avi differ diff --git a/toolkit/crashreporter/client/crashreporter.cpp b/toolkit/crashreporter/client/crashreporter.cpp new file mode 100644 index 000000000..10aa65dd2 --- /dev/null +++ b/toolkit/crashreporter/client/crashreporter.cpp @@ -0,0 +1,759 @@ +/* -*- 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 + +using std::string; +using std::istream; +using std::ifstream; +using std::istringstream; +using std::ostringstream; +using std::ostream; +using std::ofstream; +using std::vector; +using std::auto_ptr; + +namespace CrashReporter { + +StringTable gStrings; +string gSettingsPath; +string gEventsPath; +int gArgc; +char** gArgv; + +enum SubmissionResult {Succeeded, Failed}; + +static auto_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) +{ + string errorMessage; + if (!gStrings[ST_CRASHREPORTERERROR].empty()) { + char buf[2048]; + UI_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; +} + +static string Escape(const string& str) +{ + string ret; + for (string::const_iterator iter = str.begin(); + iter != str.end(); + iter++) { + if (*iter == '\\') { + ret += "\\\\"; + } else if (*iter == '\n') { + ret += "\\n"; + } else if (*iter == '\t') { + ret += "\\t"; + } else { + ret.push_back(*iter); + } + } + + return ret; +} + +bool ReadStrings(istream& in, StringTable& strings, bool unescape) +{ + string currentSection; + 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); + bool success = false; + if (f->is_open()) { + success = ReadStrings(*f, strings, unescape); + f->close(); + } + + delete f; + return success; +} + +bool WriteStrings(ostream& out, + const string& header, + StringTable& strings, + bool escape) +{ + out << "[" << header << "]" << std::endl; + for (StringTable::iterator iter = strings.begin(); + iter != strings.end(); + iter++) { + out << iter->first << "="; + if (escape) + out << Escape(iter->second); + else + out << iter->second; + + out << std::endl; + } + + return true; +} + +bool WriteStringsToFile(const string& path, + const string& header, + StringTable& strings, + bool escape) +{ + ofstream* f = UIOpenWrite(path.c_str()); + bool success = false; + if (f->is_open()) { + success = WriteStrings(*f, header, strings, escape); + f->close(); + } + + 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); + else + return file; +} + +static string GetDumpLocalID() +{ + string localId = Basename(gReporterDumpFile); + string::size_type dot = localId.rfind('.'); + + if (dot == string::npos) + return ""; + + return localId.substr(0, dot); +} + +// This appends the StackTraces entry generated by the minidump analyzer to the +// main crash event so that it can be picked up by Firefox once it restarts +static void AppendStackTracesToEventFile(const string& aStackTraces) +{ + if (gEventsPath.empty()) { + // If there is no path for finding the crash event, skip this step. + return; + } + + string localId = GetDumpLocalID(); + string path = gEventsPath + UI_DIR_SEPARATOR + localId; + ofstream* f = UIOpenWrite(path.c_str(), true); + + if (f->is_open()) { + *f << "StackTraces=" << aStackTraces; + f->close(); + } + + delete f; +} + +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 = GetDumpLocalID(); + string fpath = gEventsPath + UI_DIR_SEPARATOR + localId + "-submission"; + ofstream* f = UIOpenWrite(fpath.c_str(), false, true); + 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 << std::endl; + } +} + +static void OpenLogFile() +{ + string logPath = gSettingsPath + UI_DIR_SEPARATOR + "submit.log"; + gLogStream.reset(UIOpenWrite(logPath.c_str(), true)); +} + +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); + 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); + if (!file->is_open()) { + delete file; + return false; + } + + char buf[1024]; + UI_SNPRINTF(buf, 1024, + gStrings["CrashID"].c_str(), + responseItems["CrashID"].c_str()); + *file << buf << "\n"; + + if (responseItems.find("ViewURL") != responseItems.end()) { + UI_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, ""); + } +} + +bool ShouldEnableSending() +{ + srand(time(0)); + return ((rand() % 100) < MOZ_CRASHREPORTER_ENABLE_PERCENT); +} + +} // namespace CrashReporter + +using namespace CrashReporter; + +void RewriteStrings(StringTable& queryParameters) +{ + // rewrite some UI strings with the values from the query parameters + string product = queryParameters["ProductName"]; + string vendor = queryParameters["Vendor"]; + if (vendor.empty()) { + // Assume Mozilla if no vendor is specified + vendor = "Mozilla"; + } + + char buf[4096]; + UI_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 + UI_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; + } + + UI_SNPRINTF(buf, sizeof(buf), + gStrings[ST_CRASHREPORTERDESCRIPTION].c_str(), + product.c_str()); + gStrings[ST_CRASHREPORTERDESCRIPTION] = buf; + + UI_SNPRINTF(buf, sizeof(buf), + gStrings[ST_CHECKSUBMIT].c_str(), + vendor.c_str()); + gStrings[ST_CHECKSUBMIT] = buf; + + UI_SNPRINTF(buf, sizeof(buf), + gStrings[ST_CHECKEMAIL].c_str(), + vendor.c_str()); + gStrings[ST_CHECKEMAIL] = buf; + + UI_SNPRINTF(buf, sizeof(buf), + gStrings[ST_RESTART].c_str(), + product.c_str()); + gStrings[ST_RESTART] = buf; + + UI_SNPRINTF(buf, sizeof(buf), + gStrings[ST_QUIT].c_str(), + product.c_str()); + gStrings[ST_QUIT] = buf; + + UI_SNPRINTF(buf, sizeof(buf), + gStrings[ST_ERROR_ENDOFLIFE].c_str(), + product.c_str()); + gStrings[ST_ERROR_ENDOFLIFE] = buf; +} + +bool CheckEndOfLifed(string version) +{ + string reportPath = + gSettingsPath + UI_DIR_SEPARATOR + "EndOfLife" + version; + return UIFileExists(reportPath); +} + +#ifndef RELEASE_OR_BETA + +static string +GetMinidumpAnalyzerPath() +{ + string path = gArgv[0]; + size_t pos = path.rfind(UI_CRASH_REPORTER_FILENAME BIN_SUFFIX); + path.erase(pos); + path.append(UI_MINIDUMP_ANALYZER_FILENAME BIN_SUFFIX); + + return path; +} + +#endif + +int main(int argc, char** argv) +{ + gArgc = argc; + gArgv = argv; + + 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 + UIShowDefaultUI(); + } else { +#ifndef RELEASE_OR_BETA + // start by running minidump analyzer, this is currently enabled only in + // nightly and aurora + UIRunMinidumpAnalyzer(GetMinidumpAnalyzerPath(), gReporterDumpFile); +#endif + + // 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(); + } + + StringTable queryParameters; + if (!ReadStringsFromFile(gExtraFile, queryParameters, true)) { + UIError(gStrings[ST_ERROR_EXTRAFILEREAD]); + return 0; + } + + if (queryParameters.find("ProductName") == queryParameters.end()) { + UIError(gStrings[ST_ERROR_NOPRODUCTNAME]); + return 0; + } + + // There is enough information in the extra file to rewrite strings + // to be product specific + RewriteStrings(queryParameters); + + if (queryParameters.find("ServerURL") == queryParameters.end()) { + 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. +#ifdef XP_WIN32 + static const wchar_t kDataDirKey[] = L"MOZ_CRASHREPORTER_DATA_DIRECTORY"; + const wchar_t *settingsPath = _wgetenv(kDataDirKey); + if (settingsPath && *settingsPath) { + gSettingsPath = WideToUTF8(settingsPath); + } +#else + static const char kDataDirKey[] = "MOZ_CRASHREPORTER_DATA_DIRECTORY"; + const char *settingsPath = getenv(kDataDirKey); + if (settingsPath && *settingsPath) { + gSettingsPath = settingsPath; + } +#endif + else { + string product = queryParameters["ProductName"]; + string vendor = queryParameters["Vendor"]; + if (!UIGetSettingsPath(vendor, product, gSettingsPath)) { + gSettingsPath.clear(); + } + } + + if (gSettingsPath.empty() || !UIEnsurePathExists(gSettingsPath)) { + UIError(gStrings[ST_ERROR_NOSETTINGSPATH]); + return 0; + } + + OpenLogFile(); + +#ifdef XP_WIN32 + static const wchar_t kEventsDirKey[] = L"MOZ_CRASHREPORTER_EVENTS_DIRECTORY"; + const wchar_t *eventsPath = _wgetenv(kEventsDirKey); + if (eventsPath && *eventsPath) { + gEventsPath = WideToUTF8(eventsPath); + } +#else + static const char kEventsDirKey[] = "MOZ_CRASHREPORTER_EVENTS_DIRECTORY"; + const char *eventsPath = getenv(kEventsDirKey); + if (eventsPath && *eventsPath) { + gEventsPath = eventsPath; + } +#endif + else { + gEventsPath.clear(); + } + + // Update the crash event with stacks if they are present + auto stackTracesItr = queryParameters.find("StackTraces"); + if (stackTracesItr != queryParameters.end()) { + AppendStackTracesToEventFile(stackTracesItr->second); + } + + 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 = queryParameters["ServerURL"]; + // we don't need to actually send this + queryParameters.erase("ServerURL"); + + queryParameters["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; + + ostringstream paramName; + int i = 0; + 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 (queryParameters.find("Version") != queryParameters.end() && + CheckEndOfLifed(queryParameters["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, queryParameters, 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 000000000..f8587bfad --- /dev/null +++ b/toolkit/crashreporter/client/crashreporter.exe.manifest @@ -0,0 +1,38 @@ + + + +Crash Reporter + + + + + + + + + + + + + + + + + + + + + + diff --git a/toolkit/crashreporter/client/crashreporter.h b/toolkit/crashreporter/client/crashreporter.h new file mode 100644 index 000000000..8c5ca3613 --- /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 +#include + +#define MAX_COMMENT_LENGTH 500 + +#if defined(XP_WIN32) + +#include + +#define UI_SNPRINTF _snprintf +#define UI_DIR_SEPARATOR "\\" + +std::string WideToUTF8(const std::wstring& wide, bool* success = 0); + +#else + +#define UI_SNPRINTF snprintf +#define UI_DIR_SEPARATOR "/" + +#endif + +#define UI_CRASH_REPORTER_FILENAME "crashreporter" +#define UI_MINIDUMP_ANALYZER_FILENAME "minidump-analyzer" + +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_CHECKEMAIL "CheckAllowEmail" +#define ST_EMAILGRAYTEXT "EmailGrayText" +#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 +//============================================================================= + +namespace CrashReporter { + extern StringTable gStrings; + extern std::string gSettingsPath; + extern std::string gEventsPath; + extern int gArgc; + extern char** gArgv; + + 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); + bool WriteStrings(std::ostream& out, + const std::string& header, + StringTable& strings, + bool escape); + bool WriteStringsToFile(const std::string& path, + const std::string& header, + StringTable& strings, + bool escape); + void LogMessage(const std::string& message); + void DeleteDump(); + bool ShouldEnableSending(); + + static const unsigned int kSaveCount = 10; +} + +//============================================================================= +// 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 StringTable& 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::ofstream* UIOpenWrite(const std::string& filename, + bool append=false, + bool binary=false); +void UIPruneSavedDumps(const std::string& directory); +void UIRunMinidumpAnalyzer(const std::string& exename, + const std::string& filename); + +#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 000000000..29ac3c618 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 000000000..0ccd0757f --- /dev/null +++ b/toolkit/crashreporter/client/crashreporter.rc @@ -0,0 +1,148 @@ +/* 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 + +1 24 "crashreporter.exe.manifest" + +///////////////////////////////////////////////////////////////////////////// +// +// 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 "tell mozilla to email me with more information",IDC_EMAILMECHECK, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,24,120,210,10 + EDITTEXT IDC_EMAILTEXT,36,133,198,14,ES_AUTOHSCROLL + 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 000000000..395a339bf --- /dev/null +++ b/toolkit/crashreporter/client/crashreporter_gtk_common.cpp @@ -0,0 +1,453 @@ +/* -*- 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 +#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; +StringTable gQueryParameters; +string gHttpProxy; +string gAuth; +string gCACertificateFile; +string gSendURL; +string gURLParameter; +vector gRestartArgs; +GThread* gSendThreadID; + +// From crashreporter_linux.cpp +void SaveSettings(); +void SendReport(); +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) + return false; + else if (pid == 0) { + (void)execv(argv[0], argv); + _exit(1); + } + + free(argv); + + return true; +} + +// Quit the app, used as a timeout callback +static gboolean CloseApp(gpointer data) +{ + 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; +} + +#ifdef MOZ_ENABLE_GCONF +#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(). +} +#endif + +gpointer SendThread(gpointer args) +{ + string response, error; + long response_code; + + bool success = google_breakpad::HTTPUpload::SendRequest + (gSendURL, + gQueryParameters, + 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); + // 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; + SendReport(); + } 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.erase("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 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 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); +} + +bool UIDeleteFile(const string& file) +{ + return (unlink(file.c_str()) != -1); +} + +std::ifstream* UIOpenRead(const string& filename) +{ + return new std::ifstream(filename.c_str(), std::ios::in); +} + +std::ofstream* UIOpenWrite(const string& filename, + bool append, // append=false + bool binary) // binary=false +{ + std::ios_base::openmode mode = std::ios::out; + + if (append) { + mode = mode | std::ios::app; + } + + if (binary) { + mode = mode | std::ios::binary; + } + + return new std::ofstream(filename.c_str(), mode); +} diff --git a/toolkit/crashreporter/client/crashreporter_gtk_common.h b/toolkit/crashreporter/client/crashreporter_gtk_common.h new file mode 100644 index 000000000..3a6350c5b --- /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 + +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 StringTable gQueryParameters; +extern std::string gHttpProxy; +extern std::string gAuth; +extern std::string gCACertificateFile; +extern std::string gSendURL; +extern std::string gURLParameter; + +void LoadProxyinfo(); +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); + +#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 000000000..6e7ccce40 --- /dev/null +++ b/toolkit/crashreporter/client/crashreporter_linux.cpp @@ -0,0 +1,576 @@ +/* -*- 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::string; +using std::vector; + +using namespace CrashReporter; + +static GtkWidget* gViewReportButton = 0; +static GtkWidget* gCommentTextLabel = 0; +static GtkWidget* gCommentText = 0; +static GtkWidget* gEmailMeCheck = 0; +static GtkWidget* gEmailEntryLabel = 0; +static GtkWidget* gEmailEntry = 0; + +static bool gEmailFieldHint = true; +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. + */ + + StringTable settings; + if (ReadStringsFromFile(gSettingsPath + "/" + kIniFile, settings, true)) { + if (settings.find("Email") != settings.end()) { + gtk_entry_set_text(GTK_ENTRY(gEmailEntry), settings["Email"].c_str()); + gEmailFieldHint = false; + } + if (settings.find("EmailMe") != settings.end()) { + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gEmailMeCheck), + settings["EmailMe"][0] != '0'); + } + if (settings.find("IncludeURL") != settings.end() && + gIncludeURLCheck != 0) { + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gIncludeURLCheck), + settings["IncludeURL"][0] != '0'); + } + bool enabled; + if (settings.find("SubmitReport") != settings.end()) + enabled = settings["SubmitReport"][0] != '0'; + else + enabled = ShouldEnableSending(); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gSubmitReportCheck), + enabled); + } +} + +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 (!gEmailFieldHint) + settings["Email"] = gtk_entry_get_text(GTK_ENTRY(gEmailEntry)); + else + settings.erase("Email"); + + settings["EmailMe"] = + gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gEmailMeCheck)) ? "1" : "0"; + 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() +{ + // 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(gEmailMeCheck, FALSE); + gtk_widget_set_sensitive(gEmailEntry, 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()); + +#ifdef MOZ_ENABLE_GCONF + LoadProxyinfo(); +#endif + + // and spawn a thread to do the sending + GError* err; + gSendThreadID = g_thread_create(SendThread, nullptr, TRUE, &err); +} + +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 (StringTable::iterator iter = gQueryParameters.begin(); + iter != gQueryParameters.end(); + iter++) { + gtk_text_buffer_insert(buffer, &end, iter->first.c_str(), -1); + gtk_text_buffer_insert(buffer, &end, ": ", -1); + gtk_text_buffer_insert(buffer, &end, iter->second.c_str(), -1); + 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_widget_set_sensitive(gEmailMeCheck, TRUE); + gtk_widget_set_sensitive(gEmailEntry, + gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gEmailMeCheck))); + 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_widget_set_sensitive(gEmailMeCheck, FALSE); + gtk_widget_set_sensitive(gEmailEntry, 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); +#if (MOZ_WIDGET_GTK >= 3) + gtk_widget_set_vexpand(scrolled, TRUE); +#endif + + 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.erase("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; +} + +static void UpdateEmail() +{ + const char* email = gtk_entry_get_text(GTK_ENTRY(gEmailEntry)); + if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gEmailMeCheck))) { + gtk_widget_set_sensitive(gEmailEntry, TRUE); + } else { + email = ""; + gtk_widget_set_sensitive(gEmailEntry, FALSE); + } + if (email[0] == '\0' || gEmailFieldHint) + gQueryParameters.erase("Email"); + else + gQueryParameters["Email"] = email; +} + +static void EmailMeClicked(GtkButton* sender, gpointer userData) +{ + UpdateEmail(); +} + +static void EmailChanged(GtkEditable* editable, gpointer userData) +{ + UpdateEmail(); +} + +static gboolean EmailFocusChange(GtkWidget* widget, GdkEventFocus* event, + gpointer userData) +{ + UpdateHintText(widget, event->in, &gEmailFieldHint, + gStrings[ST_EMAILGRAYTEXT].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 StringTable& queryParameters, + const string& sendURL, + const vector& restartArgs) +{ + gFiles = files; + gQueryParameters = queryParameters; + gSendURL = sendURL; + gRestartArgs = restartArgs; + if (gQueryParameters.find("URL") != gQueryParameters.end()) + gURLParameter = gQueryParameters["URL"]; + + 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 +#if (MOZ_WIDGET_GTK == 2) + gtk_widget_set_size_request(descriptionLabel, 400, -1); +#else + gtk_label_set_max_width_chars(GTK_LABEL(descriptionLabel), LABEL_MAX_CHAR_WIDTH); +#endif + 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); +#if (MOZ_WIDGET_GTK >= 3) + gtk_scrolled_window_set_min_content_height(GTK_SCROLLED_WINDOW(scrolled), 100); +#endif + + 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); + gtk_widget_set_size_request(GTK_WIDGET(gCommentText), -1, 100); + + if (gQueryParameters.find("URL") != gQueryParameters.end()) { + 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); + } + + gEmailMeCheck = + gtk_check_button_new_with_label(gStrings[ST_CHECKEMAIL].c_str()); + gtk_box_pack_start(GTK_BOX(innerVBox), gEmailMeCheck, FALSE, FALSE, 0); + g_signal_connect(gEmailMeCheck, "clicked", G_CALLBACK(EmailMeClicked), 0); + + GtkWidget* emailIndentBox = gtk_hbox_new(FALSE, 0); + gtk_box_pack_start(GTK_BOX(innerVBox), emailIndentBox, FALSE, FALSE, 0); + gtk_box_pack_start(GTK_BOX(emailIndentBox), gtk_label_new(""), + FALSE, FALSE, 9); + + gEmailEntryLabel = gtk_label_new(gStrings[ST_EMAILGRAYTEXT].c_str()); + gEmailEntry = gtk_entry_new(); + gtk_label_set_mnemonic_widget(GTK_LABEL(gEmailEntryLabel), gEmailEntry); + gtk_box_pack_start(GTK_BOX(emailIndentBox), gEmailEntry, TRUE, TRUE, 0); + g_signal_connect(gEmailEntry, "changed", G_CALLBACK(EmailChanged), 0); + g_signal_connect(gEmailEntry, "focus-in-event", G_CALLBACK(EmailFocusChange), 0); + g_signal_connect(gEmailEntry, "focus-out-event", G_CALLBACK(EmailFocusChange), 0); + + 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 +#if (MOZ_WIDGET_GTK == 2) + gtk_widget_set_size_request(gProgressLabel, 400, -1); +#else + gtk_label_set_max_width_chars(GTK_LABEL(gProgressLabel), LABEL_MAX_CHAR_WIDTH); +#endif + 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.size() > 0) { + 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(); + + UpdateEmail(); + UpdateSubmit(); + + UpdateHintText(gCommentText, FALSE, &gCommentFieldHint, + gStrings[ST_COMMENTGRAYTEXT].c_str()); + UpdateHintText(gEmailEntry, FALSE, &gEmailFieldHint, + gStrings[ST_EMAILGRAYTEXT].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 000000000..e274de0de --- /dev/null +++ b/toolkit/crashreporter/client/crashreporter_osx.h @@ -0,0 +1,107 @@ +/* -*- 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" + +// 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 StringTable&)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; +- (IBAction)emailMeClicked:(id)sender; + +- (void)controlTextDidChange:(NSNotification *)note; +- (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 000000000..0768d6da3 --- /dev/null +++ b/toolkit/crashreporter/client/crashreporter_osx.mm @@ -0,0 +1,922 @@ +/* -*- 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::string; +using std::vector; +using std::ostringstream; + +using namespace CrashReporter; + +static NSAutoreleasePool* gMainPool; +static CrashReporterUI* gUI = 0; +static StringTable gFiles; +static StringTable 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, +#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"]]; +} + +-(void)showCrashUI:(const StringTable&)files + queryParameters:(const StringTable&)queryParameters + sendURL:(const string&)sendURL +{ + gFiles = files; + gQueryParameters = queryParameters; + gSendURL = sendURL; + + [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)]; + [mEmailMeButton setTitle:Str(ST_CHECKEMAIL)]; + [mViewReportOkButton setTitle:Str(ST_OK)]; + + [mCommentText setPlaceholder:Str(ST_COMMENTGRAYTEXT)]; + if (gRTLlayout) + [mCommentText toggleBaseWritingDirection:self]; + [[mEmailText cell] setPlaceholderString:Str(ST_EMAILGRAYTEXT)]; + + if (gQueryParameters.find("URL") != gQueryParameters.end()) { + // save the URL value in case the checkbox gets unchecked + gURLParameter = gQueryParameters["URL"]; + } + 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 = NO; + NSUserDefaults* userDefaults = [NSUserDefaults standardUserDefaults]; + if (nil != [userDefaults objectForKey:@"submitReport"]) { + submitChecked = [userDefaults boolForKey:@"submitReport"]; + } + else { + // use compile-time specified enable percentage + submitChecked = ShouldEnableSending(); + [userDefaults setBool:submitChecked forKey:@"submitReport"]; + } + [mSubmitReportButton setState:(submitChecked ? 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 = [NSDictionary + dictionaryWithObject: + [NSFont boldSystemFontOfSize: + [NSFont smallSystemFontSize]] + forKey:NSFontAttributeName]; + NSDictionary* normalAttr = [NSDictionary + dictionaryWithObject: + [NSFont systemFontOfSize: + [NSFont smallSystemFontSize]] + forKey:NSFontAttributeName]; + + [mViewReportTextView setString:@""]; + for (StringTable::iterator iter = gQueryParameters.begin(); + iter != gQueryParameters.end(); + iter++) { + NSAttributedString* key = [[NSAttributedString alloc] + initWithString:NSSTR(iter->first + ": ") + attributes:boldAttr]; + NSAttributedString* value = [[NSAttributedString alloc] + initWithString:NSSTR(iter->second + "\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]; +} + +-(IBAction)emailMeClicked:(id)sender +{ + [self updateEmail]; +} + +-(void)controlTextDidChange:(NSNotification *)note +{ + [self updateEmail]; +} + +- (void)textDidChange:(NSNotification *)aNotification +{ + // update comment parameter + if ([[[mCommentText textStorage] mutableString] length] > 0) + gQueryParameters["Comments"] = [[[mCommentText textStorage] mutableString] + UTF8String]; + else + gQueryParameters.erase("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, + mEmailMeButton + }; + + for (int i=0; i<3; i++) { + NSRect frame = [checkboxes[i] frame]; + [checkboxes[i] sizeToFit]; + if (gRTLlayout) { + // sizeToFit will keep the left side fixed, so realign + float oldWidth = frame.size.width; + frame = [checkboxes[i] frame]; + frame.origin.x += oldWidth - frame.size.width; + [checkboxes[i] setFrame: frame]; + } + // keep existing spacing on left side, + 20 px spare on right + float neededWidth = frame.origin.x + frame.size.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, + mEmailMeButton, + mEmailText, + mProgressIndicator, + mProgressText + }; + for (unsigned int i=0; ifirst); + NSString* value = NSSTR(i->second); + if (key && value) { + [parameters setObject: value forKey: key]; + } else { + ostringstream message; + message << "Warning: skipping annotation '" << i->first + << "' due to malformed UTF-8 encoding"; + LogMessage(message.str()); + } + } + + for (StringTable::const_iterator i = gFiles.begin(); + i != gFiles.end(); + i++) { + [mPost addFileAtPath: NSSTR(i->second) name: NSSTR(i->first)]; + } + + [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); + + [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:NSRightTextAlignment + 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; + + [NSBundle loadNibNamed:(gRTLlayout ? @"MainMenuRTL" : @"MainMenu") + owner:NSApp]; + + return true; +} + +void UIShutdown() +{ + [gMainPool release]; +} + +void UIShowDefaultUI() +{ + [gUI showErrorUI: gStrings[ST_CRASHREPORTERDEFAULT]]; + [NSApp run]; +} + +bool UIShowCrashUI(const StringTable& files, + const StringTable& 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) +{ + FSRef foundRef; + OSErr err = FSFindFolder(kUserDomain, kApplicationSupportFolderType, + kCreateFolder, &foundRef); + if (err != noErr) + return false; + + unsigned char path[PATH_MAX]; + FSRefMakePath(&foundRef, path, sizeof(path)); + NSString* destPath = [NSString stringWithUTF8String:reinterpret_cast(path)]; + + // 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 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 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); +} + +bool UIDeleteFile(const string& file) +{ + return (unlink(file.c_str()) != -1); +} + +std::ifstream* UIOpenRead(const string& filename) +{ + return new std::ifstream(filename.c_str(), std::ios::in); +} + +std::ofstream* UIOpenWrite(const string& filename, + bool append, // append=false + bool binary) // binary=false +{ + std::ios_base::openmode mode = std::ios::out; + + if (append) { + mode = mode | std::ios::app; + } + + if (binary) { + mode = mode | std::ios::binary; + } + + return new std::ofstream(filename.c_str(), mode); +} diff --git a/toolkit/crashreporter/client/crashreporter_unix_common.cpp b/toolkit/crashreporter/client/crashreporter_unix_common.cpp new file mode 100644 index 000000000..f42a35616 --- /dev/null +++ b/toolkit/crashreporter/client/crashreporter_unix_common.cpp @@ -0,0 +1,85 @@ +/* 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 + +using namespace CrashReporter; +using std::string; +using std::vector; +using std::sort; + +struct FileData +{ + time_t timestamp; + string path; +}; + +static bool CompareFDTime(const FileData& fd1, const FileData& fd2) +{ + return fd1.timestamp > fd2.timestamp; +} + +void UIPruneSavedDumps(const std::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); + } + + 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.c_str()); + + // s/.dmp/.extra/ + path.replace(path.size() - 4, 4, ".extra"); + UIDeleteFile(path.c_str()); + + dumpfiles.pop_back(); + } +} + +void UIRunMinidumpAnalyzer(const string& exename, const string& filename) +{ + // Run the minidump analyzer and wait for it to finish + pid_t pid = fork(); + + if (pid == -1) { + return; // Nothing to do upon failure + } else if (pid == 0) { + execl(exename.c_str(), exename.c_str(), filename.c_str(), nullptr); + } else { + waitpid(pid, nullptr, 0); + } +} diff --git a/toolkit/crashreporter/client/crashreporter_win.cpp b/toolkit/crashreporter/client/crashreporter_win.cpp new file mode 100644 index 000000000..57ca495ba --- /dev/null +++ b/toolkit/crashreporter/client/crashreporter_win.cpp @@ -0,0 +1,1568 @@ +/* -*- 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 +#include "resource.h" +#include "client/windows/sender/crash_report_sender.h" +#include "common/windows/string_utils-inl.h" + +#define CRASH_REPORTER_VALUE L"Enabled" +#define SUBMIT_REPORT_VALUE L"SubmitCrashReport" +#define SUBMIT_REPORT_OLD L"SubmitReport" +#define INCLUDE_URL_VALUE L"IncludeURL" +#define EMAIL_ME_VALUE L"EmailMe" +#define EMAIL_VALUE L"Email" +#define MAX_EMAIL_LENGTH 1024 + +#define SENDURL_ORIGINAL L"https://crash-reports.mozilla.com/submit" +#define SENDURL_XPSP2 L"https://crash-reports-xpsp2.mozilla.com/submit" + +#define WM_UPLOADCOMPLETE WM_APP + +// Thanks, Windows.h :( +#undef min +#undef max + +using std::string; +using std::wstring; +using std::map; +using std::vector; +using std::set; +using std::ios; +using std::ifstream; +using std::ofstream; + +using namespace CrashReporter; + +typedef struct { + HWND hDlg; + map 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 map gQueryParameters; +static wstring gCrashReporterKey(L"Software\\Mozilla\\Crash Reporter"); +static wstring 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_EMAILMECHECK, + IDC_EMAILTEXT, + 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; +} + +// Removes a value from HKEY_LOCAL_MACHINE and HKEY_CURRENT_USER, if it exists. +static void RemoveUnusedValues(const wchar_t* key, LPCTSTR valueName) +{ + HKEY hRegKey; + + if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, key, 0, KEY_SET_VALUE, &hRegKey) + == ERROR_SUCCESS) { + RegDeleteValue(hRegKey, valueName); + RegCloseKey(hRegKey); + } + + if (RegOpenKeyEx(HKEY_CURRENT_USER, key, 0, KEY_SET_VALUE, &hRegKey) + == ERROR_SUCCESS) { + RegDeleteValue(hRegKey, valueName); + RegCloseKey(hRegKey); + } +} + +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; + + // remove the old value from the registry if it exists + RemoveUnusedValues(key, SUBMIT_REPORT_OLD); + + 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 bool GetStringValue(HKEY hRegKey, LPCTSTR valueName, wstring& value) +{ + DWORD type, dataSize; + wchar_t buf[2048]; + dataSize = sizeof(buf); + if (RegQueryValueEx(hRegKey, valueName, nullptr, + &type, (LPBYTE)buf, &dataSize) == ERROR_SUCCESS && + type == REG_SZ) { + value = buf; + return true; + } + + return false; +} + +static bool GetStringKey(const wchar_t* key, + const wchar_t* valueName, + wstring& value) +{ + value = L""; + bool found = false; + HKEY hRegKey; + // see if our reg key is set globally + if (RegOpenKey(HKEY_LOCAL_MACHINE, key, &hRegKey) == ERROR_SUCCESS) { + if (GetStringValue(hRegKey, valueName, value)) { + found = true; + } + RegCloseKey(hRegKey); + } else { + // look for it in user settings + if (RegOpenKey(HKEY_CURRENT_USER, key, &hRegKey) == ERROR_SUCCESS) { + if (GetStringValue(hRegKey, valueName, value)) { + found = true; + } + RegCloseKey(hRegKey); + } + } + + return found; +} + +static void SetStringKey(const wchar_t* key, + const wchar_t* valueName, + const wstring& value) +{ + HKEY hRegKey; + if (RegCreateKey(HKEY_CURRENT_USER, key, &hRegKey) == ERROR_SUCCESS) { + RegSetValueEx(hRegKey, valueName, 0, REG_SZ, + (LPBYTE)value.c_str(), + (value.length() + 1) * sizeof(wchar_t)); + 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", 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); +} + +static void SetDlgItemDisabled(HWND hwndDlg, UINT item, bool disabled) +{ + HWND hwnd = GetDlgItem(hwndDlg, item); + LONG style = GetWindowLong(hwnd, GWL_STYLE); + if (!disabled) + style |= WS_DISABLED; + else + style &= ~WS_DISABLED; + + SetWindowLong(hwnd, GWL_STYLE, style); +} + +/* === 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 { + google_breakpad::CrashReportSender sender(L""); + finishedOk = (sender.SendCrashReport(td->sendURL, + td->queryParameters, + 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()); + } + } + + 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 + wchar_t email[MAX_EMAIL_LENGTH]; + GetDlgItemTextW(hwndDlg, IDC_EMAILTEXT, email, + sizeof(email) / sizeof(email[0])); + SetStringKey(gCrashReporterKey.c_str(), EMAIL_VALUE, email); + + SetBoolKey(gCrashReporterKey.c_str(), INCLUDE_URL_VALUE, + IsDlgButtonChecked(hwndDlg, IDC_INCLUDEURLCHECK) != 0); + SetBoolKey(gCrashReporterKey.c_str(), EMAIL_ME_VALUE, + IsDlgButtonChecked(hwndDlg, IDC_EMAILMECHECK) != 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 (int 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_EMAILMECHECK), false); + EnableWindow(GetDlgItem(hwndDlg, IDC_EMAILTEXT), 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 (map::const_iterator i = gQueryParameters.begin(); + i != gQueryParameters.end(); + i++) { + description += i->first; + description += L": "; + description += i->second; + 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[L"URL"] = gURLParameter; + } else { + gQueryParameters.erase(L"URL"); + } +} + +static void UpdateEmail(HWND hwndDlg) +{ + if (IsDlgButtonChecked(hwndDlg, IDC_EMAILMECHECK)) { + wchar_t email[MAX_EMAIL_LENGTH]; + GetDlgItemTextW(hwndDlg, IDC_EMAILTEXT, email, + sizeof(email) / sizeof(email[0])); + gQueryParameters[L"Email"] = email; + if (IsDlgButtonChecked(hwndDlg, IDC_SUBMITREPORTCHECK)) + EnableWindow(GetDlgItem(hwndDlg, IDC_EMAILTEXT), true); + } else { + gQueryParameters.erase(L"Email"); + EnableWindow(GetDlgItem(hwndDlg, IDC_EMAILTEXT), false); + } +} + +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[L"Comments"] = comment; + else + gQueryParameters.erase(L"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_EMAILMECHECK, + IDC_EMAILTEXT, + IDC_PROGRESSTEXT + }; + + RECT dlgRect; + GetClientRect(hwndDlg, &dlgRect); + + for (int i=0; iexStyle |= 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 = ShouldEnableSending(); + + 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); + } + + hwnd = GetDlgItem(hwndDlg, IDC_EMAILMECHECK); + GetRelativeRect(hwnd, hwndDlg, &rect); + diff = ResizeControl(hwnd, rect, Str(ST_CHECKEMAIL), false, + gCheckboxPadding); + maxdiff = std::max(diff, maxdiff); + SetDlgItemText(hwndDlg, IDC_EMAILMECHECK, Str(ST_CHECKEMAIL).c_str()); + + if (CheckBoolKey(gCrashReporterKey.c_str(), EMAIL_ME_VALUE, &enabled) && + enabled) { + CheckDlgButton(hwndDlg, IDC_EMAILMECHECK, BST_CHECKED); + } else { + CheckDlgButton(hwndDlg, IDC_EMAILMECHECK, BST_UNCHECKED); + } + + wstring email; + if (GetStringKey(gCrashReporterKey.c_str(), EMAIL_VALUE, email)) { + SetDlgItemText(hwndDlg, IDC_EMAILTEXT, email.c_str()); + } + + // Subclass email edit control to get placeholder text + HWND hwndEmail = GetDlgItem(hwndDlg, IDC_EMAILTEXT); + OldWndProc = (WNDPROC)SetWindowLongPtr(hwndEmail, + GWLP_WNDPROC, + (LONG_PTR)EditSubclassProc); + SetWindowLongPtr(hwndEmail, GWLP_USERDATA, (LONG_PTR)OldWndProc); + wstring emailGrayText = Str(ST_EMAILGRAYTEXT); + hMem = (wchar_t*)GlobalAlloc(GPTR, (emailGrayText.length() + 1)*sizeof(wchar_t)); + wcscpy(hMem, emailGrayText.c_str()); + SetProp(hwndEmail, L"PROP_GRAYTEXT", hMem); + + 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.find(L"URL") == gQueryParameters.end()) { + RECT urlCheckRect, emailCheckRect; + GetWindowRect(GetDlgItem(hwndDlg, IDC_INCLUDEURLCHECK), &urlCheckRect); + GetWindowRect(GetDlgItem(hwndDlg, IDC_EMAILMECHECK), &emailCheckRect); + + SetDlgItemVisible(hwndDlg, IDC_INCLUDEURLCHECK, false); + + gAttachedBottom.erase(IDC_VIEWREPORTBUTTON); + gAttachedBottom.erase(IDC_SUBMITREPORTCHECK); + gAttachedBottom.erase(IDC_COMMENTTEXT); + + StretchDialog(hwndDlg, urlCheckRect.top - emailCheckRect.top); + + 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); + UpdateEmail(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_EMAILMECHECK: + UpdateEmail(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_EMAILTEXT: + UpdateEmail(hwndDlg); + break; + 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_LBUTTONDOWN: { + HWND hwndEmail = GetDlgItem(hwndDlg, IDC_EMAILTEXT); + POINT p = { LOWORD(lParam), HIWORD(lParam) }; + // if the email edit control is clicked, enable it, + // check the email checkbox, and focus the email edit control + if (ChildWindowFromPoint(hwndDlg, p) == hwndEmail && + IsWindowEnabled(GetDlgItem(hwndDlg, IDC_RESTARTBUTTON)) && + !IsWindowEnabled(hwndEmail) && + IsDlgButtonChecked(hwndDlg, IDC_SUBMITREPORTCHECK) != 0) { + CheckDlgButton(hwndDlg, IDC_EMAILMECHECK, BST_CHECKED); + UpdateEmail(hwndDlg); + SetFocus(hwndEmail); + } + break; + } + + 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 (int 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); +} + +static bool CanUseMainCrashReportServer() +{ + // Any NT from 6.0 and above is fine. + if (IsWindowsVersionOrGreater(6, 0, 0)) { + return true; + } + + // On NT 5 servers, we need Server 2003 SP2. + if (IsWindowsServer()) { + return IsWindowsVersionOrGreater(5, 2, 2); + } + + // Otherwise we have an NT 5 client. + // We need exactly XP SP3 (version 5.1 SP3 but not version 5.2). + return (IsWindowsVersionOrGreater(5, 1, 3) && + !IsWindowsVersionOrGreater(5, 2, 0)); +} + +bool UIShowCrashUI(const StringTable& files, + const StringTable& queryParameters, + const string& sendURL, + const vector& restartArgs) +{ + gSendData.hDlg = nullptr; + gSendData.sendURL = UTF8ToWide(sendURL); + + // Older Windows don't support the crash report server's crypto. + // This is a hack to use an alternate server. + if (!CanUseMainCrashReportServer() && + gSendData.sendURL.find(SENDURL_ORIGINAL) == 0) { + gSendData.sendURL.replace(0, ARRAYSIZE(SENDURL_ORIGINAL) - 1, + SENDURL_XPSP2); + } + + for (StringTable::const_iterator i = files.begin(); + i != files.end(); + i++) { + gSendData.files[UTF8ToWide(i->first)] = UTF8ToWide(i->second); + } + + for (StringTable::const_iterator i = queryParameters.begin(); + i != queryParameters.end(); + i++) { + gQueryParameters[UTF8ToWide(i->first)] = UTF8ToWide(i->second); + } + + if (gQueryParameters.find(L"Vendor") != gQueryParameters.end()) { + gCrashReporterKey = L"Software\\"; + if (!gQueryParameters[L"Vendor"].empty()) { + gCrashReporterKey += gQueryParameters[L"Vendor"] + L"\\"; + } + gCrashReporterKey += gQueryParameters[L"ProductName"] + L"\\Crash Reporter"; + } + + if (gQueryParameters.find(L"URL") != gQueryParameters.end()) + gURLParameter = gQueryParameters[L"URL"]; + + gRestartArgs = restartArgs; + + if (gStrings.find("isRTL") != gStrings.end() && + gStrings["isRTL"] == "yes") + gRTLlayout = 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, size, dwRes; + dwRes = ::RegOpenKeyExW(HKEY_CURRENT_USER, + L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\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) +{ + // adapted from breakpad's src/common/windows/http_upload.cc + +#if defined(_MSC_VER) + ifstream* file = new ifstream(); + file->open(UTF8ToWide(filename).c_str(), ios::in); +#else // GCC + ifstream* file = new ifstream(WideToMBCP(UTF8ToWide(filename), CP_ACP).c_str(), + ios::in); +#endif // _MSC_VER + + return file; +} + +ofstream* UIOpenWrite(const string& filename, + bool append, // append=false + bool binary) // binary=false +{ + // adapted from breakpad's src/common/windows/http_upload.cc + std::ios_base::openmode mode = ios::out; + if (append) { + mode = mode | ios::app; + } + if (binary) { + mode = mode | ios::binary; + } + +#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(); + } +} + +void UIRunMinidumpAnalyzer(const string& exename, const string& filename) +{ + wstring cmdLine; + + cmdLine += L"\"" + UTF8ToWide(exename) + L"\" "; + cmdLine += L"\"" + UTF8ToWide(filename) + L"\" "; + + STARTUPINFO si = {}; + PROCESS_INFORMATION pi = {}; + + si.cb = sizeof(si); + si.dwFlags = STARTF_USESHOWWINDOW; + si.wShowWindow = SW_SHOWNORMAL; + + if (CreateProcess(nullptr, (LPWSTR)cmdLine.c_str(), nullptr, nullptr, FALSE, + 0, nullptr, nullptr, &si, &pi)) { + WaitForSingleObject(pi.hProcess, INFINITE); + CloseHandle(pi.hProcess); + CloseHandle(pi.hThread); + } +} diff --git a/toolkit/crashreporter/client/macbuild/Contents/Info.plist b/toolkit/crashreporter/client/macbuild/Contents/Info.plist new file mode 100644 index 000000000..299581f52 --- /dev/null +++ b/toolkit/crashreporter/client/macbuild/Contents/Info.plist @@ -0,0 +1,32 @@ + + + + + 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 + NSPrincipalClass + NSApplication + + diff --git a/toolkit/crashreporter/client/macbuild/Contents/PkgInfo b/toolkit/crashreporter/client/macbuild/Contents/PkgInfo new file mode 100644 index 000000000..cae6d0a58 --- /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 000000000..6fe086e35 --- /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 = "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 000000000..e31ff0bfb --- /dev/null +++ b/toolkit/crashreporter/client/macbuild/Contents/Resources/English.lproj/MainMenu.nib/classes.nib @@ -0,0 +1,102 @@ + + + + + IBClasses + + + ACTIONS + + closeClicked + id + emailMeClicked + 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 000000000..517349ffc --- /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 000000000..bfdcccb74 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 000000000..e31ff0bfb --- /dev/null +++ b/toolkit/crashreporter/client/macbuild/Contents/Resources/English.lproj/MainMenuRTL.nib/classes.nib @@ -0,0 +1,102 @@ + + + + + IBClasses + + + ACTIONS + + closeClicked + id + emailMeClicked + 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 000000000..4a2251aaf --- /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 000000000..6c93849b9 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 000000000..341cd05a4 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 000000000..456c794af --- /dev/null +++ b/toolkit/crashreporter/client/moz.build @@ -0,0 +1,78 @@ +# -*- 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 += [ + 'crashreporter.cpp', + ] + +if CONFIG['OS_ARCH'] == 'WINNT': + UNIFIED_SOURCES += [ + 'crashreporter_win.cpp', + ] + DEFINES['UNICODE'] = True + DEFINES['_UNICODE'] = True + USE_LIBS += [ + 'google_breakpad_libxul_s', + ] + OS_LIBS += [ + 'comctl32', + 'shell32', + 'wininet', + 'shlwapi', + ] +elif CONFIG['OS_ARCH'] == 'Darwin': + UNIFIED_SOURCES += [ + 'crashreporter_osx.mm', + 'crashreporter_unix_common.cpp', + ] + LOCAL_INCLUDES += [ + '../google-breakpad/src/common/mac', + ] + OS_LIBS += ['-framework Cocoa'] + USE_LIBS += [ + 'breakpad_common_s', + 'breakpad_mac_common_s', + ] +elif CONFIG['OS_ARCH'] == 'SunOS': + SOURCES += [ + 'crashreporter_linux.cpp', + 'crashreporter_unix.cpp', + ] + USE_LIBS += [ + 'breakpad_solaris_common_s', + ] + +if 'gtk' in CONFIG['MOZ_WIDGET_TOOLKIT']: + UNIFIED_SOURCES += [ + 'crashreporter_gtk_common.cpp', + 'crashreporter_linux.cpp', + 'crashreporter_unix_common.cpp' + ] + USE_LIBS += [ + 'breakpad_linux_common_s', + ] + OS_LIBS += CONFIG['TK_LIBS'] + OS_LIBS += CONFIG['MOZ_GTHREAD_LIBS'] + CXXFLAGS += CONFIG['TK_CFLAGS'] + CXXFLAGS += CONFIG['MOZ_GTHREAD_CFLAGS'] + +if CONFIG['OS_ARCH'] == 'Linux' or CONFIG['OS_ARCH'] == 'SunOS': + FINAL_TARGET_FILES += [ + '/toolkit/themes/windows/global/throbber/Throbber-small.gif', + ] + +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. +DISABLE_STL_WRAPPING = True + +include('/toolkit/crashreporter/crashreporter.mozbuild') diff --git a/toolkit/crashreporter/client/resource.h b/toolkit/crashreporter/client/resource.h new file mode 100644 index 000000000..d736b0367 --- /dev/null +++ b/toolkit/crashreporter/client/resource.h @@ -0,0 +1,37 @@ +/* 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_EMAILMECHECK 1008 +#define IDC_EMAILTEXT 1009 +#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.js b/toolkit/crashreporter/content/crashes.js new file mode 100644 index 000000000..f1d3f39d9 --- /dev/null +++ b/toolkit/crashreporter/content/crashes.js @@ -0,0 +1,179 @@ +/* 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/. */ + +var { classes: Cc, utils: Cu, interfaces: Ci } = Components; + +var reportURL; + +Cu.import("resource://gre/modules/CrashReports.jsm"); +Cu.import("resource://gre/modules/Services.jsm"); +Cu.import("resource://gre/modules/XPCOMUtils.jsm"); +Cu.import("resource://gre/modules/Task.jsm"); +Cu.import("resource://gre/modules/osfile.jsm"); + +XPCOMUtils.defineLazyModuleGetter(this, "CrashSubmit", + "resource://gre/modules/CrashSubmit.jsm"); + +const buildID = Services.appinfo.appBuildID; + +function submitPendingReport(event) { + let link = event.target; + let id = link.firstChild.textContent; + link.className = "submitting"; + CrashSubmit.submit(id, { noThrottle: true }).then( + (remoteCrashID) => { + link.className = ""; + // Reset the link to point at our new crash report. This way, if the + // user clicks "Back", the link will be correct. + link.firstChild.textContent = remoteCrashID; + link.setAttribute("id", remoteCrashID); + link.removeEventListener("click", submitPendingReport, true); + + if (reportURL) { + link.setAttribute("href", reportURL + remoteCrashID); + // redirect the user to their brand new crash report + window.location.href = reportURL + remoteCrashID; + } + }, + () => { + // XXX: do something more useful here + link.className = ""; + + // Dispatch an event, useful for testing + let event = document.createEvent("Events"); + event.initEvent("CrashSubmitFailed", true, false); + document.dispatchEvent(event); + }); + event.preventDefault(); + return false; +} + +function populateReportList() { + + Services.telemetry.getHistogramById("ABOUTCRASHES_OPENED_COUNT").add(1); + + var prefService = Cc["@mozilla.org/preferences-service;1"]. + getService(Ci.nsIPrefBranch); + + try { + reportURL = prefService.getCharPref("breakpad.reportURL"); + // Ignore any non http/https urls + if (!/^https?:/i.test(reportURL)) + reportURL = null; + } + catch (e) { } + if (!reportURL) { + document.getElementById("clear-reports").style.display = "none"; + document.getElementById("reportList").style.display = "none"; + document.getElementById("noConfig").style.display = "block"; + return; + } + let reports = CrashReports.getReports(); + + if (reports.length == 0) { + document.getElementById("clear-reports").style.display = "none"; + document.getElementById("reportList").style.display = "none"; + document.getElementById("noReports").style.display = "block"; + return; + } + + const locale = Cc["@mozilla.org/chrome/chrome-registry;1"] + .getService(Ci.nsIXULChromeRegistry) + .getSelectedLocale("global", true); + var dateFormatter = new Intl.DateTimeFormat(locale, { year: '2-digit', + month: 'numeric', + day: 'numeric' }); + var timeFormatter = new Intl.DateTimeFormat(locale, { hour: 'numeric', + minute: 'numeric' }); + var ios = Cc["@mozilla.org/network/io-service;1"]. + getService(Ci.nsIIOService); + var reportURI = ios.newURI(reportURL, null, null); + // resolving this URI relative to /report/index + var aboutThrottling = ios.newURI("../../about/throttling", null, reportURI); + + for (var i = 0; i < reports.length; i++) { + var row = document.createElement("tr"); + var cell = document.createElement("td"); + row.appendChild(cell); + var link = document.createElement("a"); + if (reports[i].pending) { + link.setAttribute("href", aboutThrottling.spec); + link.addEventListener("click", submitPendingReport, true); + } + else { + link.setAttribute("href", reportURL + reports[i].id); + } + link.setAttribute("id", reports[i].id); + link.classList.add("crashReport"); + link.appendChild(document.createTextNode(reports[i].id)); + cell.appendChild(link); + + var date = new Date(reports[i].date); + cell = document.createElement("td"); + cell.appendChild(document.createTextNode(dateFormatter.format(date))); + row.appendChild(cell); + cell = document.createElement("td"); + cell.appendChild(document.createTextNode(timeFormatter.format(date))); + row.appendChild(cell); + if (reports[i].pending) { + document.getElementById("unsubmitted").appendChild(row); + } else { + document.getElementById("submitted").appendChild(row); + } + } +} + +var clearReports = Task.async(function*() { + let bundle = Services.strings.createBundle("chrome://global/locale/crashes.properties"); + + if (!Services. + prompt.confirm(window, + bundle.GetStringFromName("deleteconfirm.title"), + bundle.GetStringFromName("deleteconfirm.description"))) { + return; + } + + let cleanupFolder = Task.async(function*(path, filter) { + let iterator = new OS.File.DirectoryIterator(path); + try { + yield iterator.forEach(Task.async(function*(aEntry) { + if (!filter || (yield filter(aEntry))) { + yield OS.File.remove(aEntry.path); + } + })); + } catch (e) { + if (!(e instanceof OS.File.Error) || !e.becauseNoSuchFile) { + throw e; + } + } finally { + iterator.close(); + } + }); + + yield cleanupFolder(CrashReports.submittedDir.path, function*(aEntry) { + return aEntry.name.startsWith("bp-") && aEntry.name.endsWith(".txt"); + }); + + let oneYearAgo = Date.now() - 31586000000; + yield cleanupFolder(CrashReports.reportsDir.path, function*(aEntry) { + if (!aEntry.name.startsWith("InstallTime") || + aEntry.name == "InstallTime" + buildID) { + return false; + } + + let date = aEntry.winLastWriteDate; + if (!date) { + let stat = yield OS.File.stat(aEntry.path); + date = stat.lastModificationDate; + } + + return (date < oneYearAgo); + }); + + yield cleanupFolder(CrashReports.pendingDir.path); + + document.getElementById("clear-reports").style.display = "none"; + document.getElementById("reportList").style.display = "none"; + document.getElementById("noReports").style.display = "block"; +}); diff --git a/toolkit/crashreporter/content/crashes.xhtml b/toolkit/crashreporter/content/crashes.xhtml new file mode 100644 index 000000000..695320356 --- /dev/null +++ b/toolkit/crashreporter/content/crashes.xhtml @@ -0,0 +1,123 @@ + + + + + + %globalDTD; + %crashesDTD; +]> + + + + + +