aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/breakpad_googletest_includes.h5
-rw-r--r--src/build/all.gyp41
-rw-r--r--src/build/common.gypi1045
-rw-r--r--src/build/filename_rules.gypi57
-rwxr-xr-xsrc/build/gyp_breakpad67
-rw-r--r--src/build/testing.gyp90
-rw-r--r--src/client/apple/Framework/BreakpadDefines.h5
-rw-r--r--src/client/ios/Breakpad.h51
-rw-r--r--src/client/ios/Breakpad.mm305
-rw-r--r--src/client/ios/Breakpad.xcodeproj/project.pbxproj16
-rw-r--r--src/client/ios/BreakpadController.h5
-rw-r--r--src/client/ios/BreakpadController.mm5
-rw-r--r--src/client/ios/exception_handler_no_mach.cc11
-rw-r--r--src/client/ios/exception_handler_no_mach.h47
-rw-r--r--src/client/ios/handler/ios_exception_minidump_generator.h19
-rw-r--r--src/client/ios/handler/ios_exception_minidump_generator.mm25
-rw-r--r--src/client/linux/crash_generation/client_info.h5
-rw-r--r--src/client/linux/crash_generation/crash_generation_client.cc7
-rw-r--r--src/client/linux/crash_generation/crash_generation_client.h5
-rw-r--r--src/client/linux/crash_generation/crash_generation_server.cc11
-rw-r--r--src/client/linux/crash_generation/crash_generation_server.h5
-rw-r--r--src/client/linux/dump_writer_common/mapping_info.h5
-rw-r--r--src/client/linux/dump_writer_common/raw_context_cpu.h13
-rw-r--r--src/client/linux/dump_writer_common/thread_info.cc98
-rw-r--r--src/client/linux/dump_writer_common/thread_info.h7
-rw-r--r--src/client/linux/dump_writer_common/ucontext_reader.cc84
-rw-r--r--src/client/linux/dump_writer_common/ucontext_reader.h11
-rw-r--r--src/client/linux/handler/exception_handler.cc26
-rw-r--r--src/client/linux/handler/exception_handler.h23
-rw-r--r--src/client/linux/handler/exception_handler_unittest.cc37
-rw-r--r--src/client/linux/handler/microdump_extra_info.h5
-rw-r--r--src/client/linux/handler/minidump_descriptor.cc5
-rw-r--r--src/client/linux/handler/minidump_descriptor.h6
-rw-r--r--src/client/linux/log/log.cc9
-rw-r--r--src/client/linux/log/log.h5
-rw-r--r--src/client/linux/microdump_writer/microdump_writer.cc27
-rw-r--r--src/client/linux/microdump_writer/microdump_writer.h5
-rw-r--r--src/client/linux/microdump_writer/microdump_writer_unittest.cc5
-rw-r--r--src/client/linux/minidump_writer/cpu_set.h5
-rw-r--r--src/client/linux/minidump_writer/cpu_set_unittest.cc5
-rw-r--r--src/client/linux/minidump_writer/directory_reader.h5
-rw-r--r--src/client/linux/minidump_writer/directory_reader_unittest.cc7
-rw-r--r--src/client/linux/minidump_writer/line_reader.h7
-rw-r--r--src/client/linux/minidump_writer/line_reader_unittest.cc19
-rw-r--r--src/client/linux/minidump_writer/linux_core_dumper.cc33
-rw-r--r--src/client/linux/minidump_writer/linux_core_dumper.h5
-rw-r--r--src/client/linux/minidump_writer/linux_core_dumper_unittest.cc5
-rw-r--r--src/client/linux/minidump_writer/linux_dumper.cc19
-rw-r--r--src/client/linux/minidump_writer/linux_dumper.h15
-rw-r--r--src/client/linux/minidump_writer/linux_dumper_unittest_helper.cc15
-rw-r--r--src/client/linux/minidump_writer/linux_ptrace_dumper.cc10
-rw-r--r--src/client/linux/minidump_writer/linux_ptrace_dumper.h5
-rw-r--r--src/client/linux/minidump_writer/linux_ptrace_dumper_unittest.cc14
-rw-r--r--src/client/linux/minidump_writer/minidump_writer.cc185
-rw-r--r--src/client/linux/minidump_writer/minidump_writer.h5
-rw-r--r--src/client/linux/minidump_writer/minidump_writer_unittest.cc24
-rw-r--r--src/client/linux/minidump_writer/minidump_writer_unittest_utils.cc7
-rw-r--r--src/client/linux/minidump_writer/minidump_writer_unittest_utils.h5
-rw-r--r--src/client/linux/minidump_writer/pe_file.cc147
-rw-r--r--src/client/linux/minidump_writer/pe_file.h76
-rw-r--r--src/client/linux/minidump_writer/pe_structs.h225
-rw-r--r--src/client/linux/minidump_writer/proc_cpuinfo_reader.h5
-rw-r--r--src/client/linux/minidump_writer/proc_cpuinfo_reader_unittest.cc11
-rw-r--r--src/client/linux/sender/google_crash_report_sender.cc7
-rw-r--r--src/client/mac/Breakpad.xcodeproj/project.pbxproj60
-rw-r--r--src/client/mac/Framework/Breakpad.h27
-rw-r--r--src/client/mac/Framework/Breakpad.mm209
-rw-r--r--src/client/mac/Framework/OnDemandServer.h17
-rw-r--r--src/client/mac/Framework/OnDemandServer.mm28
-rw-r--r--src/client/mac/crash_generation/ConfigFile.h27
-rw-r--r--src/client/mac/crash_generation/ConfigFile.mm40
-rw-r--r--src/client/mac/crash_generation/Inspector.h19
-rw-r--r--src/client/mac/crash_generation/Inspector.mm35
-rw-r--r--src/client/mac/crash_generation/InspectorMain.mm5
-rw-r--r--src/client/mac/crash_generation/client_info.h5
-rw-r--r--src/client/mac/crash_generation/crash_generation_client.cc5
-rw-r--r--src/client/mac/crash_generation/crash_generation_client.h5
-rw-r--r--src/client/mac/crash_generation/crash_generation_server.cc21
-rw-r--r--src/client/mac/crash_generation/crash_generation_server.h37
-rw-r--r--src/client/mac/handler/breakpad_nlist_64.cc77
-rw-r--r--src/client/mac/handler/breakpad_nlist_64.h17
-rw-r--r--src/client/mac/handler/dynamic_images.cc49
-rw-r--r--src/client/mac/handler/dynamic_images.h32
-rw-r--r--src/client/mac/handler/exception_handler.cc11
-rw-r--r--src/client/mac/handler/exception_handler.h67
-rw-r--r--src/client/mac/handler/mach_vm_compat.h5
-rw-r--r--src/client/mac/handler/minidump_generator.cc193
-rw-r--r--src/client/mac/handler/minidump_generator.h75
-rw-r--r--src/client/mac/handler/protected_memory_allocator.cc5
-rw-r--r--src/client/mac/handler/protected_memory_allocator.h5
-rw-r--r--src/client/mac/handler/testcases/DynamicImagesTests.cc13
-rw-r--r--src/client/mac/handler/testcases/DynamicImagesTests.h7
-rw-r--r--src/client/mac/handler/testcases/breakpad_nlist_test.cc19
-rw-r--r--src/client/mac/handler/testcases/breakpad_nlist_test.h9
-rw-r--r--src/client/mac/handler/testcases/dwarftests.h7
-rw-r--r--src/client/mac/handler/testcases/dwarftests.mm7
-rw-r--r--src/client/mac/handler/ucontext_compat.h5
-rw-r--r--src/client/mac/sender/crash_report_sender.h5
-rw-r--r--src/client/mac/sender/crash_report_sender.m5
-rw-r--r--src/client/mac/sender/uploader.h5
-rw-r--r--src/client/mac/sender/uploader.mm5
-rw-r--r--src/client/mac/testapp/Controller.h5
-rw-r--r--src/client/mac/testapp/Controller.m5
-rw-r--r--src/client/mac/testapp/TestClass.h5
-rw-r--r--src/client/mac/testapp/TestClass.mm5
-rw-r--r--src/client/mac/testapp/main.m7
-rw-r--r--src/client/mac/tests/BreakpadFramework_Test.mm5
-rw-r--r--src/client/mac/tests/crash_generation_server_test.cc13
-rw-r--r--src/client/mac/tests/exception_handler_test.cc19
-rw-r--r--src/client/mac/tests/minidump_generator_test.cc7
-rw-r--r--src/client/mac/tests/minidump_generator_test_helper.cc5
-rw-r--r--src/client/mac/tests/spawn_child_process.h5
-rw-r--r--src/client/minidump_file_writer-inl.h9
-rw-r--r--src/client/minidump_file_writer.cc35
-rw-r--r--src/client/minidump_file_writer.h47
-rw-r--r--src/client/minidump_file_writer_unittest.cc22
-rw-r--r--src/client/solaris/handler/Makefile5
-rw-r--r--src/client/solaris/handler/exception_handler.cc27
-rw-r--r--src/client/solaris/handler/exception_handler.h37
-rw-r--r--src/client/solaris/handler/exception_handler_test.cc19
-rw-r--r--src/client/solaris/handler/minidump_generator.cc182
-rw-r--r--src/client/solaris/handler/minidump_generator.h13
-rw-r--r--src/client/solaris/handler/minidump_test.cc7
-rw-r--r--src/client/solaris/handler/solaris_lwp.cc77
-rw-r--r--src/client/solaris/handler/solaris_lwp.h21
-rw-r--r--src/client/windows/breakpad_client.gyp66
-rw-r--r--src/client/windows/common/auto_critical_section.h5
-rw-r--r--src/client/windows/common/ipc_protocol.h5
-rw-r--r--src/client/windows/crash_generation/client_info.cc5
-rw-r--r--src/client/windows/crash_generation/client_info.h5
-rw-r--r--src/client/windows/crash_generation/crash_generation.gyp63
-rw-r--r--src/client/windows/crash_generation/crash_generation_client.cc5
-rw-r--r--src/client/windows/crash_generation/crash_generation_client.h5
-rw-r--r--src/client/windows/crash_generation/crash_generation_server.cc5
-rw-r--r--src/client/windows/crash_generation/crash_generation_server.h5
-rw-r--r--src/client/windows/crash_generation/minidump_generator.cc9
-rw-r--r--src/client/windows/crash_generation/minidump_generator.h5
-rw-r--r--src/client/windows/handler/exception_handler.cc11
-rw-r--r--src/client/windows/handler/exception_handler.gyp47
-rw-r--r--src/client/windows/handler/exception_handler.h13
-rw-r--r--src/client/windows/sender/crash_report_sender.cc19
-rw-r--r--src/client/windows/sender/crash_report_sender.gyp46
-rw-r--r--src/client/windows/sender/crash_report_sender.h23
-rw-r--r--src/client/windows/tests/crash_generation_app/abstract_class.cc5
-rw-r--r--src/client/windows/tests/crash_generation_app/abstract_class.h5
-rw-r--r--src/client/windows/tests/crash_generation_app/crash_generation_app.cc5
-rw-r--r--src/client/windows/tests/crash_generation_app/crash_generation_app.gyp63
-rw-r--r--src/client/windows/tests/crash_generation_app/crash_generation_app.h5
-rw-r--r--src/client/windows/tests/crash_generation_app/resource.h5
-rw-r--r--src/client/windows/unittests/client_tests.gyp81
-rw-r--r--src/client/windows/unittests/crash_generation_server_test.cc5
-rw-r--r--src/client/windows/unittests/dump_analysis.cc9
-rw-r--r--src/client/windows/unittests/dump_analysis.h5
-rw-r--r--src/client/windows/unittests/exception_handler_death_test.cc23
-rw-r--r--src/client/windows/unittests/exception_handler_nesting_test.cc11
-rw-r--r--src/client/windows/unittests/exception_handler_test.cc25
-rw-r--r--src/client/windows/unittests/exception_handler_test.h5
-rw-r--r--src/client/windows/unittests/minidump_test.cc5
-rw-r--r--src/client/windows/unittests/testing.gyp90
-rw-r--r--src/common/android/include/elf.h5
-rw-r--r--src/common/android/include/link.h5
-rw-r--r--src/common/android/include/stab.h5
-rw-r--r--src/common/android/include/sys/procfs.h5
-rw-r--r--src/common/android/include/sys/user.h5
-rw-r--r--src/common/android/testing/include/wchar.h5
-rw-r--r--src/common/android/testing/mkdtemp.h5
-rw-r--r--src/common/android/testing/pthread_fixes.h7
-rw-r--r--src/common/basictypes.h5
-rw-r--r--src/common/byte_cursor.h54
-rw-r--r--src/common/byte_cursor_unittest.cc17
-rw-r--r--src/common/common.gyp260
-rw-r--r--src/common/dwarf/bytereader-inl.h37
-rw-r--r--src/common/dwarf/bytereader.cc16
-rw-r--r--src/common/dwarf/bytereader.h41
-rw-r--r--src/common/dwarf/bytereader_unittest.cc515
-rw-r--r--src/common/dwarf/cfi_assembler.cc59
-rw-r--r--src/common/dwarf/cfi_assembler.h55
-rw-r--r--src/common/dwarf/dwarf2diehandler.cc30
-rw-r--r--src/common/dwarf/dwarf2diehandler.h31
-rw-r--r--src/common/dwarf/dwarf2diehandler_unittest.cc26
-rw-r--r--src/common/dwarf/dwarf2enums.h73
-rw-r--r--src/common/dwarf/dwarf2reader.cc1211
-rw-r--r--src/common/dwarf/dwarf2reader.h294
-rw-r--r--src/common/dwarf/dwarf2reader_cfi_unittest.cc494
-rw-r--r--src/common/dwarf/dwarf2reader_die_unittest.cc678
-rw-r--r--src/common/dwarf/dwarf2reader_lineinfo_unittest.cc186
-rw-r--r--src/common/dwarf/dwarf2reader_splitfunctions_unittest.cc125
-rw-r--r--src/common/dwarf/dwarf2reader_test_common.h54
-rw-r--r--src/common/dwarf/elf_reader.cc198
-rw-r--r--src/common/dwarf/elf_reader.h44
-rw-r--r--src/common/dwarf/functioninfo.cc27
-rw-r--r--src/common/dwarf/functioninfo.h8
-rw-r--r--src/common/dwarf/line_state_machine.h10
-rw-r--r--src/common/dwarf/types.h4
-rw-r--r--src/common/dwarf_cfi_to_module.cc34
-rw-r--r--src/common/dwarf_cfi_to_module.h43
-rw-r--r--src/common/dwarf_cfi_to_module_unittest.cc13
-rw-r--r--src/common/dwarf_cu_to_module.cc865
-rw-r--r--src/common/dwarf_cu_to_module.h92
-rw-r--r--src/common/dwarf_cu_to_module_unittest.cc569
-rw-r--r--src/common/dwarf_line_to_module.cc21
-rw-r--r--src/common/dwarf_line_to_module.h30
-rw-r--r--src/common/dwarf_line_to_module_unittest.cc70
-rw-r--r--src/common/dwarf_range_list_handler.cc13
-rw-r--r--src/common/dwarf_range_list_handler.h20
-rw-r--r--src/common/language.cc62
-rw-r--r--src/common/language.h9
-rw-r--r--src/common/linux/breakpad_getcontext.S171
-rw-r--r--src/common/linux/breakpad_getcontext.h5
-rw-r--r--src/common/linux/breakpad_getcontext_unittest.cc24
-rw-r--r--src/common/linux/crc32.cc5
-rw-r--r--src/common/linux/crc32.h5
-rw-r--r--src/common/linux/dump_symbols.cc328
-rw-r--r--src/common/linux/dump_symbols.h24
-rw-r--r--src/common/linux/dump_symbols_unittest.cc11
-rw-r--r--src/common/linux/eintr_wrapper.h5
-rw-r--r--src/common/linux/elf_core_dump.cc33
-rw-r--r--src/common/linux/elf_core_dump.h13
-rw-r--r--src/common/linux/elf_core_dump_unittest.cc15
-rw-r--r--src/common/linux/elf_gnu_compat.h5
-rw-r--r--src/common/linux/elf_symbols_to_module.cc29
-rw-r--r--src/common/linux/elf_symbols_to_module.h10
-rw-r--r--src/common/linux/elf_symbols_to_module_unittest.cc19
-rw-r--r--src/common/linux/elfutils-inl.h5
-rw-r--r--src/common/linux/elfutils.cc33
-rw-r--r--src/common/linux/elfutils.h48
-rw-r--r--src/common/linux/file_id.cc13
-rw-r--r--src/common/linux/file_id.h7
-rw-r--r--src/common/linux/file_id_unittest.cc34
-rw-r--r--src/common/linux/google_crashdump_uploader.cc41
-rw-r--r--src/common/linux/google_crashdump_uploader.h15
-rw-r--r--src/common/linux/google_crashdump_uploader_test.cc77
-rw-r--r--src/common/linux/guid_creator.cc13
-rw-r--r--src/common/linux/guid_creator.h5
-rw-r--r--src/common/linux/http_upload.cc61
-rw-r--r--src/common/linux/http_upload.h29
-rw-r--r--src/common/linux/ignore_ret.h5
-rw-r--r--src/common/linux/libcurl_wrapper.cc20
-rw-r--r--src/common/linux/libcurl_wrapper.h35
-rw-r--r--src/common/linux/linux_libc_support.cc7
-rw-r--r--src/common/linux/linux_libc_support.h5
-rw-r--r--src/common/linux/linux_libc_support_unittest.cc5
-rw-r--r--src/common/linux/memory_mapped_file.cc13
-rw-r--r--src/common/linux/memory_mapped_file.h5
-rw-r--r--src/common/linux/memory_mapped_file_unittest.cc5
-rw-r--r--src/common/linux/safe_readlink.cc5
-rw-r--r--src/common/linux/safe_readlink.h5
-rw-r--r--src/common/linux/safe_readlink_unittest.cc5
-rw-r--r--src/common/linux/symbol_collector_client.cc5
-rw-r--r--src/common/linux/symbol_collector_client.h5
-rw-r--r--src/common/linux/symbol_upload.cc15
-rw-r--r--src/common/linux/symbol_upload.h5
-rw-r--r--src/common/linux/synth_elf.cc4
-rw-r--r--src/common/linux/synth_elf.h9
-rw-r--r--src/common/linux/synth_elf_unittest.cc9
-rw-r--r--src/common/linux/tests/auto_testfile.h5
-rw-r--r--src/common/linux/tests/crash_generator.cc16
-rw-r--r--src/common/linux/tests/crash_generator.h9
-rw-r--r--src/common/linux/ucontext_constants.h106
-rw-r--r--src/common/long_string_dictionary.cc5
-rw-r--r--src/common/long_string_dictionary.h5
-rw-r--r--src/common/long_string_dictionary_unittest.cc5
-rw-r--r--src/common/mac/Breakpad.xcconfig5
-rw-r--r--src/common/mac/BreakpadDebug.xcconfig5
-rw-r--r--src/common/mac/BreakpadRelease.xcconfig5
-rw-r--r--src/common/mac/GTMDefines.h2
-rw-r--r--src/common/mac/GTMLogger.h2
-rw-r--r--src/common/mac/GTMLogger.m2
-rw-r--r--src/common/mac/HTTPGetRequest.h41
-rw-r--r--src/common/mac/HTTPGetRequest.m38
-rw-r--r--src/common/mac/HTTPMultipartUpload.h57
-rw-r--r--src/common/mac/HTTPMultipartUpload.m204
-rw-r--r--src/common/mac/HTTPPutRequest.h50
-rw-r--r--src/common/mac/HTTPPutRequest.m55
-rw-r--r--src/common/mac/HTTPRequest.h72
-rw-r--r--src/common/mac/HTTPRequest.m267
-rw-r--r--src/common/mac/HTTPSimplePostRequest.h56
-rw-r--r--src/common/mac/HTTPSimplePostRequest.m68
-rw-r--r--src/common/mac/MachIPC.h25
-rw-r--r--src/common/mac/MachIPC.mm31
-rw-r--r--src/common/mac/SymbolCollectorClient.h103
-rw-r--r--src/common/mac/SymbolCollectorClient.m271
-rw-r--r--src/common/mac/arch_utilities.cc12
-rw-r--r--src/common/mac/arch_utilities.h5
-rw-r--r--src/common/mac/bootstrap_compat.cc5
-rw-r--r--src/common/mac/bootstrap_compat.h5
-rw-r--r--src/common/mac/byteswap.h5
-rw-r--r--src/common/mac/dump_syms.cc258
-rw-r--r--src/common/mac/dump_syms.h95
-rw-r--r--src/common/mac/encoding_util.h40
-rw-r--r--src/common/mac/encoding_util.m46
-rw-r--r--src/common/mac/file_id.cc52
-rw-r--r--src/common/mac/file_id.h30
-rw-r--r--src/common/mac/launch_reporter.cc5
-rw-r--r--src/common/mac/launch_reporter.h5
-rw-r--r--src/common/mac/macho_id.cc175
-rw-r--r--src/common/mac/macho_id.h51
-rw-r--r--src/common/mac/macho_reader.cc62
-rw-r--r--src/common/mac/macho_reader.h51
-rw-r--r--src/common/mac/macho_reader_unittest.cc136
-rw-r--r--src/common/mac/macho_utilities.cc5
-rw-r--r--src/common/mac/macho_utilities.h5
-rw-r--r--src/common/mac/macho_walker.cc25
-rw-r--r--src/common/mac/macho_walker.h31
-rw-r--r--src/common/mac/minidump_upload.m (renamed from src/tools/mac/symupload/minidump_upload.m)45
-rw-r--r--src/common/mac/scoped_task_suspend-inl.h5
-rw-r--r--src/common/mac/string_utilities.cc9
-rw-r--r--src/common/mac/string_utilities.h7
-rw-r--r--src/common/mac/super_fat_arch.h7
-rw-r--r--src/common/mac/testing/GTMSenTestCase.h2
-rw-r--r--src/common/mac/testing/GTMSenTestCase.m2
-rw-r--r--src/common/macros.h5
-rw-r--r--src/common/md5.cc14
-rw-r--r--src/common/md5.h3
-rw-r--r--src/common/memory_allocator.h36
-rw-r--r--src/common/memory_allocator_unittest.cc11
-rw-r--r--src/common/memory_range.h5
-rw-r--r--src/common/memory_range_unittest.cc5
-rw-r--r--src/common/minidump_type_helper.h5
-rw-r--r--src/common/module.cc260
-rw-r--r--src/common/module.h231
-rw-r--r--src/common/module_unittest.cc293
-rw-r--r--src/common/path_helper.cc5
-rw-r--r--src/common/path_helper.h5
-rw-r--r--src/common/safe_math.h81
-rw-r--r--src/common/safe_math_unittest.cc72
-rw-r--r--src/common/scoped_ptr.h4
-rw-r--r--src/common/simple_string_dictionary.cc5
-rw-r--r--src/common/simple_string_dictionary.h5
-rw-r--r--src/common/simple_string_dictionary_unittest.cc5
-rw-r--r--src/common/solaris/dump_symbols.cc156
-rw-r--r--src/common/solaris/dump_symbols.h7
-rw-r--r--src/common/solaris/file_id.cc50
-rw-r--r--src/common/solaris/file_id.h7
-rw-r--r--src/common/solaris/guid_creator.cc9
-rw-r--r--src/common/solaris/guid_creator.h5
-rw-r--r--src/common/solaris/message_output.h5
-rw-r--r--src/common/stabs_reader.cc30
-rw-r--r--src/common/stabs_reader.h40
-rw-r--r--src/common/stabs_reader_unittest.cc41
-rw-r--r--src/common/stabs_to_module.cc31
-rw-r--r--src/common/stabs_to_module.h11
-rw-r--r--src/common/stabs_to_module_unittest.cc26
-rw-r--r--src/common/stdio_wrapper.h5
-rw-r--r--src/common/string_conversion.cc63
-rw-r--r--src/common/string_conversion.h13
-rw-r--r--src/common/string_conversion_unittest.cc5
-rw-r--r--src/common/string_view.h113
-rw-r--r--src/common/symbol_data.h27
-rw-r--r--src/common/test_assembler.cc53
-rw-r--r--src/common/test_assembler.h75
-rw-r--r--src/common/test_assembler_unittest.cc13
-rw-r--r--src/common/tests/auto_tempdir.h5
-rw-r--r--src/common/tests/file_utils.cc9
-rw-r--r--src/common/tests/file_utils.h8
-rw-r--r--src/common/unordered.h13
-rw-r--r--src/common/using_std_string.h6
-rw-r--r--src/common/windows/common_windows.gyp112
-rw-r--r--src/common/windows/dia_util.cc182
-rw-r--r--src/common/windows/dia_util.h4
-rw-r--r--src/common/windows/guid_string.cc5
-rw-r--r--src/common/windows/guid_string.h5
-rw-r--r--src/common/windows/http_upload.cc62
-rw-r--r--src/common/windows/http_upload.h9
-rw-r--r--src/common/windows/module_info.h149
-rw-r--r--src/common/windows/omap.cc12
-rw-r--r--src/common/windows/omap.h4
-rw-r--r--src/common/windows/omap_internal.h4
-rw-r--r--src/common/windows/omap_unittest.cc658
-rw-r--r--src/common/windows/pdb_source_line_writer.cc528
-rw-r--r--src/common/windows/pdb_source_line_writer.h156
-rw-r--r--src/common/windows/pe_source_line_writer.cc153
-rw-r--r--src/common/windows/pe_source_line_writer.h135
-rw-r--r--src/common/windows/pe_util.cc818
-rw-r--r--src/common/windows/pe_util.h155
-rw-r--r--src/common/windows/string_utils-inl.h27
-rw-r--r--src/common/windows/string_utils.cc11
-rw-r--r--src/common/windows/sym_upload_v2_protocol.cc118
-rw-r--r--src/common/windows/sym_upload_v2_protocol.h66
-rw-r--r--src/common/windows/symbol_collector_client.cc34
-rw-r--r--src/common/windows/symbol_collector_client.h21
-rw-r--r--src/config.h.in29
-rw-r--r--src/google_breakpad/common/breakpad_types.h5
-rw-r--r--src/google_breakpad/common/minidump_cpu_amd64.h5
-rw-r--r--src/google_breakpad/common/minidump_cpu_arm.h5
-rw-r--r--src/google_breakpad/common/minidump_cpu_arm64.h5
-rw-r--r--src/google_breakpad/common/minidump_cpu_mips.h5
-rw-r--r--src/google_breakpad/common/minidump_cpu_ppc.h5
-rw-r--r--src/google_breakpad/common/minidump_cpu_ppc64.h5
-rw-r--r--src/google_breakpad/common/minidump_cpu_riscv.h168
-rw-r--r--src/google_breakpad/common/minidump_cpu_sparc.h5
-rw-r--r--src/google_breakpad/common/minidump_cpu_x86.h5
-rw-r--r--src/google_breakpad/common/minidump_exception_fuchsia.h5
-rw-r--r--src/google_breakpad/common/minidump_exception_linux.h5
-rw-r--r--src/google_breakpad/common/minidump_exception_mac.h13
-rw-r--r--src/google_breakpad/common/minidump_exception_ps3.h5
-rw-r--r--src/google_breakpad/common/minidump_exception_solaris.h5
-rw-r--r--src/google_breakpad/common/minidump_exception_win32.h78
-rw-r--r--src/google_breakpad/common/minidump_format.h49
-rw-r--r--src/google_breakpad/common/minidump_size.h5
-rw-r--r--src/google_breakpad/processor/basic_source_line_resolver.h81
-rw-r--r--src/google_breakpad/processor/call_stack.h5
-rw-r--r--src/google_breakpad/processor/code_module.h5
-rw-r--r--src/google_breakpad/processor/code_modules.h5
-rw-r--r--src/google_breakpad/processor/dump_context.h45
-rw-r--r--src/google_breakpad/processor/dump_object.h5
-rw-r--r--src/google_breakpad/processor/exception_record.h5
-rw-r--r--src/google_breakpad/processor/exploitability.h5
-rw-r--r--src/google_breakpad/processor/fast_source_line_resolver.h7
-rw-r--r--src/google_breakpad/processor/memory_region.h5
-rw-r--r--src/google_breakpad/processor/microdump.h5
-rw-r--r--src/google_breakpad/processor/microdump_processor.h5
-rw-r--r--src/google_breakpad/processor/minidump.h142
-rw-r--r--src/google_breakpad/processor/minidump_processor.h13
-rw-r--r--src/google_breakpad/processor/proc_maps_linux.h2
-rw-r--r--src/google_breakpad/processor/process_result.h11
-rw-r--r--src/google_breakpad/processor/process_state.h12
-rw-r--r--src/google_breakpad/processor/source_line_resolver_base.h50
-rw-r--r--src/google_breakpad/processor/source_line_resolver_interface.h38
-rw-r--r--src/google_breakpad/processor/stack_frame.h30
-rw-r--r--src/google_breakpad/processor/stack_frame_cpu.h122
-rw-r--r--src/google_breakpad/processor/stack_frame_symbolizer.h11
-rw-r--r--src/google_breakpad/processor/stackwalker.h13
-rw-r--r--src/google_breakpad/processor/symbol_supplier.h33
-rw-r--r--src/google_breakpad/processor/system_info.h5
-rw-r--r--src/processor/address_map-inl.h13
-rw-r--r--src/processor/address_map.h11
-rw-r--r--src/processor/address_map_unittest.cc7
-rw-r--r--src/processor/basic_code_module.h19
-rw-r--r--src/processor/basic_code_modules.cc5
-rw-r--r--src/processor/basic_code_modules.h9
-rw-r--r--src/processor/basic_source_line_resolver.cc377
-rw-r--r--src/processor/basic_source_line_resolver_types.h78
-rw-r--r--src/processor/basic_source_line_resolver_unittest.cc339
-rw-r--r--src/processor/call_stack.cc7
-rw-r--r--src/processor/cfi_frame_info-inl.h19
-rw-r--r--src/processor/cfi_frame_info.cc39
-rw-r--r--src/processor/cfi_frame_info.h57
-rw-r--r--src/processor/cfi_frame_info_unittest.cc38
-rw-r--r--src/processor/contained_range_map-inl.h39
-rw-r--r--src/processor/contained_range_map.h43
-rw-r--r--src/processor/contained_range_map_unittest.cc194
-rw-r--r--src/processor/convert_old_arm64_context.cc5
-rw-r--r--src/processor/convert_old_arm64_context.h5
-rw-r--r--src/processor/disassembler_objdump.cc520
-rw-r--r--src/processor/disassembler_objdump.h142
-rw-r--r--src/processor/disassembler_objdump_unittest.cc464
-rw-r--r--src/processor/disassembler_x86.cc23
-rw-r--r--src/processor/disassembler_x86.h8
-rw-r--r--src/processor/disassembler_x86_unittest.cc7
-rw-r--r--src/processor/dump_context.cc240
-rw-r--r--src/processor/dump_object.cc5
-rw-r--r--src/processor/exploitability.cc5
-rw-r--r--src/processor/exploitability_linux.cc402
-rw-r--r--src/processor/exploitability_linux.h50
-rw-r--r--src/processor/exploitability_unittest.cc152
-rw-r--r--src/processor/exploitability_win.cc22
-rw-r--r--src/processor/exploitability_win.h5
-rw-r--r--src/processor/fast_source_line_resolver.cc131
-rw-r--r--src/processor/fast_source_line_resolver_types.h138
-rw-r--r--src/processor/fast_source_line_resolver_unittest.cc159
-rw-r--r--src/processor/linked_ptr.h5
-rw-r--r--src/processor/logging.cc13
-rw-r--r--src/processor/logging.h33
-rw-r--r--src/processor/map_serializers-inl.h59
-rw-r--r--src/processor/map_serializers.h31
-rw-r--r--src/processor/map_serializers_unittest.cc15
-rw-r--r--src/processor/microdump.cc5
-rw-r--r--src/processor/microdump_processor.cc5
-rw-r--r--src/processor/microdump_processor_unittest.cc5
-rw-r--r--src/processor/microdump_stackwalk.cc12
-rwxr-xr-xsrc/processor/microdump_stackwalk_machine_readable_test5
-rwxr-xr-xsrc/processor/microdump_stackwalk_test5
-rw-r--r--src/processor/minidump.cc671
-rw-r--r--src/processor/minidump_dump.cc18
-rwxr-xr-xsrc/processor/minidump_dump_test5
-rw-r--r--src/processor/minidump_processor.cc430
-rw-r--r--src/processor/minidump_processor_unittest.cc143
-rw-r--r--src/processor/minidump_stackwalk.cc18
-rwxr-xr-xsrc/processor/minidump_stackwalk_machine_readable_test5
-rwxr-xr-xsrc/processor/minidump_stackwalk_test5
-rw-r--r--src/processor/minidump_unittest.cc160
-rw-r--r--src/processor/module_comparer.cc9
-rw-r--r--src/processor/module_comparer.h7
-rw-r--r--src/processor/module_factory.h11
-rw-r--r--src/processor/module_serializer.cc51
-rw-r--r--src/processor/module_serializer.h33
-rw-r--r--src/processor/pathname_stripper.cc7
-rw-r--r--src/processor/pathname_stripper.h7
-rw-r--r--src/processor/pathname_stripper_unittest.cc7
-rw-r--r--src/processor/postfix_evaluator-inl.h37
-rw-r--r--src/processor/postfix_evaluator.h35
-rw-r--r--src/processor/postfix_evaluator_unittest.cc29
-rw-r--r--src/processor/proc_maps_linux.cc2
-rw-r--r--src/processor/proc_maps_linux_unittest.cc2
-rw-r--r--src/processor/process_state.cc8
-rw-r--r--src/processor/processor.gyp187
-rw-r--r--src/processor/processor_tools.gypi57
-rw-r--r--src/processor/proto/process_state.proto5
-rw-r--r--src/processor/range_map-inl.h39
-rw-r--r--src/processor/range_map.h35
-rw-r--r--src/processor/range_map_truncate_lower_unittest.cc7
-rw-r--r--src/processor/range_map_truncate_upper_unittest.cc7
-rw-r--r--src/processor/range_map_unittest.cc36
-rw-r--r--src/processor/simple_serializer-inl.h173
-rw-r--r--src/processor/simple_serializer.h11
-rw-r--r--src/processor/simple_symbol_supplier.cc37
-rw-r--r--src/processor/simple_symbol_supplier.h45
-rw-r--r--src/processor/source_line_resolver_base.cc70
-rw-r--r--src/processor/source_line_resolver_base_types.h68
-rw-r--r--src/processor/stack_frame_cpu.cc5
-rw-r--r--src/processor/stack_frame_symbolizer.cc12
-rw-r--r--src/processor/stackwalk_common.cc1088
-rw-r--r--src/processor/stackwalk_common.h6
-rw-r--r--src/processor/stackwalker.cc33
-rw-r--r--src/processor/stackwalker_address_list.cc5
-rw-r--r--src/processor/stackwalker_address_list.h5
-rw-r--r--src/processor/stackwalker_address_list_unittest.cc10
-rw-r--r--src/processor/stackwalker_amd64.cc70
-rw-r--r--src/processor/stackwalker_amd64.h14
-rw-r--r--src/processor/stackwalker_amd64_unittest.cc51
-rw-r--r--src/processor/stackwalker_arm.cc19
-rw-r--r--src/processor/stackwalker_arm.h11
-rw-r--r--src/processor/stackwalker_arm64.cc21
-rw-r--r--src/processor/stackwalker_arm64.h11
-rw-r--r--src/processor/stackwalker_arm64_unittest.cc41
-rw-r--r--src/processor/stackwalker_arm_unittest.cc49
-rw-r--r--src/processor/stackwalker_mips.cc8
-rw-r--r--src/processor/stackwalker_mips.h5
-rw-r--r--src/processor/stackwalker_mips64_unittest.cc12
-rw-r--r--src/processor/stackwalker_mips_unittest.cc6
-rw-r--r--src/processor/stackwalker_ppc.cc12
-rw-r--r--src/processor/stackwalker_ppc.h5
-rw-r--r--src/processor/stackwalker_ppc64.cc12
-rw-r--r--src/processor/stackwalker_ppc64.h5
-rw-r--r--src/processor/stackwalker_riscv.cc535
-rw-r--r--src/processor/stackwalker_riscv.h100
-rw-r--r--src/processor/stackwalker_riscv64.cc535
-rw-r--r--src/processor/stackwalker_riscv64.h100
-rw-r--r--src/processor/stackwalker_riscv64_unittest.cc883
-rw-r--r--src/processor/stackwalker_riscv_unittest.cc883
-rw-r--r--src/processor/stackwalker_selftest.cc7
-rw-r--r--src/processor/stackwalker_selftest_sol.s5
-rw-r--r--src/processor/stackwalker_sparc.cc12
-rw-r--r--src/processor/stackwalker_sparc.h5
-rw-r--r--src/processor/stackwalker_unittest_utils.h69
-rw-r--r--src/processor/stackwalker_x86.cc62
-rw-r--r--src/processor/stackwalker_x86.h11
-rw-r--r--src/processor/stackwalker_x86_unittest.cc109
-rw-r--r--src/processor/static_address_map-inl.h9
-rw-r--r--src/processor/static_address_map.h11
-rw-r--r--src/processor/static_address_map_unittest.cc13
-rw-r--r--src/processor/static_contained_range_map-inl.h26
-rw-r--r--src/processor/static_contained_range_map.h13
-rw-r--r--src/processor/static_contained_range_map_unittest.cc24
-rw-r--r--src/processor/static_map-inl.h10
-rw-r--r--src/processor/static_map.h12
-rw-r--r--src/processor/static_map_iterator-inl.h6
-rw-r--r--src/processor/static_map_iterator.h6
-rw-r--r--src/processor/static_map_unittest.cc13
-rw-r--r--src/processor/static_range_map-inl.h23
-rw-r--r--src/processor/static_range_map.h19
-rw-r--r--src/processor/static_range_map_unittest.cc15
-rw-r--r--src/processor/symbolic_constants_win.cc5
-rw-r--r--src/processor/symbolic_constants_win.h5
-rw-r--r--src/processor/synth_minidump.cc61
-rw-r--r--src/processor/synth_minidump.h93
-rw-r--r--src/processor/synth_minidump_unittest.cc5
-rw-r--r--src/processor/testdata/linux_inline.dmpbin0 -> 21456 bytes
-rw-r--r--src/processor/testdata/linux_test_app.cc13
-rw-r--r--src/processor/testdata/minidump2.dump.out4
-rw-r--r--src/processor/testdata/minidump_crashpad_annotation.dmpbin0 -> 332000 bytes
-rw-r--r--src/processor/testdata/module1.out4
-rw-r--r--src/processor/testdata/symbols/linux_inline/BBA6FA10B8AAB33D00000000000000000/linux_inline.new.sym71
-rw-r--r--src/processor/testdata/symbols/linux_inline/BBA6FA10B8AAB33D00000000000000000/linux_inline.old.sym68
-rw-r--r--src/processor/testdata/test_app.cc15
-rw-r--r--src/processor/testdata/thread_name_list.dmpbin0 -> 18011 bytes
-rw-r--r--src/processor/testdata/tiny-exe-fastfail.dmpbin0 -> 98722 bytes
-rw-r--r--src/processor/testdata/tiny-exe-with-cet-xsave.dmpbin0 -> 92736 bytes
-rw-r--r--src/processor/testdata/write_av_non_canonical.dmpbin0 -> 27561 bytes
-rw-r--r--src/processor/tokenize.cc22
-rw-r--r--src/processor/tokenize.h13
-rw-r--r--src/processor/windows_frame_info.h13
-rw-r--r--src/third_party/curl/curlbuild.h3
-rw-r--r--src/third_party/libdisasm/libdisasm.gyp67
-rw-r--r--src/third_party/linux/include/gflags/gflags_completions.h5
-rw-r--r--src/third_party/lss/linux_syscall_support.h1102
-rw-r--r--src/tools/linux/core2md/core2md.cc9
-rw-r--r--src/tools/linux/core_handler/core_handler.cc147
-rw-r--r--src/tools/linux/dump_syms/dump_syms.cc30
-rw-r--r--src/tools/linux/md2core/minidump-2-core.cc120
-rw-r--r--src/tools/linux/md2core/minidump_memory_range.h5
-rw-r--r--src/tools/linux/md2core/minidump_memory_range_unittest.cc5
-rw-r--r--src/tools/linux/pid2md/pid2md.cc58
-rw-r--r--src/tools/linux/symupload/minidump_upload.cc14
-rw-r--r--src/tools/linux/symupload/sym_upload.cc25
-rw-r--r--src/tools/linux/tools_linux.gypi83
-rw-r--r--src/tools/mac/crash_report/crash_report.mm408
-rw-r--r--src/tools/mac/crash_report/crash_report.xcodeproj/project.pbxproj618
-rw-r--r--src/tools/mac/crash_report/on_demand_symbol_supplier.h111
-rw-r--r--src/tools/mac/crash_report/on_demand_symbol_supplier.mm314
-rw-r--r--src/tools/mac/dump_syms/dump_syms_tool.cc104
-rw-r--r--src/tools/mac/dump_syms/macho_dump.cc37
-rw-r--r--src/tools/mac/symupload/symupload.m204
-rw-r--r--src/tools/mac/symupload/symupload.mm474
-rw-r--r--src/tools/mac/symupload/symupload.xcodeproj/project.pbxproj230
-rw-r--r--src/tools/mac/tools_mac.gypi116
-rw-r--r--src/tools/mac/upload_system_symbols/arch_constants.h5
-rw-r--r--src/tools/mac/upload_system_symbols/arch_reader.go5
-rw-r--r--src/tools/mac/upload_system_symbols/go.mod3
-rw-r--r--src/tools/mac/upload_system_symbols/upload_system_symbols.go45
-rwxr-xr-xsrc/tools/python/deps-to-manifest.py9
-rw-r--r--src/tools/python/filter_syms.py5
-rw-r--r--src/tools/python/tests/filter_syms_unittest.py5
-rw-r--r--src/tools/solaris/dump_syms/Makefile5
-rw-r--r--src/tools/solaris/dump_syms/dump_syms.cc9
-rw-r--r--src/tools/solaris/dump_syms/run_regtest.sh5
-rw-r--r--src/tools/solaris/dump_syms/testdata/dump_syms_regtest.cc11
-rw-r--r--src/tools/tools.gyp38
-rw-r--r--src/tools/windows/converter/ms_symbol_server_converter.cc130
-rw-r--r--src/tools/windows/converter/ms_symbol_server_converter.gyp46
-rw-r--r--src/tools/windows/converter/ms_symbol_server_converter.h59
-rw-r--r--src/tools/windows/converter_exe/converter.cc1711
-rw-r--r--src/tools/windows/converter_exe/converter.gyp57
-rw-r--r--src/tools/windows/converter_exe/escaping.cc1514
-rw-r--r--src/tools/windows/converter_exe/escaping.h198
-rw-r--r--src/tools/windows/converter_exe/http_client.h192
-rw-r--r--src/tools/windows/converter_exe/http_download.cc652
-rw-r--r--src/tools/windows/converter_exe/http_download.h124
-rw-r--r--src/tools/windows/converter_exe/tokenizer.cc122
-rw-r--r--src/tools/windows/converter_exe/tokenizer.h102
-rw-r--r--src/tools/windows/converter_exe/winhttp_client.cc614
-rw-r--r--src/tools/windows/converter_exe/winhttp_client.h80
-rw-r--r--src/tools/windows/converter_exe/wininet_client.cc556
-rw-r--r--src/tools/windows/converter_exe/wininet_client.h80
-rw-r--r--src/tools/windows/dump_syms/dump_syms.cc63
-rw-r--r--src/tools/windows/dump_syms/dump_syms.gyp64
-rw-r--r--src/tools/windows/dump_syms/dump_syms_unittest.cc488
-rwxr-xr-xsrc/tools/windows/dump_syms/run_regtest.sh5
-rw-r--r--src/tools/windows/dump_syms/testdata/dump_syms_regtest.cc11
-rw-r--r--src/tools/windows/symupload/symupload.cc152
-rw-r--r--src/tools/windows/symupload/symupload.gyp50
-rw-r--r--src/tools/windows/tools_windows.gyp46
643 files changed, 27769 insertions, 17897 deletions
diff --git a/src/breakpad_googletest_includes.h b/src/breakpad_googletest_includes.h
index 19a3e980..4bc44a83 100644
--- a/src/breakpad_googletest_includes.h
+++ b/src/breakpad_googletest_includes.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2009, Google Inc.
-// All rights reserved.
+// Copyright 2009 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/build/all.gyp b/src/build/all.gyp
deleted file mode 100644
index 4b59d917..00000000
--- a/src/build/all.gyp
+++ /dev/null
@@ -1,41 +0,0 @@
-# Copyright 2014 Google Inc. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-# * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-# * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-{
- 'targets': [
- {
- 'target_name': 'All',
- 'type': 'none',
- 'dependencies': [
- '../common/common.gyp:*',
- '../processor/processor.gyp:*',
- '../tools/tools.gyp:*',
- ],
- },
- ],
-}
diff --git a/src/build/common.gypi b/src/build/common.gypi
deleted file mode 100644
index 29990c65..00000000
--- a/src/build/common.gypi
+++ /dev/null
@@ -1,1045 +0,0 @@
-# Copyright 2010 Google Inc. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-# * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-# * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-# IMPORTANT:
-# Please don't directly include this file if you are building via gyp_chromium,
-# since gyp_chromium is automatically forcing its inclusion.
-{
- 'variables': {
- # Variables expected to be overriden on the GYP command line (-D) or by
- # ~/.gyp/include.gypi.
-
- # Putting a variables dict inside another variables dict looks kind of
- # weird. This is necessary to get these variables defined for the conditions
- # within this variables dict that operate on these variables.
- 'variables': {
- 'variables': {
- # Compute the architecture that we're building on.
- 'conditions': [
- [ 'OS=="linux" or OS=="freebsd" or OS=="openbsd"', {
- # This handles the Linux platforms we generally deal with. Anything
- # else gets passed through, which probably won't work very well; such
- # hosts should pass an explicit target_arch to gyp.
- 'host_arch%':
- '<!(uname -m | sed -e "s/i.86/ia32/;s/x86_64/x64/;s/amd64/x64/;s/arm.*/arm/")',
- }, { # OS!="linux"
- 'host_arch%': 'ia32',
- }],
- ],
- },
-
- 'host_arch%': '<(host_arch)',
-
- # Default architecture we're building for is the architecture we're
- # building on.
- 'target_arch%': '<(host_arch)',
-
- # This variable tells WebCore.gyp and JavaScriptCore.gyp whether they are
- # are built under a chromium full build (1) or a webkit.org chromium
- # build (0).
- 'inside_chromium_build%': 1,
-
- # Set to 1 compile with -fPIC cflag on linux. This is a must for shared
- # libraries on linux x86-64 and arm.
- 'linux_fpic%': 0,
-
- # Python version.
- 'python_ver%': '2.5',
-
- # Determine ARM compilation flags.
- 'arm_version%': 7,
-
- # Set Neon compilation flags (only meaningful if arm_version==7).
- 'arm_neon%': 1,
-
- # The system root for cross-compiles. Default: none.
- 'sysroot%': '',
-
- # On Linux, we build with sse2 for Chromium builds.
- 'disable_sse2%': 0,
- },
-
- 'target_arch%': '<(target_arch)',
- 'host_arch%': '<(host_arch)',
- 'inside_chromium_build%': '<(inside_chromium_build)',
- 'linux_fpic%': '<(linux_fpic)',
- 'python_ver%': '<(python_ver)',
- 'arm_version%': '<(arm_version)',
- 'arm_neon%': '<(arm_neon)',
- 'sysroot%': '<(sysroot)',
- 'disable_sse2%': '<(disable_sse2)',
-
- # The release channel that this build targets. This is used to restrict
- # channel-specific build options, like which installer packages to create.
- # The default is 'all', which does no channel-specific filtering.
- 'channel%': 'all',
-
- # Override chromium_mac_pch and set it to 0 to suppress the use of
- # precompiled headers on the Mac. Prefix header injection may still be
- # used, but prefix headers will not be precompiled. This is useful when
- # using distcc to distribute a build to compile slaves that don't
- # share the same compiler executable as the system driving the compilation,
- # because precompiled headers rely on pointers into a specific compiler
- # executable's image. Setting this to 0 is needed to use an experimental
- # Linux-Mac cross compiler distcc farm.
- 'chromium_mac_pch%': 1,
-
- # Mac OS X SDK and deployment target support.
- # The SDK identifies the version of the system headers that will be used,
- # and corresponds to the MAC_OS_X_VERSION_MAX_ALLOWED compile-time macro.
- # "Maximum allowed" refers to the operating system version whose APIs are
- # available in the headers.
- # The deployment target identifies the minimum system version that the
- # built products are expected to function on. It corresponds to the
- # MAC_OS_X_VERSION_MIN_REQUIRED compile-time macro.
- # To ensure these macros are available, #include <AvailabilityMacros.h>.
- # Additional documentation on these macros is available at
- # http://developer.apple.com/mac/library/technotes/tn2002/tn2064.html#SECTION3
- # Chrome normally builds with the Mac OS X 10.5 SDK and sets the
- # deployment target to 10.5. Other projects, such as O3D, may override
- # these defaults.
- 'mac_sdk%': '10.5',
- 'mac_deployment_target%': '10.5',
-
- # Set to 1 to enable code coverage. In addition to build changes
- # (e.g. extra CFLAGS), also creates a new target in the src/chrome
- # project file called "coverage".
- # Currently ignored on Windows.
- 'coverage%': 0,
-
- # Although base/allocator lets you select a heap library via an
- # environment variable, the libcmt shim it uses sometimes gets in
- # the way. To disable it entirely, and switch to normal msvcrt, do e.g.
- # 'win_use_allocator_shim': 0,
- # 'win_release_RuntimeLibrary': 2
- # to ~/.gyp/include.gypi, gclient runhooks --force, and do a release build.
- 'win_use_allocator_shim%': 1, # 0 = shim allocator via libcmt; 1 = msvcrt
-
- # Whether usage of OpenMAX is enabled.
- 'enable_openmax%': 0,
-
- # TODO(bradnelson): eliminate this when possible.
- # To allow local gyp files to prevent release.vsprops from being included.
- # Yes(1) means include release.vsprops.
- # Once all vsprops settings are migrated into gyp, this can go away.
- 'msvs_use_common_release%': 1,
-
- # TODO(bradnelson): eliminate this when possible.
- # To allow local gyp files to override additional linker options for msvs.
- # Yes(1) means set use the common linker options.
- 'msvs_use_common_linker_extras%': 1,
-
- # TODO(sgk): eliminate this if possible.
- # It would be nicer to support this via a setting in 'target_defaults'
- # in chrome/app/locales/locales.gypi overriding the setting in the
- # 'Debug' configuration in the 'target_defaults' dict below,
- # but that doesn't work as we'd like.
- 'msvs_debug_link_incremental%': '2',
-
- # This is the location of the sandbox binary. Chrome looks for this before
- # running the zygote process. If found, and SUID, it will be used to
- # sandbox the zygote process and, thus, all renderer processes.
- 'linux_sandbox_path%': '',
-
- # Set this to true to enable SELinux support.
- 'selinux%': 0,
-
- # Strip the binary after dumping symbols.
- 'linux_strip_binary%': 0,
-
- # Enable TCMalloc.
- 'linux_use_tcmalloc%': 1,
-
- # Disable TCMalloc's debugallocation.
- 'linux_use_debugallocation%': 0,
-
- # Disable TCMalloc's heapchecker.
- 'linux_use_heapchecker%': 0,
-
- # Set to 1 to turn on seccomp sandbox by default.
- # (Note: this is ignored for official builds.)
- 'linux_use_seccomp_sandbox%': 0,
-
- # Set to select the Title Case versions of strings in GRD files.
- 'use_titlecase_in_grd%': 0,
-
- # Used to disable Native Client at compile time, for platforms where it
- # isn't supported
- 'disable_nacl%': 0,
-
- # Set Thumb compilation flags.
- 'arm_thumb%': 0,
-
- # Set ARM fpu compilation flags (only meaningful if arm_version==7 and
- # arm_neon==0).
- 'arm_fpu%': 'vfpv3',
-
- # Enable new NPDevice API.
- 'enable_new_npdevice_api%': 0,
-
- 'conditions': [
- # Whether to use multiple cores to compile with visual studio. This is
- # optional because it sometimes causes corruption on VS 2005.
- # It is on by default on VS 2008 and off on VS 2005.
- ['OS=="win"', {
- 'conditions': [
- ['MSVS_VERSION=="2005"', {
- 'msvs_multi_core_compile%': 0,
- },{
- 'msvs_multi_core_compile%': 1,
- }],
- # Don't do incremental linking for large modules on 32-bit.
- ['MSVS_OS_BITS==32', {
- 'msvs_large_module_debug_link_mode%': '1', # No
- },{
- 'msvs_large_module_debug_link_mode%': '2', # Yes
- }],
- ],
- 'nacl_win64_defines': [
- # This flag is used to minimize dependencies when building
- # Native Client loader for 64-bit Windows.
- 'NACL_WIN64',
- ],
- }],
- ],
-
- # NOTE: When these end up in the Mac bundle, we need to replace '-' for '_'
- # so Cocoa is happy (http://crbug.com/20441).
- 'locales': [
- 'am', 'ar', 'bg', 'bn', 'ca', 'cs', 'da', 'de', 'el', 'en-GB',
- 'en-US', 'es-419', 'es', 'et', 'fi', 'fil', 'fr', 'gu', 'he',
- 'hi', 'hr', 'hu', 'id', 'it', 'ja', 'kn', 'ko', 'lt', 'lv',
- 'ml', 'mr', 'nb', 'nl', 'pl', 'pt-BR', 'pt-PT', 'ro', 'ru',
- 'sk', 'sl', 'sr', 'sv', 'sw', 'ta', 'te', 'th', 'tr', 'uk',
- 'vi', 'zh-CN', 'zh-TW',
- ],
- },
- 'target_defaults': {
- 'includes': [
- 'filename_rules.gypi',
- ],
- 'variables': {
- # See http://gcc.gnu.org/onlinedocs/gcc-4.4.2/gcc/Optimize-Options.html
- 'mac_release_optimization%': '3', # Use -O3 unless overridden
- 'mac_debug_optimization%': '0', # Use -O0 unless overridden
- # See http://msdn.microsoft.com/en-us/library/aa652360(VS.71).aspx
- 'win_release_Optimization%': '2', # 2 = /Os
- 'win_debug_Optimization%': '0', # 0 = /Od
- # See http://msdn.microsoft.com/en-us/library/aa652367(VS.71).aspx
- 'win_release_RuntimeLibrary%': '0', # 0 = /MT (nondebug static)
- 'win_debug_RuntimeLibrary%': '1', # 1 = /MTd (debug static)
-
- 'release_extra_cflags%': '',
- 'debug_extra_cflags%': '',
- 'release_valgrind_build%': 0,
- },
- 'conditions': [
- ['selinux==1', {
- 'defines': ['CHROMIUM_SELINUX=1'],
- }],
- ['win_use_allocator_shim==0', {
- 'conditions': [
- ['OS=="win"', {
- 'defines': ['NO_TCMALLOC'],
- }],
- ],
- }],
- ['coverage!=0', {
- 'conditions': [
- ['OS=="mac"', {
- 'xcode_settings': {
- 'GCC_INSTRUMENT_PROGRAM_FLOW_ARCS': 'YES', # -fprofile-arcs
- 'GCC_GENERATE_TEST_COVERAGE_FILES': 'YES', # -ftest-coverage
- },
- # Add -lgcov for types executable, shared_library, and
- # loadable_module; not for static_library.
- # This is a delayed conditional.
- 'target_conditions': [
- ['_type!="static_library"', {
- 'xcode_settings': { 'OTHER_LDFLAGS': [ '-lgcov' ] },
- }],
- ],
- }],
- # Linux gyp (into scons) doesn't like target_conditions?
- # TODO(???): track down why 'target_conditions' doesn't work
- # on Linux gyp into scons like it does on Mac gyp into xcodeproj.
- ['OS=="linux"', {
- 'cflags': [ '-ftest-coverage',
- '-fprofile-arcs' ],
- 'link_settings': { 'libraries': [ '-lgcov' ] },
- }],
- # Finally, for Windows, we simply turn on profiling.
- ['OS=="win"', {
- 'msvs_settings': {
- 'VCLinkerTool': {
- 'Profile': 'true',
- },
- 'VCCLCompilerTool': {
- # /Z7, not /Zi, so coverage is happyb
- 'DebugInformationFormat': '1',
- 'AdditionalOptions': ['/Yd'],
- }
- }
- }], # OS==win
- ], # conditions for coverage
- }], # coverage!=0
- ], # conditions for 'target_defaults'
- 'target_conditions': [
- [ 'OS=="linux" or OS=="freebsd" or OS=="openbsd"', {
- 'cflags!': [
- '-Wall',
- '-Wextra',
- '-Werror',
- ],
- }],
- [ 'OS=="win"', {
- 'defines': [
- '_CRT_SECURE_NO_DEPRECATE',
- '_CRT_NONSTDC_NO_WARNINGS',
- '_CRT_NONSTDC_NO_DEPRECATE',
- # This is required for ATL to use XP-safe versions of its functions.
- '_USING_V110_SDK71_',
- ],
- 'msvs_disabled_warnings': [4800],
- 'msvs_settings': {
- 'VCCLCompilerTool': {
- 'WarnAsError': 'true',
- 'Detect64BitPortabilityProblems': 'false',
- },
- },
- }],
- [ 'OS=="mac"', {
- 'xcode_settings': {
- 'GCC_TREAT_WARNINGS_AS_ERRORS': 'NO',
- 'WARNING_CFLAGS!': ['-Wall'],
- },
- }],
- ], # target_conditions for 'target_defaults'
- 'default_configuration': 'Debug',
- 'configurations': {
- # VCLinkerTool LinkIncremental values below:
- # 0 == default
- # 1 == /INCREMENTAL:NO
- # 2 == /INCREMENTAL
- # Debug links incremental, Release does not.
- #
- # Abstract base configurations to cover common
- # attributes.
- #
- 'Common_Base': {
- 'abstract': 1,
- 'msvs_configuration_attributes': {
- 'OutputDirectory': '$(SolutionDir)$(ConfigurationName)',
- 'IntermediateDirectory': '$(OutDir)\\obj\\$(ProjectName)',
- 'CharacterSet': '1',
- },
- },
- 'x86_Base': {
- 'abstract': 1,
- 'msvs_settings': {
- 'VCLinkerTool': {
- 'MinimumRequiredVersion': '5.01', # XP.
- 'TargetMachine': '1',
- },
- },
- 'msvs_configuration_platform': 'Win32',
- },
- 'x64_Base': {
- 'abstract': 1,
- 'msvs_configuration_platform': 'x64',
- 'msvs_settings': {
- 'VCLinkerTool': {
- 'TargetMachine': '17', # x86 - 64
- 'AdditionalLibraryDirectories!':
- ['<(DEPTH)/third_party/platformsdk_win7/files/Lib'],
- 'AdditionalLibraryDirectories':
- ['<(DEPTH)/third_party/platformsdk_win7/files/Lib/x64'],
- },
- 'VCLibrarianTool': {
- 'AdditionalLibraryDirectories!':
- ['<(DEPTH)/third_party/platformsdk_win7/files/Lib'],
- 'AdditionalLibraryDirectories':
- ['<(DEPTH)/third_party/platformsdk_win7/files/Lib/x64'],
- },
- },
- 'defines': [
- # Not sure if tcmalloc works on 64-bit Windows.
- 'NO_TCMALLOC',
- ],
- },
- 'Debug_Base': {
- 'abstract': 1,
- 'xcode_settings': {
- 'COPY_PHASE_STRIP': 'NO',
- 'GCC_OPTIMIZATION_LEVEL': '<(mac_debug_optimization)',
- 'OTHER_CFLAGS': [ '<@(debug_extra_cflags)', ],
- },
- 'msvs_settings': {
- 'VCCLCompilerTool': {
- 'Optimization': '<(win_debug_Optimization)',
- 'PreprocessorDefinitions': ['_DEBUG'],
- 'BasicRuntimeChecks': '3',
- 'RuntimeLibrary': '<(win_debug_RuntimeLibrary)',
- },
- 'VCLinkerTool': {
- 'LinkIncremental': '<(msvs_debug_link_incremental)',
- },
- 'VCResourceCompilerTool': {
- 'PreprocessorDefinitions': ['_DEBUG'],
- },
- },
- 'conditions': [
- ['OS=="linux"', {
- 'cflags': [
- '<@(debug_extra_cflags)',
- ],
- }],
- ],
- },
- 'Release_Base': {
- 'abstract': 1,
- 'defines': [
- 'NDEBUG',
- ],
- 'xcode_settings': {
- 'DEAD_CODE_STRIPPING': 'YES', # -Wl,-dead_strip
- 'GCC_OPTIMIZATION_LEVEL': '<(mac_release_optimization)',
- 'OTHER_CFLAGS': [ '<@(release_extra_cflags)', ],
- },
- 'msvs_settings': {
- 'VCCLCompilerTool': {
- 'Optimization': '<(win_release_Optimization)',
- 'RuntimeLibrary': '<(win_release_RuntimeLibrary)',
- },
- 'VCLinkerTool': {
- 'LinkIncremental': '1',
- },
- },
- 'conditions': [
- ['release_valgrind_build==0', {
- 'defines': ['NVALGRIND'],
- }],
- ['win_use_allocator_shim==0', {
- 'defines': ['NO_TCMALLOC'],
- }],
- ['win_release_RuntimeLibrary==2', {
- # Visual C++ 2008 barfs when building anything with /MD (msvcrt):
- # VC\include\typeinfo(139) : warning C4275: non dll-interface
- # class 'stdext::exception' used as base for dll-interface
- # class 'std::bad_cast'
- 'msvs_disabled_warnings': [4275],
- }],
- ['OS=="linux"', {
- 'cflags': [
- '<@(release_extra_cflags)',
- ],
- }],
- ],
- },
- 'Purify_Base': {
- 'abstract': 1,
- 'defines': [
- 'PURIFY',
- 'NO_TCMALLOC',
- ],
- 'msvs_settings': {
- 'VCCLCompilerTool': {
- 'Optimization': '0',
- 'RuntimeLibrary': '0',
- 'BufferSecurityCheck': 'false',
- },
- 'VCLinkerTool': {
- 'EnableCOMDATFolding': '1',
- 'LinkIncremental': '1',
- },
- },
- },
- #
- # Concrete configurations
- #
- 'Debug': {
- 'inherit_from': ['Common_Base', 'x86_Base', 'Debug_Base'],
- },
- 'Release': {
- 'inherit_from': ['Common_Base', 'x86_Base', 'Release_Base'],
- 'conditions': [
- ['msvs_use_common_release', {
- 'defines': ['OFFICIAL_BUILD'],
- 'msvs_settings': {
- 'VCCLCompilerTool': {
- 'Optimization': '3',
- 'StringPooling': 'true',
- 'OmitFramePointers': 'true',
- 'InlineFunctionExpansion': '2',
- 'EnableIntrinsicFunctions': 'true',
- 'FavorSizeOrSpeed': '2',
- 'OmitFramePointers': 'true',
- 'EnableFiberSafeOptimizations': 'true',
- 'WholeProgramOptimization': 'true',
- },
- 'VCLibrarianTool': {
- 'AdditionalOptions': ['/ltcg', '/expectedoutputsize:120000000'],
- },
- 'VCLinkerTool': {
- 'LinkIncremental': '1',
- 'OptimizeReferences': '2',
- 'EnableCOMDATFolding': '2',
- 'OptimizeForWindows98': '1',
- 'LinkTimeCodeGeneration': '1',
- },
- },
- }],
- ]
- },
- 'conditions': [
- [ 'OS=="win"', {
- # TODO(bradnelson): add a gyp mechanism to make this more graceful.
- 'Purify': {
- 'inherit_from': ['Common_Base', 'x86_Base', 'Release_Base', 'Purify'],
- },
- 'Debug_x64': {
- 'inherit_from': ['Common_Base', 'x64_Base', 'Debug_Base'],
- },
- 'Release_x64': {
- 'inherit_from': ['Common_Base', 'x64_Base', 'Release_Base'],
- },
- 'Purify_x64': {
- 'inherit_from': ['Common_Base', 'x64_Base', 'Release_Base', 'Purify_Base'],
- },
- }],
- ],
- },
- },
- 'conditions': [
- ['OS=="linux" or OS=="freebsd" or OS=="openbsd" or OS=="solaris"', {
- 'target_defaults': {
- # Enable -Werror by default, but put it in a variable so it can
- # be disabled in ~/.gyp/include.gypi on the valgrind builders.
- 'variables': {
- # Use -fno-strict-aliasing by default since gcc 4.4 has periodic
- # issues that slip through the cracks. We could do this just for
- # gcc 4.4 but it makes more sense to be consistent on all
- # compilers in use. TODO(Craig): turn this off again when
- # there is some 4.4 test infrastructure in place and existing
- # aliasing issues have been fixed.
- 'no_strict_aliasing%': 1,
- 'conditions': [['OS=="linux"', {'werror%': '-Werror',}],
- ['OS=="freebsd"', {'werror%': '',}],
- ['OS=="openbsd"', {'werror%': '',}],
- ],
- },
- 'cflags': [
- '<(werror)', # See note above about the werror variable.
- '-pthread',
- '-fno-exceptions',
- '-Wall',
- # TODO(evan): turn this back on once all the builds work.
- # '-Wextra',
- # Don't warn about unused function params. We use those everywhere.
- '-Wno-unused-parameter',
- # Don't warn about the "struct foo f = {0};" initialization pattern.
- '-Wno-missing-field-initializers',
- '-D_FILE_OFFSET_BITS=64',
- # Don't export any symbols (for example, to plugins we dlopen()).
- # Note: this is *required* to make some plugins work.
- '-fvisibility=hidden',
- ],
- 'cflags_cc': [
- '-frtti',
- '-fno-threadsafe-statics',
- # Make inline functions have hidden visiblity by default.
- # Surprisingly, not covered by -fvisibility=hidden.
- '-fvisibility-inlines-hidden',
- ],
- 'ldflags': [
- '-pthread', '-Wl,-z,noexecstack',
- ],
- 'scons_variable_settings': {
- 'LIBPATH': ['$LIB_DIR'],
- # Linking of large files uses lots of RAM, so serialize links
- # using the handy flock command from util-linux.
- 'FLOCK_LINK': ['flock', '$TOP_BUILDDIR/linker.lock', '$LINK'],
- 'FLOCK_SHLINK': ['flock', '$TOP_BUILDDIR/linker.lock', '$SHLINK'],
- 'FLOCK_LDMODULE': ['flock', '$TOP_BUILDDIR/linker.lock', '$LDMODULE'],
-
- # We have several cases where archives depend on each other in
- # a cyclic fashion. Since the GNU linker does only a single
- # pass over the archives we surround the libraries with
- # --start-group and --end-group (aka -( and -) ). That causes
- # ld to loop over the group until no more undefined symbols
- # are found. In an ideal world we would only make groups from
- # those libraries which we knew to be in cycles. However,
- # that's tough with SCons, so we bodge it by making all the
- # archives a group by redefining the linking command here.
- #
- # TODO: investigate whether we still have cycles that
- # require --{start,end}-group. There has been a lot of
- # refactoring since this was first coded, which might have
- # eliminated the circular dependencies.
- #
- # Note: $_LIBDIRFLAGS comes before ${LINK,SHLINK,LDMODULE}FLAGS
- # so that we prefer our own built libraries (e.g. -lpng) to
- # system versions of libraries that pkg-config might turn up.
- # TODO(sgk): investigate handling this not by re-ordering the
- # flags this way, but by adding a hook to use the SCons
- # ParseFlags() option on the output from pkg-config.
- 'LINKCOM': [['$FLOCK_LINK', '-o', '$TARGET',
- '$_LIBDIRFLAGS', '$LINKFLAGS', '$SOURCES',
- '-Wl,--start-group', '$_LIBFLAGS', '-Wl,--end-group']],
- 'SHLINKCOM': [['$FLOCK_SHLINK', '-o', '$TARGET',
- '$_LIBDIRFLAGS', '$SHLINKFLAGS', '$SOURCES',
- '-Wl,--start-group', '$_LIBFLAGS', '-Wl,--end-group']],
- 'LDMODULECOM': [['$FLOCK_LDMODULE', '-o', '$TARGET',
- '$_LIBDIRFLAGS', '$LDMODULEFLAGS', '$SOURCES',
- '-Wl,--start-group', '$_LIBFLAGS', '-Wl,--end-group']],
- 'IMPLICIT_COMMAND_DEPENDENCIES': 0,
- },
- 'scons_import_variables': [
- 'AS',
- 'CC',
- 'CXX',
- 'LINK',
- ],
- 'scons_propagate_variables': [
- 'AS',
- 'CC',
- 'CCACHE_DIR',
- 'CXX',
- 'DISTCC_DIR',
- 'DISTCC_HOSTS',
- 'HOME',
- 'INCLUDE_SERVER_ARGS',
- 'INCLUDE_SERVER_PORT',
- 'LINK',
- 'CHROME_BUILD_TYPE',
- 'CHROMIUM_BUILD',
- 'OFFICIAL_BUILD',
- ],
- 'configurations': {
- 'Debug_Base': {
- 'variables': {
- 'debug_optimize%': '0',
- },
- 'defines': [
- '_DEBUG',
- ],
- 'cflags': [
- '-O>(debug_optimize)',
- '-g',
- # One can use '-gstabs' to enable building the debugging
- # information in STABS format for breakpad's dumpsyms.
- ],
- 'ldflags': [
- '-rdynamic', # Allows backtrace to resolve symbols.
- ],
- },
- 'Release_Base': {
- 'variables': {
- 'release_optimize%': '2',
- },
- 'cflags': [
- '-O>(release_optimize)',
- # Don't emit the GCC version ident directives, they just end up
- # in the .comment section taking up binary size.
- '-fno-ident',
- # Put data and code in their own sections, so that unused symbols
- # can be removed at link time with --gc-sections.
- '-fdata-sections',
- '-ffunction-sections',
- ],
- 'ldflags': [
- '-Wl,--gc-sections',
- ],
- },
- },
- 'variants': {
- 'coverage': {
- 'cflags': ['-fprofile-arcs', '-ftest-coverage'],
- 'ldflags': ['-fprofile-arcs'],
- },
- 'profile': {
- 'cflags': ['-pg', '-g'],
- 'ldflags': ['-pg'],
- },
- 'symbols': {
- 'cflags': ['-g'],
- },
- },
- 'conditions': [
- [ 'target_arch=="ia32"', {
- 'asflags': [
- # Needed so that libs with .s files (e.g. libicudata.a)
- # are compatible with the general 32-bit-ness.
- '-32',
- ],
- # All floating-point computations on x87 happens in 80-bit
- # precision. Because the C and C++ language standards allow
- # the compiler to keep the floating-point values in higher
- # precision than what's specified in the source and doing so
- # is more efficient than constantly rounding up to 64-bit or
- # 32-bit precision as specified in the source, the compiler,
- # especially in the optimized mode, tries very hard to keep
- # values in x87 floating-point stack (in 80-bit precision)
- # as long as possible. This has important side effects, that
- # the real value used in computation may change depending on
- # how the compiler did the optimization - that is, the value
- # kept in 80-bit is different than the value rounded down to
- # 64-bit or 32-bit. There are possible compiler options to make
- # this behavior consistent (e.g. -ffloat-store would keep all
- # floating-values in the memory, thus force them to be rounded
- # to its original precision) but they have significant runtime
- # performance penalty.
- #
- # -mfpmath=sse -msse2 makes the compiler use SSE instructions
- # which keep floating-point values in SSE registers in its
- # native precision (32-bit for single precision, and 64-bit for
- # double precision values). This means the floating-point value
- # used during computation does not change depending on how the
- # compiler optimized the code, since the value is always kept
- # in its specified precision.
- 'conditions': [
- ['disable_sse2==0', {
- 'cflags': [
- '-march=pentium4',
- '-msse2',
- '-mfpmath=sse',
- ],
- }],
- ],
- # -mmmx allows mmintrin.h to be used for mmx intrinsics.
- # video playback is mmx and sse2 optimized.
- 'cflags': [
- '-m32',
- '-mmmx',
- ],
- 'ldflags': [
- '-m32',
- ],
- }],
- ['target_arch=="arm"', {
- 'target_conditions': [
- ['_toolset=="target"', {
- 'cflags_cc': [
- # The codesourcery arm-2009q3 toolchain warns at that the ABI
- # has changed whenever it encounters a varargs function. This
- # silences those warnings, as they are not helpful and
- # clutter legitimate warnings.
- '-Wno-abi',
- ],
- 'conditions': [
- ['arm_thumb == 1', {
- 'cflags': [
- '-mthumb',
- # TODO(piman): -Wa,-mimplicit-it=thumb is needed for
- # inline assembly that uses condition codes but it's
- # suboptimal. Better would be to #ifdef __thumb__ at the
- # right place and have a separate thumb path.
- '-Wa,-mimplicit-it=thumb',
- ]
- }],
- ['arm_version==7', {
- 'cflags': [
- '-march=armv7-a',
- '-mtune=cortex-a8',
- '-mfloat-abi=softfp',
- ],
- 'conditions': [
- ['arm_neon==1', {
- 'cflags': [ '-mfpu=neon', ],
- }, {
- 'cflags': [ '-mfpu=<(arm_fpu)', ],
- }]
- ],
- }],
- ],
- }],
- ],
- }],
- ['linux_fpic==1', {
- 'cflags': [
- '-fPIC',
- ],
- }],
- ['sysroot!=""', {
- 'target_conditions': [
- ['_toolset=="target"', {
- 'cflags': [
- '--sysroot=<(sysroot)',
- ],
- 'ldflags': [
- '--sysroot=<(sysroot)',
- ],
- }]]
- }],
- ['no_strict_aliasing==1', {
- 'cflags': [
- '-fno-strict-aliasing',
- ],
- }],
- ['linux_use_heapchecker==1', {
- 'variables': {'linux_use_tcmalloc%': 1},
- }],
- ['linux_use_tcmalloc==0', {
- 'defines': ['NO_TCMALLOC'],
- }],
- ['linux_use_heapchecker==0', {
- 'defines': ['NO_HEAPCHECKER'],
- }],
- ],
- },
- }],
- # FreeBSD-specific options; note that most FreeBSD options are set above,
- # with Linux.
- ['OS=="freebsd"', {
- 'target_defaults': {
- 'ldflags': [
- '-Wl,--no-keep-memory',
- ],
- },
- }],
- ['OS=="solaris"', {
- 'cflags!': ['-fvisibility=hidden'],
- 'cflags_cc!': ['-fvisibility-inlines-hidden'],
- }],
- ['OS=="mac"', {
- 'target_defaults': {
- 'variables': {
- # This should be 'mac_real_dsym%', but there seems to be a bug
- # with % in variables that are intended to be set to different
- # values in different targets, like this one.
- 'mac_real_dsym': 0, # Fake .dSYMs are fine in most cases.
- },
- 'mac_bundle': 0,
- 'xcode_settings': {
- 'ALWAYS_SEARCH_USER_PATHS': 'NO',
- 'GCC_C_LANGUAGE_STANDARD': 'c99', # -std=c99
- 'GCC_CW_ASM_SYNTAX': 'NO', # No -fasm-blocks
- 'GCC_DYNAMIC_NO_PIC': 'NO', # No -mdynamic-no-pic
- # (Equivalent to -fPIC)
- 'GCC_ENABLE_CPP_EXCEPTIONS': 'NO', # -fno-exceptions
- 'GCC_ENABLE_CPP_RTTI': 'YES', # -frtti
- 'GCC_ENABLE_PASCAL_STRINGS': 'NO', # No -mpascal-strings
- # GCC_INLINES_ARE_PRIVATE_EXTERN maps to -fvisibility-inlines-hidden
- 'GCC_INLINES_ARE_PRIVATE_EXTERN': 'YES',
- 'GCC_OBJC_CALL_CXX_CDTORS': 'YES', # -fobjc-call-cxx-cdtors
- 'GCC_SYMBOLS_PRIVATE_EXTERN': 'YES', # -fvisibility=hidden
- 'GCC_THREADSAFE_STATICS': 'NO', # -fno-threadsafe-statics
- 'GCC_TREAT_WARNINGS_AS_ERRORS': 'YES', # -Werror
- 'GCC_VERSION': '4.2',
- 'GCC_WARN_ABOUT_MISSING_NEWLINE': 'YES', # -Wnewline-eof
- # MACOSX_DEPLOYMENT_TARGET maps to -mmacosx-version-min
- 'MACOSX_DEPLOYMENT_TARGET': '<(mac_deployment_target)',
- 'PREBINDING': 'NO', # No -Wl,-prebind
- 'USE_HEADERMAP': 'NO',
- 'WARNING_CFLAGS': ['-Wall', '-Wendif-labels'],
- 'conditions': [
- ['chromium_mac_pch', {'GCC_PRECOMPILE_PREFIX_HEADER': 'YES'},
- {'GCC_PRECOMPILE_PREFIX_HEADER': 'NO'}
- ],
- ],
- },
- 'target_conditions': [
- ['_type!="static_library"', {
- 'xcode_settings': {'OTHER_LDFLAGS': ['-Wl,-search_paths_first']},
- }],
- ['_mac_bundle', {
- 'xcode_settings': {'OTHER_LDFLAGS': ['-Wl,-ObjC']},
- }],
- ], # target_conditions
- }, # target_defaults
- }], # OS=="mac"
- ['OS=="win"', {
- 'target_defaults': {
- 'defines': [
- '_WIN32_WINNT=0x0600',
- 'WINVER=0x0600',
- 'WIN32',
- '_WINDOWS',
- '_HAS_EXCEPTIONS=0',
- 'NOMINMAX',
- '_CRT_RAND_S',
- 'CERT_CHAIN_PARA_HAS_EXTRA_FIELDS',
- 'WIN32_LEAN_AND_MEAN',
- '_SECURE_ATL',
- '_HAS_TR1=0',
- ],
- 'msvs_system_include_dirs': [
- '<(DEPTH)/third_party/platformsdk_win7/files/Include',
- '$(VSInstallDir)/VC/atlmfc/include',
- ],
- 'msvs_cygwin_dirs': ['<(DEPTH)/third_party/cygwin'],
- 'msvs_disabled_warnings': [
- 4091, 4100, 4127, 4366, 4396, 4503, 4512, 4819, 4995, 4702
- ],
- 'msvs_settings': {
- 'VCCLCompilerTool': {
- 'MinimalRebuild': 'false',
- 'ExceptionHandling': '0',
- 'BufferSecurityCheck': 'true',
- 'EnableFunctionLevelLinking': 'true',
- 'RuntimeTypeInfo': 'false',
- 'WarningLevel': '4',
- 'WarnAsError': 'true',
- 'DebugInformationFormat': '3',
- 'conditions': [
- [ 'msvs_multi_core_compile', {
- 'AdditionalOptions': ['/MP'],
- }],
- ],
- },
- 'VCLibrarianTool': {
- 'AdditionalOptions': ['/ignore:4221'],
- 'AdditionalLibraryDirectories':
- ['<(DEPTH)/third_party/platformsdk_win7/files/Lib'],
- },
- 'VCLinkerTool': {
- 'AdditionalDependencies': [
- 'wininet.lib',
- 'version.lib',
- 'msimg32.lib',
- 'ws2_32.lib',
- 'usp10.lib',
- 'psapi.lib',
- 'dbghelp.lib',
- ],
- 'AdditionalLibraryDirectories':
- ['<(DEPTH)/third_party/platformsdk_win7/files/Lib'],
- 'GenerateDebugInformation': 'true',
- 'MapFileName': '$(OutDir)\\$(TargetName).map',
- 'ImportLibrary': '$(OutDir)\\lib\\$(TargetName).lib',
- 'FixedBaseAddress': '1',
- # SubSystem values:
- # 0 == not set
- # 1 == /SUBSYSTEM:CONSOLE
- # 2 == /SUBSYSTEM:WINDOWS
- # Most of the executables we'll ever create are tests
- # and utilities with console output.
- 'SubSystem': '1',
- },
- 'VCMIDLTool': {
- 'GenerateStublessProxies': 'true',
- 'TypeLibraryName': '$(InputName).tlb',
- 'OutputDirectory': '$(IntDir)',
- 'HeaderFileName': '$(InputName).h',
- 'DLLDataFileName': 'dlldata.c',
- 'InterfaceIdentifierFileName': '$(InputName)_i.c',
- 'ProxyFileName': '$(InputName)_p.c',
- },
- 'VCResourceCompilerTool': {
- 'Culture' : '1033',
- 'AdditionalIncludeDirectories': ['<(DEPTH)'],
- },
- },
- },
- }],
- ['disable_nacl==1 or OS=="freebsd" or OS=="openbsd" or OS=="solaris"', {
- 'target_defaults': {
- 'defines': [
- 'DISABLE_NACL',
- ],
- },
- }],
- ['OS=="win" and msvs_use_common_linker_extras', {
- 'target_defaults': {
- 'msvs_settings': {
- 'VCLinkerTool': {
- 'DelayLoadDLLs': [
- 'dbghelp.dll',
- 'dwmapi.dll',
- 'uxtheme.dll',
- ],
- },
- },
- 'configurations': {
- 'x86_Base': {
- 'msvs_settings': {
- 'VCLinkerTool': {
- 'AdditionalOptions': [
- '/safeseh',
- '/dynamicbase',
- '/ignore:4199',
- '/ignore:4221',
- '/nxcompat',
- ],
- },
- },
- },
- 'x64_Base': {
- 'msvs_settings': {
- 'VCLinkerTool': {
- 'AdditionalOptions': [
- # safeseh is not compatible with x64
- '/dynamicbase',
- '/ignore:4199',
- '/ignore:4221',
- '/nxcompat',
- ],
- },
- },
- },
- },
- },
- }],
- ['enable_new_npdevice_api==1', {
- 'target_defaults': {
- 'defines': [
- 'ENABLE_NEW_NPDEVICE_API',
- ],
- },
- }],
- ],
- 'scons_settings': {
- 'sconsbuild_dir': '<(DEPTH)/sconsbuild',
- 'tools': ['ar', 'as', 'gcc', 'g++', 'gnulink', 'chromium_builders'],
- },
- 'xcode_settings': {
- # DON'T ADD ANYTHING NEW TO THIS BLOCK UNLESS YOU REALLY REALLY NEED IT!
- # This block adds *project-wide* configuration settings to each project
- # file. It's almost always wrong to put things here. Specify your
- # custom xcode_settings in target_defaults to add them to targets instead.
-
- # In an Xcode Project Info window, the "Base SDK for All Configurations"
- # setting sets the SDK on a project-wide basis. In order to get the
- # configured SDK to show properly in the Xcode UI, SDKROOT must be set
- # here at the project level.
- 'SDKROOT': 'macosx<(mac_sdk)', # -isysroot
-
- # The Xcode generator will look for an xcode_settings section at the root
- # of each dict and use it to apply settings on a file-wide basis. Most
- # settings should not be here, they should be in target-specific
- # xcode_settings sections, or better yet, should use non-Xcode-specific
- # settings in target dicts. SYMROOT is a special case, because many other
- # Xcode variables depend on it, including variables such as
- # PROJECT_DERIVED_FILE_DIR. When a source group corresponding to something
- # like PROJECT_DERIVED_FILE_DIR is added to a project, in order for the
- # files to appear (when present) in the UI as actual files and not red
- # red "missing file" proxies, the correct path to PROJECT_DERIVED_FILE_DIR,
- # and therefore SYMROOT, needs to be set at the project level.
- 'SYMROOT': '<(DEPTH)/xcodebuild',
- },
-}
diff --git a/src/build/filename_rules.gypi b/src/build/filename_rules.gypi
deleted file mode 100644
index 78cd1808..00000000
--- a/src/build/filename_rules.gypi
+++ /dev/null
@@ -1,57 +0,0 @@
-# Copyright 2014 Google Inc. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-# * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-# * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-{
- 'target_conditions': [
- ['OS!="win"', {
- 'sources/': [
- ['exclude', '(^|/)windows/'],
- ],
- }],
- ['OS!="linux"', {
- 'sources/': [
- ['exclude', '(^|/)linux/'],
- ],
- }],
- ['OS!="mac"', {
- 'sources/': [
- ['exclude', '(^|/)mac/'],
- ],
- }],
- ['OS!="android"', {
- 'sources/': [
- ['exclude', '(^|/)android/'],
- ],
- }],
- ['OS!="solaris"', {
- 'sources/': [
- ['exclude', '(^|/)solaris/'],
- ],
- }],
- ],
-}
diff --git a/src/build/gyp_breakpad b/src/build/gyp_breakpad
deleted file mode 100755
index 0b8077d2..00000000
--- a/src/build/gyp_breakpad
+++ /dev/null
@@ -1,67 +0,0 @@
-#!/usr/bin/env python
-
-# Copyright 2014 Google Inc. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-# * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-# * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-import os
-import platform
-import sys
-
-script_dir = os.path.dirname(os.path.realpath(__file__))
-breakpad_root = os.path.abspath(os.path.join(script_dir, os.pardir))
-
-sys.path.insert(0, os.path.join(breakpad_root, 'tools', 'gyp', 'pylib'))
-import gyp
-
-def run_gyp(args):
- rc = gyp.main(args)
- if rc != 0:
- print 'Error running GYP'
- sys.exit(rc)
-
-
-def main():
- args = sys.argv[1:]
- args.append(os.path.join(script_dir, 'all.gyp'))
-
- args.append('-I')
- args.append(os.path.join(breakpad_root, 'build', 'common.gypi'))
-
- args.extend(['-D', 'gyp_output_dir=out'])
-
- # Set the GYP DEPTH variable to the root of the project.
- args.append('--depth=' + os.path.relpath(breakpad_root))
-
- print 'Updating projects from gyp files...'
- sys.stdout.flush()
-
- run_gyp(args)
-
-
-if __name__ == '__main__':
- sys.exit(main())
diff --git a/src/build/testing.gyp b/src/build/testing.gyp
deleted file mode 100644
index 6a459a64..00000000
--- a/src/build/testing.gyp
+++ /dev/null
@@ -1,90 +0,0 @@
-# Copyright 2014 Google Inc. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-# * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-# * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-{
- 'targets': [
- {
- 'target_name': 'gtest',
- 'type': 'static_library',
- 'sources': [
- '../testing/googletest/src/gtest-all.cc',
- ],
- 'include_dirs': [
- '../testing/googletest',
- '../testing/googletest/include',
- ],
- 'direct_dependent_settings': {
- 'include_dirs': [
- '../testing/googletest/include',
- ],
- },
- },
- {
- 'target_name': 'gtest_main',
- 'type': 'static_library',
- 'dependencies': [
- 'gtest',
- ],
- 'sources': [
- '../testing/googletest/src/gtest_main.cc',
- ],
- },
- {
- 'target_name': 'gmock',
- 'type': 'static_library',
- 'dependencies': [
- 'gtest',
- ],
- 'sources': [
- '../testing/googlemock/src/gmock-all.cc',
- ],
- 'include_dirs': [
- '../testing/googlemock',
- '../testing/googlemock/include',
- ],
- 'direct_dependent_settings': {
- 'include_dirs': [
- '../testing/googlemock/include',
- ],
- },
- 'export_dependent_settings': [
- 'gtest',
- ],
- },
- {
- 'target_name': 'gmock_main',
- 'type': 'static_library',
- 'dependencies': [
- 'gmock',
- ],
- 'sources': [
- '../testing/googlemock/src/gmock_main.cc',
- ],
- },
- ],
-}
diff --git a/src/client/apple/Framework/BreakpadDefines.h b/src/client/apple/Framework/BreakpadDefines.h
index 410a5a6f..1946534e 100644
--- a/src/client/apple/Framework/BreakpadDefines.h
+++ b/src/client/apple/Framework/BreakpadDefines.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2011, Google Inc.
-// All rights reserved.
+// Copyright 2011 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/client/ios/Breakpad.h b/src/client/ios/Breakpad.h
index fa790f77..950c0388 100644
--- a/src/client/ios/Breakpad.h
+++ b/src/client/ios/Breakpad.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2011, Google Inc.
-// All rights reserved.
+// Copyright 2011 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -37,7 +36,7 @@
//
// These files can then be uploaded to a server.
-typedef void *BreakpadRef;
+typedef void* BreakpadRef;
#ifdef __cplusplus
extern "C" {
@@ -60,15 +59,15 @@ extern "C" {
typedef bool (*BreakpadFilterCallback)(int exception_type,
int exception_code,
mach_port_t crashing_thread,
- void *context);
+ void* context);
// Optional user-defined function that will be called after a network upload
// of a crash report.
// |report_id| will be the id returned by the server, or "ERR" if an error
// occurred.
// |error| will contain the error, or nil if no error occured.
-typedef void (*BreakpadUploadCompletionCallback)(NSString *report_id,
- NSError *error);
+typedef void (*BreakpadUploadCompletionCallback)(NSString* report_id,
+ NSError* error);
// Create a new BreakpadRef object and install it as an exception
// handler. The |parameters| will typically be the contents of your
@@ -163,7 +162,7 @@ typedef void (*BreakpadUploadCompletionCallback)(NSString *report_id,
// internal values.
// Returns a new BreakpadRef object on success, NULL otherwise.
-BreakpadRef BreakpadCreate(NSDictionary *parameters);
+BreakpadRef BreakpadCreate(NSDictionary* parameters);
// Uninstall and release the data associated with |ref|.
void BreakpadRelease(BreakpadRef ref);
@@ -187,20 +186,20 @@ void BreakpadRelease(BreakpadRef ref);
// TODO (nealsid): separate server parameter dictionary from the
// dictionary used to configure Breakpad, and document limits for each
// independently.
-void BreakpadSetKeyValue(BreakpadRef ref, NSString *key, NSString *value);
-NSString *BreakpadKeyValue(BreakpadRef ref, NSString *key);
-void BreakpadRemoveKeyValue(BreakpadRef ref, NSString *key);
+void BreakpadSetKeyValue(BreakpadRef ref, NSString* key, NSString* value);
+NSString* BreakpadKeyValue(BreakpadRef ref, NSString* key);
+void BreakpadRemoveKeyValue(BreakpadRef ref, NSString* key);
// You can use this method to specify parameters that will be uploaded
// to the crash server. They will be automatically encoded as
// necessary. Note that as mentioned above there are limits on both
// the number of keys and their length.
-void BreakpadAddUploadParameter(BreakpadRef ref, NSString *key,
- NSString *value);
+void BreakpadAddUploadParameter(BreakpadRef ref, NSString* key,
+ NSString* value);
// This method will remove a previously-added parameter from the
// upload parameter set.
-void BreakpadRemoveUploadParameter(BreakpadRef ref, NSString *key);
+void BreakpadRemoveUploadParameter(BreakpadRef ref, NSString* key);
// Method to handle uploading data to the server
@@ -208,10 +207,10 @@ void BreakpadRemoveUploadParameter(BreakpadRef ref, NSString *key);
int BreakpadGetCrashReportCount(BreakpadRef ref);
// Returns the next upload configuration. The report file is deleted.
-NSDictionary *BreakpadGetNextReportConfiguration(BreakpadRef ref);
+NSDictionary* BreakpadGetNextReportConfiguration(BreakpadRef ref);
// Returns the date of the most recent crash report.
-NSDate *BreakpadGetDateOfMostRecentCrashReport(BreakpadRef ref);
+NSDate* BreakpadGetDateOfMostRecentCrashReport(BreakpadRef ref);
// Upload next report to the server.
void BreakpadUploadNextReport(BreakpadRef ref);
@@ -220,7 +219,7 @@ void BreakpadUploadNextReport(BreakpadRef ref);
// |server_parameters| is additional server parameters to send.
void BreakpadUploadNextReportWithParameters(
BreakpadRef ref,
- NSDictionary *server_parameters,
+ NSDictionary* server_parameters,
BreakpadUploadCompletionCallback callback);
// Upload a report to the server.
@@ -228,8 +227,8 @@ void BreakpadUploadNextReportWithParameters(
// |configuration| is the configuration of the breakpad report to send.
void BreakpadUploadReportWithParametersAndConfiguration(
BreakpadRef ref,
- NSDictionary *server_parameters,
- NSDictionary *configuration,
+ NSDictionary* server_parameters,
+ NSDictionary* configuration,
BreakpadUploadCompletionCallback callback);
// Handles the network response of a breakpad upload. This function is needed if
@@ -239,21 +238,21 @@ void BreakpadUploadReportWithParametersAndConfiguration(
// BreakpadUploadReportWithParametersAndConfiguration.
// |data| and |error| contain the network response.
void BreakpadHandleNetworkResponse(BreakpadRef ref,
- NSDictionary *configuration,
- NSData *data,
- NSError *error);
+ NSDictionary* configuration,
+ NSData* data,
+ NSError* error);
// Upload a file to the server. |data| is the content of the file to sent.
// |server_parameters| is additional server parameters to send.
-void BreakpadUploadData(BreakpadRef ref, NSData *data, NSString *name,
- NSDictionary *server_parameters);
+void BreakpadUploadData(BreakpadRef ref, NSData* data, NSString* name,
+ NSDictionary* server_parameters);
// Generate a breakpad minidump and configuration file in the dump directory.
// The report will be available for uploading. The paths of the created files
// are returned in the dictionary. |server_parameters| is additional server
// parameters to add in the config file.
-NSDictionary *BreakpadGenerateReport(BreakpadRef ref,
- NSDictionary *server_parameters);
+NSDictionary* BreakpadGenerateReport(BreakpadRef ref,
+ NSDictionary* server_parameters);
#ifdef __cplusplus
}
diff --git a/src/client/ios/Breakpad.mm b/src/client/ios/Breakpad.mm
index 2b61bbe3..e2497461 100644
--- a/src/client/ios/Breakpad.mm
+++ b/src/client/ios/Breakpad.mm
@@ -1,5 +1,4 @@
-// Copyright (c) 2011, Google Inc.
-// All rights reserved.
+// Copyright 2011 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -84,9 +83,9 @@ using google_breakpad::LongStringDictionary;
// allocation of C++ objects. Note that we don't use operator delete()
// but instead call the objects destructor directly: object->~ClassName();
//
-ProtectedMemoryAllocator *gMasterAllocator = NULL;
-ProtectedMemoryAllocator *gKeyValueAllocator = NULL;
-ProtectedMemoryAllocator *gBreakpadAllocator = NULL;
+ProtectedMemoryAllocator* gMasterAllocator = NULL;
+ProtectedMemoryAllocator* gKeyValueAllocator = NULL;
+ProtectedMemoryAllocator* gBreakpadAllocator = NULL;
// Mutex for thread-safe access to the key/value dictionary used by breakpad.
// It's a global instead of an instance variable of Breakpad
@@ -101,8 +100,8 @@ pthread_mutex_t gDictionaryMutex;
// Its destructor will first re-protect the memory then release the lock.
class ProtectedMemoryLocker {
public:
- ProtectedMemoryLocker(pthread_mutex_t *mutex,
- ProtectedMemoryAllocator *allocator)
+ ProtectedMemoryLocker(pthread_mutex_t* mutex,
+ ProtectedMemoryAllocator* allocator)
: mutex_(mutex),
allocator_(allocator) {
// Lock the mutex
@@ -127,17 +126,17 @@ class ProtectedMemoryLocker {
ProtectedMemoryLocker(const ProtectedMemoryLocker&);
ProtectedMemoryLocker& operator=(const ProtectedMemoryLocker&);
- pthread_mutex_t *mutex_;
- ProtectedMemoryAllocator *allocator_;
+ pthread_mutex_t* mutex_;
+ ProtectedMemoryAllocator* allocator_;
};
//=============================================================================
class Breakpad {
public:
// factory method
- static Breakpad *Create(NSDictionary *parameters) {
+ static Breakpad* Create(NSDictionary* parameters) {
// Allocate from our special allocation pool
- Breakpad *breakpad =
+ Breakpad* breakpad =
new (gBreakpadAllocator->Allocate(sizeof(Breakpad)))
Breakpad();
@@ -155,62 +154,62 @@ class Breakpad {
~Breakpad();
- void SetKeyValue(NSString *key, NSString *value);
- NSString *KeyValue(NSString *key);
- void RemoveKeyValue(NSString *key);
- NSArray *CrashReportsToUpload();
- NSString *NextCrashReportToUpload();
- NSDictionary *NextCrashReportConfiguration();
- NSDictionary *FixedUpCrashReportConfiguration(NSDictionary *configuration);
- NSDate *DateOfMostRecentCrashReport();
- void UploadNextReport(NSDictionary *server_parameters);
- void UploadReportWithConfiguration(NSDictionary *configuration,
- NSDictionary *server_parameters,
+ void SetKeyValue(NSString* key, NSString* value);
+ NSString* KeyValue(NSString* key);
+ void RemoveKeyValue(NSString* key);
+ NSArray* CrashReportsToUpload();
+ NSString* NextCrashReportToUpload();
+ NSDictionary* NextCrashReportConfiguration();
+ NSDictionary* FixedUpCrashReportConfiguration(NSDictionary* configuration);
+ NSDate* DateOfMostRecentCrashReport();
+ void UploadNextReport(NSDictionary* server_parameters);
+ void UploadReportWithConfiguration(NSDictionary* configuration,
+ NSDictionary* server_parameters,
BreakpadUploadCompletionCallback callback);
- void UploadData(NSData *data, NSString *name,
- NSDictionary *server_parameters);
- void HandleNetworkResponse(NSDictionary *configuration,
- NSData *data,
- NSError *error);
- NSDictionary *GenerateReport(NSDictionary *server_parameters);
+ void UploadData(NSData* data, NSString* name,
+ NSDictionary* server_parameters);
+ void HandleNetworkResponse(NSDictionary* configuration,
+ NSData* data,
+ NSError* error);
+ NSDictionary* GenerateReport(NSDictionary* server_parameters);
private:
Breakpad()
: handler_(NULL),
config_params_(NULL) {}
- bool Initialize(NSDictionary *parameters);
+ bool Initialize(NSDictionary* parameters);
- bool ExtractParameters(NSDictionary *parameters);
+ bool ExtractParameters(NSDictionary* parameters);
// Dispatches to HandleMinidump()
- static bool HandleMinidumpCallback(const char *dump_dir,
- const char *minidump_id,
- void *context, bool succeeded);
+ static bool HandleMinidumpCallback(const char* dump_dir,
+ const char* minidump_id,
+ void* context, bool succeeded);
- bool HandleMinidump(const char *dump_dir,
- const char *minidump_id);
+ bool HandleMinidump(const char* dump_dir,
+ const char* minidump_id);
// NSException handler
- static void UncaughtExceptionHandler(NSException *exception);
+ static void UncaughtExceptionHandler(NSException* exception);
// Handle an uncaught NSException.
- void HandleUncaughtException(NSException *exception);
+ void HandleUncaughtException(NSException* exception);
// Since ExceptionHandler (w/o namespace) is defined as typedef in OSX's
// MachineExceptions.h, we have to explicitly name the handler.
- google_breakpad::ExceptionHandler *handler_; // The actual handler (STRONG)
+ google_breakpad::ExceptionHandler* handler_; // The actual handler (STRONG)
- LongStringDictionary *config_params_; // Create parameters (STRONG)
+ LongStringDictionary* config_params_; // Create parameters (STRONG)
ConfigFile config_file_;
// A static reference to the current Breakpad instance. Used for handling
// NSException.
- static Breakpad *current_breakpad_;
+ static Breakpad* current_breakpad_;
};
-Breakpad *Breakpad::current_breakpad_ = NULL;
+Breakpad* Breakpad::current_breakpad_ = NULL;
#pragma mark -
#pragma mark Helper functions
@@ -221,14 +220,14 @@ Breakpad *Breakpad::current_breakpad_ = NULL;
//=============================================================================
static BOOL IsDebuggerActive() {
BOOL result = NO;
- NSUserDefaults *stdDefaults = [NSUserDefaults standardUserDefaults];
+ NSUserDefaults* stdDefaults = [NSUserDefaults standardUserDefaults];
// We check both defaults and the environment variable here
BOOL ignoreDebugger = [stdDefaults boolForKey:@IGNORE_DEBUGGER];
if (!ignoreDebugger) {
- char *ignoreDebuggerStr = getenv(IGNORE_DEBUGGER);
+ char* ignoreDebuggerStr = getenv(IGNORE_DEBUGGER);
ignoreDebugger =
(ignoreDebuggerStr ? strtol(ignoreDebuggerStr, NULL, 10) : 0) != 0;
}
@@ -240,7 +239,7 @@ static BOOL IsDebuggerActive() {
size_t actualSize;
if (sysctl(mib, mibSize, NULL, &actualSize, NULL, 0) == 0) {
- struct kinfo_proc *info = (struct kinfo_proc *)malloc(actualSize);
+ struct kinfo_proc* info = (struct kinfo_proc*)malloc(actualSize);
if (info) {
// This comes from looking at the Darwin xnu Kernel
@@ -256,10 +255,10 @@ static BOOL IsDebuggerActive() {
}
//=============================================================================
-bool Breakpad::HandleMinidumpCallback(const char *dump_dir,
- const char *minidump_id,
- void *context, bool succeeded) {
- Breakpad *breakpad = (Breakpad *)context;
+bool Breakpad::HandleMinidumpCallback(const char* dump_dir,
+ const char* minidump_id,
+ void* context, bool succeeded) {
+ Breakpad* breakpad = (Breakpad*)context;
// If our context is damaged or something, just return false to indicate that
// the handler should continue without us.
@@ -270,7 +269,7 @@ bool Breakpad::HandleMinidumpCallback(const char *dump_dir,
}
//=============================================================================
-void Breakpad::UncaughtExceptionHandler(NSException *exception) {
+void Breakpad::UncaughtExceptionHandler(NSException* exception) {
NSSetUncaughtExceptionHandler(NULL);
if (current_breakpad_) {
current_breakpad_->HandleUncaughtException(exception);
@@ -282,7 +281,7 @@ void Breakpad::UncaughtExceptionHandler(NSException *exception) {
#pragma mark -
//=============================================================================
-bool Breakpad::Initialize(NSDictionary *parameters) {
+bool Breakpad::Initialize(NSDictionary* parameters) {
// Initialize
current_breakpad_ = this;
config_params_ = NULL;
@@ -325,21 +324,21 @@ Breakpad::~Breakpad() {
}
//=============================================================================
-bool Breakpad::ExtractParameters(NSDictionary *parameters) {
- NSString *serverType = [parameters objectForKey:@BREAKPAD_SERVER_TYPE];
- NSString *display = [parameters objectForKey:@BREAKPAD_PRODUCT_DISPLAY];
- NSString *product = [parameters objectForKey:@BREAKPAD_PRODUCT];
- NSString *version = [parameters objectForKey:@BREAKPAD_VERSION];
- NSString *urlStr = [parameters objectForKey:@BREAKPAD_URL];
- NSString *vendor =
+bool Breakpad::ExtractParameters(NSDictionary* parameters) {
+ NSString* serverType = [parameters objectForKey:@BREAKPAD_SERVER_TYPE];
+ NSString* display = [parameters objectForKey:@BREAKPAD_PRODUCT_DISPLAY];
+ NSString* product = [parameters objectForKey:@BREAKPAD_PRODUCT];
+ NSString* version = [parameters objectForKey:@BREAKPAD_VERSION];
+ NSString* urlStr = [parameters objectForKey:@BREAKPAD_URL];
+ NSString* vendor =
[parameters objectForKey:@BREAKPAD_VENDOR];
// We check both parameters and the environment variable here.
- char *envVarDumpSubdirectory = getenv(BREAKPAD_DUMP_DIRECTORY);
- NSString *dumpSubdirectory = envVarDumpSubdirectory ?
+ char* envVarDumpSubdirectory = getenv(BREAKPAD_DUMP_DIRECTORY);
+ NSString* dumpSubdirectory = envVarDumpSubdirectory ?
[NSString stringWithUTF8String:envVarDumpSubdirectory] :
[parameters objectForKey:@BREAKPAD_DUMP_DIRECTORY];
- NSDictionary *serverParameters =
+ NSDictionary* serverParameters =
[parameters objectForKey:@BREAKPAD_SERVER_PARAMETER_DICT];
if (!product)
@@ -360,7 +359,7 @@ bool Breakpad::ExtractParameters(NSDictionary *parameters) {
}
if (!dumpSubdirectory) {
- NSString *cachePath =
+ NSString* cachePath =
[NSSearchPathForDirectoriesInDomains(NSCachesDirectory,
NSUserDomainMask,
YES)
@@ -388,7 +387,7 @@ bool Breakpad::ExtractParameters(NSDictionary *parameters) {
new (gKeyValueAllocator->Allocate(sizeof(LongStringDictionary)))
LongStringDictionary();
- LongStringDictionary &dictionary = *config_params_;
+ LongStringDictionary& dictionary = *config_params_;
dictionary.SetKeyValue(BREAKPAD_SERVER_TYPE, [serverType UTF8String]);
dictionary.SetKeyValue(BREAKPAD_PRODUCT_DISPLAY, [display UTF8String]);
@@ -407,8 +406,8 @@ bool Breakpad::ExtractParameters(NSDictionary *parameters) {
if (serverParameters) {
// For each key-value pair, call BreakpadAddUploadParameter()
- NSEnumerator *keyEnumerator = [serverParameters keyEnumerator];
- NSString *aParameter;
+ NSEnumerator* keyEnumerator = [serverParameters keyEnumerator];
+ NSString* aParameter;
while ((aParameter = [keyEnumerator nextObject])) {
BreakpadAddUploadParameter(this, aParameter,
[serverParameters objectForKey:aParameter]);
@@ -418,7 +417,7 @@ bool Breakpad::ExtractParameters(NSDictionary *parameters) {
}
//=============================================================================
-void Breakpad::SetKeyValue(NSString *key, NSString *value) {
+void Breakpad::SetKeyValue(NSString* key, NSString* value) {
// We allow nil values. This is the same as removing the keyvalue.
if (!config_params_ || !key)
return;
@@ -427,7 +426,7 @@ void Breakpad::SetKeyValue(NSString *key, NSString *value) {
}
//=============================================================================
-NSString *Breakpad::KeyValue(NSString *key) {
+NSString* Breakpad::KeyValue(NSString* key) {
if (!config_params_ || !key)
return nil;
@@ -436,44 +435,44 @@ NSString *Breakpad::KeyValue(NSString *key) {
}
//=============================================================================
-void Breakpad::RemoveKeyValue(NSString *key) {
+void Breakpad::RemoveKeyValue(NSString* key) {
if (!config_params_ || !key) return;
config_params_->RemoveKey([key UTF8String]);
}
//=============================================================================
-NSArray *Breakpad::CrashReportsToUpload() {
- NSString *directory = KeyValue(@BREAKPAD_DUMP_DIRECTORY);
+NSArray* Breakpad::CrashReportsToUpload() {
+ NSString* directory = KeyValue(@BREAKPAD_DUMP_DIRECTORY);
if (!directory)
return nil;
- NSArray *dirContents = [[NSFileManager defaultManager]
+ NSArray* dirContents = [[NSFileManager defaultManager]
contentsOfDirectoryAtPath:directory error:nil];
- NSArray *configs = [dirContents filteredArrayUsingPredicate:[NSPredicate
+ NSArray* configs = [dirContents filteredArrayUsingPredicate:[NSPredicate
predicateWithFormat:@"self BEGINSWITH 'Config-'"]];
return configs;
}
//=============================================================================
-NSString *Breakpad::NextCrashReportToUpload() {
- NSString *directory = KeyValue(@BREAKPAD_DUMP_DIRECTORY);
+NSString* Breakpad::NextCrashReportToUpload() {
+ NSString* directory = KeyValue(@BREAKPAD_DUMP_DIRECTORY);
if (!directory)
return nil;
- NSString *config = [CrashReportsToUpload() lastObject];
+ NSString* config = [CrashReportsToUpload() lastObject];
if (!config)
return nil;
return [NSString stringWithFormat:@"%@/%@", directory, config];
}
//=============================================================================
-NSDictionary *Breakpad::NextCrashReportConfiguration() {
- NSDictionary *configuration = [Uploader readConfigurationDataFromFile:NextCrashReportToUpload()];
+NSDictionary* Breakpad::NextCrashReportConfiguration() {
+ NSDictionary* configuration = [Uploader readConfigurationDataFromFile:NextCrashReportToUpload()];
return FixedUpCrashReportConfiguration(configuration);
}
//=============================================================================
-NSDictionary *Breakpad::FixedUpCrashReportConfiguration(NSDictionary *configuration) {
- NSMutableDictionary *fixedConfiguration = [[configuration mutableCopy] autorelease];
+NSDictionary* Breakpad::FixedUpCrashReportConfiguration(NSDictionary* configuration) {
+ NSMutableDictionary* fixedConfiguration = [[configuration mutableCopy] autorelease];
// kReporterMinidumpDirectoryKey can become stale because the app's data container path includes
// an UUID that is not guaranteed to stay the same over time.
[fixedConfiguration setObject:KeyValue(@BREAKPAD_DUMP_DIRECTORY)
@@ -482,19 +481,19 @@ NSDictionary *Breakpad::FixedUpCrashReportConfiguration(NSDictionary *configurat
}
//=============================================================================
-NSDate *Breakpad::DateOfMostRecentCrashReport() {
- NSString *directory = KeyValue(@BREAKPAD_DUMP_DIRECTORY);
+NSDate* Breakpad::DateOfMostRecentCrashReport() {
+ NSString* directory = KeyValue(@BREAKPAD_DUMP_DIRECTORY);
if (!directory) {
return nil;
}
- NSFileManager *fileManager = [NSFileManager defaultManager];
- NSArray *dirContents = [fileManager contentsOfDirectoryAtPath:directory error:nil];
- NSArray *dumps = [dirContents filteredArrayUsingPredicate:[NSPredicate
+ NSFileManager* fileManager = [NSFileManager defaultManager];
+ NSArray* dirContents = [fileManager contentsOfDirectoryAtPath:directory error:nil];
+ NSArray* dumps = [dirContents filteredArrayUsingPredicate:[NSPredicate
predicateWithFormat:@"self ENDSWITH '.dmp'"]];
- NSDate *mostRecentCrashReportDate = nil;
- for (NSString *dump in dumps) {
- NSString *filePath = [directory stringByAppendingPathComponent:dump];
- NSDate *crashReportDate =
+ NSDate* mostRecentCrashReportDate = nil;
+ for (NSString* dump in dumps) {
+ NSString* filePath = [directory stringByAppendingPathComponent:dump];
+ NSDate* crashReportDate =
[[fileManager attributesOfItemAtPath:filePath error:nil] fileCreationDate];
if (!mostRecentCrashReportDate) {
mostRecentCrashReportDate = crashReportDate;
@@ -506,29 +505,29 @@ NSDate *Breakpad::DateOfMostRecentCrashReport() {
}
//=============================================================================
-void Breakpad::HandleNetworkResponse(NSDictionary *configuration,
- NSData *data,
- NSError *error) {
- Uploader *uploader = [[[Uploader alloc]
+void Breakpad::HandleNetworkResponse(NSDictionary* configuration,
+ NSData* data,
+ NSError* error) {
+ Uploader* uploader = [[[Uploader alloc]
initWithConfig:configuration] autorelease];
[uploader handleNetworkResponse:data withError:error];
}
//=============================================================================
void Breakpad::UploadReportWithConfiguration(
- NSDictionary *configuration,
- NSDictionary *server_parameters,
+ NSDictionary* configuration,
+ NSDictionary* server_parameters,
BreakpadUploadCompletionCallback callback) {
- Uploader *uploader = [[[Uploader alloc]
+ Uploader* uploader = [[[Uploader alloc]
initWithConfig:configuration] autorelease];
if (!uploader)
return;
- for (NSString *key in server_parameters) {
+ for (NSString* key in server_parameters) {
[uploader addServerParameter:[server_parameters objectForKey:key]
forKey:key];
}
if (callback) {
- [uploader setUploadCompletionBlock:^(NSString *report_id, NSError *error) {
+ [uploader setUploadCompletionBlock:^(NSString* report_id, NSError* error) {
dispatch_async(dispatch_get_main_queue(), ^{
callback(report_id, error);
});
@@ -538,8 +537,8 @@ void Breakpad::UploadReportWithConfiguration(
}
//=============================================================================
-void Breakpad::UploadNextReport(NSDictionary *server_parameters) {
- NSDictionary *configuration = NextCrashReportConfiguration();
+void Breakpad::UploadNextReport(NSDictionary* server_parameters) {
+ NSDictionary* configuration = NextCrashReportConfiguration();
if (configuration) {
return UploadReportWithConfiguration(configuration, server_parameters,
nullptr);
@@ -547,19 +546,19 @@ void Breakpad::UploadNextReport(NSDictionary *server_parameters) {
}
//=============================================================================
-void Breakpad::UploadData(NSData *data, NSString *name,
- NSDictionary *server_parameters) {
- NSMutableDictionary *config = [NSMutableDictionary dictionary];
+void Breakpad::UploadData(NSData* data, NSString* name,
+ NSDictionary* server_parameters) {
+ NSMutableDictionary* config = [NSMutableDictionary dictionary];
LongStringDictionary::Iterator it(*config_params_);
- while (const LongStringDictionary::Entry *next = it.Next()) {
+ while (const LongStringDictionary::Entry* next = it.Next()) {
[config setValue:[NSString stringWithUTF8String:next->value]
forKey:[NSString stringWithUTF8String:next->key]];
}
- Uploader *uploader =
+ Uploader* uploader =
[[[Uploader alloc] initWithConfig:config] autorelease];
- for (NSString *key in server_parameters) {
+ for (NSString* key in server_parameters) {
[uploader addServerParameter:[server_parameters objectForKey:key]
forKey:key];
}
@@ -567,11 +566,11 @@ void Breakpad::UploadData(NSData *data, NSString *name,
}
//=============================================================================
-NSDictionary *Breakpad::GenerateReport(NSDictionary *server_parameters) {
- NSString *dumpDirAsNSString = KeyValue(@BREAKPAD_DUMP_DIRECTORY);
+NSDictionary* Breakpad::GenerateReport(NSDictionary* server_parameters) {
+ NSString* dumpDirAsNSString = KeyValue(@BREAKPAD_DUMP_DIRECTORY);
if (!dumpDirAsNSString)
return nil;
- const char *dumpDir = [dumpDirAsNSString UTF8String];
+ const char* dumpDir = [dumpDirAsNSString UTF8String];
google_breakpad::MinidumpGenerator generator(mach_task_self(),
MACH_PORT_NULL);
@@ -582,7 +581,7 @@ NSDictionary *Breakpad::GenerateReport(NSDictionary *server_parameters) {
return nil;
LongStringDictionary params = *config_params_;
- for (NSString *key in server_parameters) {
+ for (NSString* key in server_parameters) {
params.SetKeyValue([key UTF8String],
[[server_parameters objectForKey:key] UTF8String]);
}
@@ -590,8 +589,8 @@ NSDictionary *Breakpad::GenerateReport(NSDictionary *server_parameters) {
config_file.WriteFile(dumpDir, &params, dumpDir, dumpId.c_str());
// Handle results.
- NSMutableDictionary *result = [NSMutableDictionary dictionary];
- NSString *dumpFullPath = [NSString stringWithUTF8String:dumpFilename.c_str()];
+ NSMutableDictionary* result = [NSMutableDictionary dictionary];
+ NSString* dumpFullPath = [NSString stringWithUTF8String:dumpFilename.c_str()];
[result setValue:dumpFullPath
forKey:@BREAKPAD_OUTPUT_DUMP_FILE];
[result setValue:[NSString stringWithUTF8String:config_file.GetFilePath()]
@@ -600,8 +599,8 @@ NSDictionary *Breakpad::GenerateReport(NSDictionary *server_parameters) {
}
//=============================================================================
-bool Breakpad::HandleMinidump(const char *dump_dir,
- const char *minidump_id) {
+bool Breakpad::HandleMinidump(const char* dump_dir,
+ const char* minidump_id) {
config_file_.WriteFile(dump_dir,
config_params_,
dump_dir,
@@ -613,7 +612,7 @@ bool Breakpad::HandleMinidump(const char *dump_dir,
}
//=============================================================================
-void Breakpad::HandleUncaughtException(NSException *exception) {
+void Breakpad::HandleUncaughtException(NSException* exception) {
// Generate the minidump.
google_breakpad::IosExceptionMinidumpGenerator generator(exception);
const std::string minidump_path =
@@ -650,7 +649,7 @@ void Breakpad::HandleUncaughtException(NSException *exception) {
#pragma mark Public API
//=============================================================================
-BreakpadRef BreakpadCreate(NSDictionary *parameters) {
+BreakpadRef BreakpadCreate(NSDictionary* parameters) {
try {
// This is confusing. Our two main allocators for breakpad memory are:
// - gKeyValueAllocator for the key/value memory
@@ -690,8 +689,8 @@ BreakpadRef BreakpadCreate(NSDictionary *parameters) {
ProtectedMemoryAllocator(breakpad_pool_size);
// Stack-based autorelease pool for Breakpad::Create() obj-c code.
- NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
- Breakpad *breakpad = Breakpad::Create(parameters);
+ NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
+ Breakpad* breakpad = Breakpad::Create(parameters);
if (breakpad) {
// Make read-only to protect against memory smashers
@@ -731,7 +730,7 @@ BreakpadRef BreakpadCreate(NSDictionary *parameters) {
//=============================================================================
void BreakpadRelease(BreakpadRef ref) {
try {
- Breakpad *breakpad = (Breakpad *)ref;
+ Breakpad* breakpad = (Breakpad*)ref;
if (gMasterAllocator) {
gMasterAllocator->Unprotect();
@@ -764,10 +763,10 @@ void BreakpadRelease(BreakpadRef ref) {
}
//=============================================================================
-void BreakpadSetKeyValue(BreakpadRef ref, NSString *key, NSString *value) {
+void BreakpadSetKeyValue(BreakpadRef ref, NSString* key, NSString* value) {
try {
// Not called at exception time
- Breakpad *breakpad = (Breakpad *)ref;
+ Breakpad* breakpad = (Breakpad*)ref;
if (breakpad && key && gKeyValueAllocator) {
ProtectedMemoryLocker locker(&gDictionaryMutex, gKeyValueAllocator);
@@ -780,20 +779,20 @@ void BreakpadSetKeyValue(BreakpadRef ref, NSString *key, NSString *value) {
}
void BreakpadAddUploadParameter(BreakpadRef ref,
- NSString *key,
- NSString *value) {
+ NSString* key,
+ NSString* value) {
// The only difference, internally, between an upload parameter and
// a key value one that is set with BreakpadSetKeyValue is that we
// prepend the keyname with a special prefix. This informs the
// crash sender that the parameter should be sent along with the
// POST of the crash dump upload.
try {
- Breakpad *breakpad = (Breakpad *)ref;
+ Breakpad* breakpad = (Breakpad*)ref;
if (breakpad && key && gKeyValueAllocator) {
ProtectedMemoryLocker locker(&gDictionaryMutex, gKeyValueAllocator);
- NSString *prefixedKey = [@BREAKPAD_SERVER_PARAMETER_PREFIX
+ NSString* prefixedKey = [@BREAKPAD_SERVER_PARAMETER_PREFIX
stringByAppendingString:key];
breakpad->SetKeyValue(prefixedKey, value);
}
@@ -803,15 +802,15 @@ void BreakpadAddUploadParameter(BreakpadRef ref,
}
void BreakpadRemoveUploadParameter(BreakpadRef ref,
- NSString *key) {
+ NSString* key) {
try {
// Not called at exception time
- Breakpad *breakpad = (Breakpad *)ref;
+ Breakpad* breakpad = (Breakpad*)ref;
if (breakpad && key && gKeyValueAllocator) {
ProtectedMemoryLocker locker(&gDictionaryMutex, gKeyValueAllocator);
- NSString *prefixedKey = [NSString stringWithFormat:@"%@%@",
+ NSString* prefixedKey = [NSString stringWithFormat:@"%@%@",
@BREAKPAD_SERVER_PARAMETER_PREFIX, key];
breakpad->RemoveKeyValue(prefixedKey);
}
@@ -820,12 +819,12 @@ void BreakpadRemoveUploadParameter(BreakpadRef ref,
}
}
//=============================================================================
-NSString *BreakpadKeyValue(BreakpadRef ref, NSString *key) {
- NSString *value = nil;
+NSString* BreakpadKeyValue(BreakpadRef ref, NSString* key) {
+ NSString* value = nil;
try {
// Not called at exception time
- Breakpad *breakpad = (Breakpad *)ref;
+ Breakpad* breakpad = (Breakpad*)ref;
if (!breakpad || !key || !gKeyValueAllocator)
return nil;
@@ -841,10 +840,10 @@ NSString *BreakpadKeyValue(BreakpadRef ref, NSString *key) {
}
//=============================================================================
-void BreakpadRemoveKeyValue(BreakpadRef ref, NSString *key) {
+void BreakpadRemoveKeyValue(BreakpadRef ref, NSString* key) {
try {
// Not called at exception time
- Breakpad *breakpad = (Breakpad *)ref;
+ Breakpad* breakpad = (Breakpad*)ref;
if (breakpad && key && gKeyValueAllocator) {
ProtectedMemoryLocker locker(&gDictionaryMutex, gKeyValueAllocator);
@@ -860,7 +859,7 @@ void BreakpadRemoveKeyValue(BreakpadRef ref, NSString *key) {
int BreakpadGetCrashReportCount(BreakpadRef ref) {
try {
// Not called at exception time
- Breakpad *breakpad = (Breakpad *)ref;
+ Breakpad* breakpad = (Breakpad*)ref;
if (breakpad) {
return static_cast<int>([breakpad->CrashReportsToUpload() count]);
@@ -877,9 +876,9 @@ void BreakpadUploadNextReport(BreakpadRef ref) {
}
//=============================================================================
-NSDictionary *BreakpadGetNextReportConfiguration(BreakpadRef ref) {
+NSDictionary* BreakpadGetNextReportConfiguration(BreakpadRef ref) {
try {
- Breakpad *breakpad = (Breakpad *)ref;
+ Breakpad* breakpad = (Breakpad*)ref;
if (breakpad)
return breakpad->NextCrashReportConfiguration();
} catch(...) { // don't let exceptions leave this C API
@@ -889,9 +888,9 @@ NSDictionary *BreakpadGetNextReportConfiguration(BreakpadRef ref) {
}
//=============================================================================
-NSDate *BreakpadGetDateOfMostRecentCrashReport(BreakpadRef ref) {
+NSDate* BreakpadGetDateOfMostRecentCrashReport(BreakpadRef ref) {
try {
- Breakpad *breakpad = (Breakpad *)ref;
+ Breakpad* breakpad = (Breakpad*)ref;
if (breakpad) {
return breakpad->DateOfMostRecentCrashReport();
}
@@ -904,11 +903,11 @@ NSDate *BreakpadGetDateOfMostRecentCrashReport(BreakpadRef ref) {
//=============================================================================
void BreakpadUploadReportWithParametersAndConfiguration(
BreakpadRef ref,
- NSDictionary *server_parameters,
- NSDictionary *configuration,
+ NSDictionary* server_parameters,
+ NSDictionary* configuration,
BreakpadUploadCompletionCallback callback) {
try {
- Breakpad *breakpad = (Breakpad *)ref;
+ Breakpad* breakpad = (Breakpad*)ref;
if (!breakpad || !configuration)
return;
breakpad->UploadReportWithConfiguration(configuration, server_parameters,
@@ -922,13 +921,13 @@ void BreakpadUploadReportWithParametersAndConfiguration(
//=============================================================================
void BreakpadUploadNextReportWithParameters(
BreakpadRef ref,
- NSDictionary *server_parameters,
+ NSDictionary* server_parameters,
BreakpadUploadCompletionCallback callback) {
try {
- Breakpad *breakpad = (Breakpad *)ref;
+ Breakpad* breakpad = (Breakpad*)ref;
if (!breakpad)
return;
- NSDictionary *configuration = breakpad->NextCrashReportConfiguration();
+ NSDictionary* configuration = breakpad->NextCrashReportConfiguration();
if (!configuration)
return;
return BreakpadUploadReportWithParametersAndConfiguration(
@@ -939,12 +938,12 @@ void BreakpadUploadNextReportWithParameters(
}
void BreakpadHandleNetworkResponse(BreakpadRef ref,
- NSDictionary *configuration,
- NSData *data,
- NSError *error) {
+ NSDictionary* configuration,
+ NSData* data,
+ NSError* error) {
try {
// Not called at exception time
- Breakpad *breakpad = (Breakpad *)ref;
+ Breakpad* breakpad = (Breakpad*)ref;
if (breakpad && configuration)
breakpad->HandleNetworkResponse(configuration,data, error);
@@ -954,11 +953,11 @@ void BreakpadHandleNetworkResponse(BreakpadRef ref,
}
//=============================================================================
-void BreakpadUploadData(BreakpadRef ref, NSData *data, NSString *name,
- NSDictionary *server_parameters) {
+void BreakpadUploadData(BreakpadRef ref, NSData* data, NSString* name,
+ NSDictionary* server_parameters) {
try {
// Not called at exception time
- Breakpad *breakpad = (Breakpad *)ref;
+ Breakpad* breakpad = (Breakpad*)ref;
if (breakpad) {
breakpad->UploadData(data, name, server_parameters);
@@ -969,11 +968,11 @@ void BreakpadUploadData(BreakpadRef ref, NSData *data, NSString *name,
}
//=============================================================================
-NSDictionary *BreakpadGenerateReport(BreakpadRef ref,
- NSDictionary *server_parameters) {
+NSDictionary* BreakpadGenerateReport(BreakpadRef ref,
+ NSDictionary* server_parameters) {
try {
// Not called at exception time
- Breakpad *breakpad = (Breakpad *)ref;
+ Breakpad* breakpad = (Breakpad*)ref;
if (breakpad) {
return breakpad->GenerateReport(server_parameters);
diff --git a/src/client/ios/Breakpad.xcodeproj/project.pbxproj b/src/client/ios/Breakpad.xcodeproj/project.pbxproj
index 2ed66d53..ca5f1f05 100644
--- a/src/client/ios/Breakpad.xcodeproj/project.pbxproj
+++ b/src/client/ios/Breakpad.xcodeproj/project.pbxproj
@@ -7,6 +7,8 @@
objects = {
/* Begin PBXBuildFile section */
+ 06D561E62700974500F9F2E8 /* encoding_util.h in Headers */ = {isa = PBXBuildFile; fileRef = 06D561E42700974500F9F2E8 /* encoding_util.h */; };
+ 06D561E72700974500F9F2E8 /* encoding_util.m in Sources */ = {isa = PBXBuildFile; fileRef = 06D561E52700974500F9F2E8 /* encoding_util.m */; };
14569321182CE29F0029C465 /* ucontext_compat.h in Headers */ = {isa = PBXBuildFile; fileRef = 14569320182CE29F0029C465 /* ucontext_compat.h */; };
14569323182CE2C10029C465 /* mach_vm_compat.h in Headers */ = {isa = PBXBuildFile; fileRef = 14569322182CE2C10029C465 /* mach_vm_compat.h */; };
16BFA67014E195E9009704F8 /* ios_exception_minidump_generator.h in Headers */ = {isa = PBXBuildFile; fileRef = 16BFA66E14E195E9009704F8 /* ios_exception_minidump_generator.h */; };
@@ -59,9 +61,13 @@
AACBBE4A0F95108600F1A2B1 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AACBBE490F95108600F1A2B1 /* Foundation.framework */; };
CF6D547D1F9E6FFE00E95174 /* long_string_dictionary.cc in Sources */ = {isa = PBXBuildFile; fileRef = CF6D547C1F9E6FFE00E95174 /* long_string_dictionary.cc */; };
CF706DC11F7C6EFB002C54C7 /* long_string_dictionary.h in Headers */ = {isa = PBXBuildFile; fileRef = CF706DC01F7C6EFB002C54C7 /* long_string_dictionary.h */; };
+ E69213D8265202570071B04F /* HTTPRequest.h in Headers */ = {isa = PBXBuildFile; fileRef = E69213D6265202570071B04F /* HTTPRequest.h */; };
+ E69213D9265202570071B04F /* HTTPRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = E69213D7265202570071B04F /* HTTPRequest.m */; };
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
+ 06D561E42700974500F9F2E8 /* encoding_util.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = encoding_util.h; sourceTree = "<group>"; };
+ 06D561E52700974500F9F2E8 /* encoding_util.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = encoding_util.m; sourceTree = "<group>"; };
14569320182CE29F0029C465 /* ucontext_compat.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ucontext_compat.h; sourceTree = "<group>"; };
14569322182CE2C10029C465 /* mach_vm_compat.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mach_vm_compat.h; sourceTree = "<group>"; };
16BFA66E14E195E9009704F8 /* ios_exception_minidump_generator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ios_exception_minidump_generator.h; sourceTree = "<group>"; };
@@ -116,6 +122,8 @@
CF6D547C1F9E6FFE00E95174 /* long_string_dictionary.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = long_string_dictionary.cc; sourceTree = "<group>"; };
CF706DC01F7C6EFB002C54C7 /* long_string_dictionary.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = long_string_dictionary.h; sourceTree = "<group>"; };
D2AAC07E0554694100DB518D /* libBreakpad.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libBreakpad.a; sourceTree = BUILT_PRODUCTS_DIR; };
+ E69213D6265202570071B04F /* HTTPRequest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HTTPRequest.h; sourceTree = "<group>"; };
+ E69213D7265202570071B04F /* HTTPRequest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HTTPRequest.m; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@@ -287,8 +295,12 @@
16C7CC82147D4A4300776EAD /* mac */ = {
isa = PBXGroup;
children = (
+ 06D561E42700974500F9F2E8 /* encoding_util.h */,
+ 06D561E52700974500F9F2E8 /* encoding_util.m */,
16C7CC88147D4A4300776EAD /* GTMLogger.h */,
16C7CC89147D4A4300776EAD /* GTMLogger.m */,
+ E69213D6265202570071B04F /* HTTPRequest.h */,
+ E69213D7265202570071B04F /* HTTPRequest.m */,
16C7CC8A147D4A4300776EAD /* HTTPMultipartUpload.h */,
16C7CC8B147D4A4300776EAD /* HTTPMultipartUpload.m */,
16C7CC93147D4A4300776EAD /* file_id.cc */,
@@ -333,8 +345,10 @@
16C7CE08147D4A4300776EAD /* uploader.h in Headers */,
16C7CE18147D4A4300776EAD /* minidump_file_writer-inl.h in Headers */,
16C7CE1A147D4A4300776EAD /* minidump_file_writer.h in Headers */,
+ 06D561E62700974500F9F2E8 /* encoding_util.h in Headers */,
16C7CE41147D4A4300776EAD /* convert_UTF.h in Headers */,
16C7CE78147D4A4300776EAD /* GTMLogger.h in Headers */,
+ E69213D8265202570071B04F /* HTTPRequest.h in Headers */,
16C7CE7A147D4A4300776EAD /* HTTPMultipartUpload.h in Headers */,
16C7CE84147D4A4300776EAD /* file_id.h in Headers */,
16C7CE86147D4A4300776EAD /* macho_id.h in Headers */,
@@ -416,6 +430,7 @@
buildActionMask = 2147483647;
files = (
16C7CCCD147D4A4300776EAD /* Breakpad.mm in Sources */,
+ E69213D9265202570071B04F /* HTTPRequest.m in Sources */,
16C7CDE9147D4A4300776EAD /* ConfigFile.mm in Sources */,
16C7CDF5147D4A4300776EAD /* breakpad_nlist_64.cc in Sources */,
16C7CDF7147D4A4300776EAD /* dynamic_images.cc in Sources */,
@@ -427,6 +442,7 @@
16C7CE19147D4A4300776EAD /* minidump_file_writer.cc in Sources */,
16C7CE40147D4A4300776EAD /* convert_UTF.cc in Sources */,
16C7CE79147D4A4300776EAD /* GTMLogger.m in Sources */,
+ 06D561E72700974500F9F2E8 /* encoding_util.m in Sources */,
16C7CE7B147D4A4300776EAD /* HTTPMultipartUpload.m in Sources */,
16C7CE83147D4A4300776EAD /* file_id.cc in Sources */,
16C7CE85147D4A4300776EAD /* macho_id.cc in Sources */,
diff --git a/src/client/ios/BreakpadController.h b/src/client/ios/BreakpadController.h
index 6c70c202..40334592 100644
--- a/src/client/ios/BreakpadController.h
+++ b/src/client/ios/BreakpadController.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2012, Google Inc.
-// All rights reserved.
+// Copyright 2012 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/client/ios/BreakpadController.mm b/src/client/ios/BreakpadController.mm
index 01fb5f13..d03833e9 100644
--- a/src/client/ios/BreakpadController.mm
+++ b/src/client/ios/BreakpadController.mm
@@ -1,5 +1,4 @@
-// Copyright (c) 2012, Google Inc.
-// All rights reserved.
+// Copyright 2012 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/client/ios/exception_handler_no_mach.cc b/src/client/ios/exception_handler_no_mach.cc
index 7fcf2d83..6bb41021 100644
--- a/src/client/ios/exception_handler_no_mach.cc
+++ b/src/client/ios/exception_handler_no_mach.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2006, Google Inc.
-// All rights reserved.
+// Copyright 2006 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -47,7 +46,7 @@
// for more details.
#if USE_PROTECTED_ALLOCATIONS
#include "client/mac/handler/protected_memory_allocator.h"
- extern ProtectedMemoryAllocator *gBreakpadAllocator;
+ extern ProtectedMemoryAllocator* gBreakpadAllocator;
#endif
namespace google_breakpad {
@@ -72,10 +71,10 @@ static union {
char protected_buffer[PAGE_SIZE] __attribute__((aligned(PAGE_SIZE)));
#endif // defined PAGE_MAX_SIZE
#endif // USE_PROTECTED_ALLOCATIONS
- google_breakpad::ExceptionHandler *handler;
+ google_breakpad::ExceptionHandler* handler;
} gProtectedData;
-ExceptionHandler::ExceptionHandler(const string &dump_path,
+ExceptionHandler::ExceptionHandler(const string& dump_path,
FilterCallback filter,
MinidumpCallback callback,
void* callback_context,
diff --git a/src/client/ios/exception_handler_no_mach.h b/src/client/ios/exception_handler_no_mach.h
index 6d99565b..57247e61 100644
--- a/src/client/ios/exception_handler_no_mach.h
+++ b/src/client/ios/exception_handler_no_mach.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2006, Google Inc.
-// All rights reserved.
+// Copyright 2006 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -53,7 +52,7 @@ class ExceptionHandler {
// attempting to write a minidump. If a FilterCallback returns false, Breakpad
// will immediately report the exception as unhandled without writing a
// minidump, allowing another handler the opportunity to handle it.
- typedef bool (*FilterCallback)(void *context);
+ typedef bool (*FilterCallback)(void* context);
// A callback function to run after the minidump has been written.
// |minidump_id| is a unique id for the dump, so the minidump
@@ -63,18 +62,18 @@ class ExceptionHandler {
// Return true if the exception was fully handled and breakpad should exit.
// Return false to allow any other exception handlers to process the
// exception.
- typedef bool (*MinidumpCallback)(const char *dump_dir,
- const char *minidump_id,
- void *context, bool succeeded);
+ typedef bool (*MinidumpCallback)(const char* dump_dir,
+ const char* minidump_id,
+ void* context, bool succeeded);
// A callback function which will be called directly if an exception occurs.
// This bypasses the minidump file writing and simply gives the client
// the exception information.
- typedef bool (*DirectCallback)( void *context,
- int exception_type,
- int exception_code,
- int exception_subcode,
- mach_port_t thread_name);
+ typedef bool (*DirectCallback)(void* context,
+ int exception_type,
+ int exception_code,
+ int exception_subcode,
+ mach_port_t thread_name);
// Creates a new ExceptionHandler instance to handle writing minidumps.
// Minidump files will be written to dump_path, and the optional callback
@@ -84,22 +83,22 @@ class ExceptionHandler {
// be written when WriteMinidump is called.
// If port_name is non-NULL, attempt to perform out-of-process dump generation
// If port_name is NULL, in-process dump generation will be used.
- ExceptionHandler(const string &dump_path,
+ ExceptionHandler(const string& dump_path,
FilterCallback filter, MinidumpCallback callback,
- void *callback_context, bool install_handler,
- const char *port_name);
+ void* callback_context, bool install_handler,
+ const char* port_name);
// A special constructor if we want to bypass minidump writing and
// simply get a callback with the exception information.
ExceptionHandler(DirectCallback callback,
- void *callback_context,
+ void* callback_context,
bool install_handler);
~ExceptionHandler();
// Get and set the minidump path.
string dump_path() const { return dump_path_; }
- void set_dump_path(const string &dump_path) {
+ void set_dump_path(const string& dump_path) {
dump_path_ = dump_path;
dump_path_c_ = dump_path_.c_str();
UpdateNextID(); // Necessary to put dump_path_ in next_minidump_path_.
@@ -126,7 +125,7 @@ class ExceptionHandler {
bool WriteMinidumpWithException(int exception_type,
int exception_code,
int exception_subcode,
- breakpad_ucontext_t *task_context,
+ breakpad_ucontext_t* task_context,
mach_port_t thread_name,
bool exit_after_write,
bool report_current_thread);
@@ -135,8 +134,8 @@ class ExceptionHandler {
static void SignalHandler(int sig, siginfo_t* info, void* uc);
// disallow copy ctor and operator=
- explicit ExceptionHandler(const ExceptionHandler &);
- void operator=(const ExceptionHandler &);
+ explicit ExceptionHandler(const ExceptionHandler&);
+ void operator=(const ExceptionHandler&);
// Generates a new ID and stores it in next_minidump_id_, and stores the
// path of the next minidump to be written in next_minidump_path_.
@@ -152,15 +151,15 @@ class ExceptionHandler {
string next_minidump_path_;
// Pointers to the UTF-8 versions of above
- const char *dump_path_c_;
- const char *next_minidump_id_c_;
- const char *next_minidump_path_c_;
+ const char* dump_path_c_;
+ const char* next_minidump_id_c_;
+ const char* next_minidump_path_c_;
// The callback function and pointer to be passed back after the minidump
// has been written
FilterCallback filter_;
MinidumpCallback callback_;
- void *callback_context_;
+ void* callback_context_;
// The callback function to be passed back when we don't want a minidump
// file to be written
diff --git a/src/client/ios/handler/ios_exception_minidump_generator.h b/src/client/ios/handler/ios_exception_minidump_generator.h
index 21133e63..cf72f00b 100644
--- a/src/client/ios/handler/ios_exception_minidump_generator.h
+++ b/src/client/ios/handler/ios_exception_minidump_generator.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2012, Google Inc.
-// All rights reserved.
+// Copyright 2012 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -41,12 +40,12 @@ namespace google_breakpad {
class IosExceptionMinidumpGenerator : public MinidumpGenerator {
public:
- explicit IosExceptionMinidumpGenerator(NSException *exception);
+ explicit IosExceptionMinidumpGenerator(NSException* exception);
virtual ~IosExceptionMinidumpGenerator();
protected:
- virtual bool WriteExceptionStream(MDRawDirectory *exception_stream);
- virtual bool WriteThreadStream(mach_port_t thread_id, MDRawThread *thread);
+ virtual bool WriteExceptionStream(MDRawDirectory* exception_stream);
+ virtual bool WriteThreadStream(mach_port_t thread_id, MDRawThread* thread);
private:
@@ -57,16 +56,16 @@ class IosExceptionMinidumpGenerator : public MinidumpGenerator {
uintptr_t GetLRFromException();
// Write a virtual thread context for the crashing site.
- bool WriteCrashingContext(MDLocationDescriptor *register_location);
+ bool WriteCrashingContext(MDLocationDescriptor* register_location);
// Per-CPU implementations of the above method.
#ifdef HAS_ARM_SUPPORT
- bool WriteCrashingContextARM(MDLocationDescriptor *register_location);
+ bool WriteCrashingContextARM(MDLocationDescriptor* register_location);
#endif
#ifdef HAS_ARM64_SUPPORT
- bool WriteCrashingContextARM64(MDLocationDescriptor *register_location);
+ bool WriteCrashingContextARM64(MDLocationDescriptor* register_location);
#endif
- NSArray *return_addresses_;
+ NSArray* return_addresses_;
};
} // namespace google_breakpad
diff --git a/src/client/ios/handler/ios_exception_minidump_generator.mm b/src/client/ios/handler/ios_exception_minidump_generator.mm
index f57bdf21..053e3671 100644
--- a/src/client/ios/handler/ios_exception_minidump_generator.mm
+++ b/src/client/ios/handler/ios_exception_minidump_generator.mm
@@ -1,5 +1,4 @@
-// Copyright (c) 2012, Google Inc.
-// All rights reserved.
+// Copyright 2012 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -52,7 +51,7 @@ const uintptr_t kExpectedFinalSp = 0;
// Append the given value to the sp position of the stack represented
// by memory.
-void AppendToMemory(uint8_t *memory, uintptr_t sp, uintptr_t data) {
+void AppendToMemory(uint8_t* memory, uintptr_t sp, uintptr_t data) {
memcpy(memory + sp, &data, sizeof(data));
}
#endif
@@ -62,7 +61,7 @@ void AppendToMemory(uint8_t *memory, uintptr_t sp, uintptr_t data) {
namespace google_breakpad {
IosExceptionMinidumpGenerator::IosExceptionMinidumpGenerator(
- NSException *exception)
+ NSException* exception)
: MinidumpGenerator(mach_task_self(), 0) {
return_addresses_ = [[exception callStackReturnAddresses] retain];
SetExceptionInformation(kExceptionType,
@@ -76,7 +75,7 @@ IosExceptionMinidumpGenerator::~IosExceptionMinidumpGenerator() {
}
bool IosExceptionMinidumpGenerator::WriteCrashingContext(
- MDLocationDescriptor *register_location) {
+ MDLocationDescriptor* register_location) {
#ifdef HAS_ARM_SUPPORT
return WriteCrashingContextARM(register_location);
#elif defined(HAS_ARM64_SUPPORT)
@@ -89,12 +88,12 @@ bool IosExceptionMinidumpGenerator::WriteCrashingContext(
#ifdef HAS_ARM_SUPPORT
bool IosExceptionMinidumpGenerator::WriteCrashingContextARM(
- MDLocationDescriptor *register_location) {
+ MDLocationDescriptor* register_location) {
TypedMDRVA<MDRawContextARM> context(&writer_);
if (!context.Allocate())
return false;
*register_location = context.location();
- MDRawContextARM *context_ptr = context.get();
+ MDRawContextARM* context_ptr = context.get();
memset(context_ptr, 0, sizeof(MDRawContextARM));
context_ptr->context_flags = MD_CONTEXT_ARM_FULL;
context_ptr->iregs[MD_CONTEXT_ARM_REG_IOS_FP] = kExpectedFinalFp; // FP
@@ -107,12 +106,12 @@ bool IosExceptionMinidumpGenerator::WriteCrashingContextARM(
#ifdef HAS_ARM64_SUPPORT
bool IosExceptionMinidumpGenerator::WriteCrashingContextARM64(
- MDLocationDescriptor *register_location) {
+ MDLocationDescriptor* register_location) {
TypedMDRVA<MDRawContextARM64_Old> context(&writer_);
if (!context.Allocate())
return false;
*register_location = context.location();
- MDRawContextARM64_Old *context_ptr = context.get();
+ MDRawContextARM64_Old* context_ptr = context.get();
memset(context_ptr, 0, sizeof(*context_ptr));
context_ptr->context_flags = MD_CONTEXT_ARM64_FULL_OLD;
context_ptr->iregs[MD_CONTEXT_ARM64_REG_FP] = kExpectedFinalFp; // FP
@@ -132,7 +131,7 @@ uintptr_t IosExceptionMinidumpGenerator::GetLRFromException() {
}
bool IosExceptionMinidumpGenerator::WriteExceptionStream(
- MDRawDirectory *exception_stream) {
+ MDRawDirectory* exception_stream) {
#if defined(HAS_ARM_SUPPORT) || defined(HAS_ARM64_SUPPORT)
TypedMDRVA<MDRawExceptionStream> exception(&writer_);
@@ -141,7 +140,7 @@ bool IosExceptionMinidumpGenerator::WriteExceptionStream(
exception_stream->stream_type = MD_EXCEPTION_STREAM;
exception_stream->location = exception.location();
- MDRawExceptionStream *exception_ptr = exception.get();
+ MDRawExceptionStream* exception_ptr = exception.get();
exception_ptr->thread_id = pthread_mach_thread_np(pthread_self());
// This naming is confusing, but it is the proper translation from
@@ -160,7 +159,7 @@ bool IosExceptionMinidumpGenerator::WriteExceptionStream(
}
bool IosExceptionMinidumpGenerator::WriteThreadStream(mach_port_t thread_id,
- MDRawThread *thread) {
+ MDRawThread* thread) {
#if defined(HAS_ARM_SUPPORT) || defined(HAS_ARM64_SUPPORT)
if (pthread_mach_thread_np(pthread_self()) != thread_id)
return MinidumpGenerator::WriteThreadStream(thread_id, thread);
diff --git a/src/client/linux/crash_generation/client_info.h b/src/client/linux/crash_generation/client_info.h
index d0a184a6..6c4ecc3f 100644
--- a/src/client/linux/crash_generation/client_info.h
+++ b/src/client/linux/crash_generation/client_info.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2010 Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/client/linux/crash_generation/crash_generation_client.cc b/src/client/linux/crash_generation/crash_generation_client.cc
index 613baddc..5a8c6b4c 100644
--- a/src/client/linux/crash_generation/crash_generation_client.cc
+++ b/src/client/linux/crash_generation/crash_generation_client.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2010 Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -58,7 +57,7 @@ class CrashGenerationClientImpl : public CrashGenerationClient {
iov.iov_base = const_cast<void*>(blob);
iov.iov_len = blob_size;
- struct kernel_msghdr msg = {};
+ struct kernel_msghdr msg = { 0 };
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
char cmsg[kControlMsgSize] = "";
diff --git a/src/client/linux/crash_generation/crash_generation_client.h b/src/client/linux/crash_generation/crash_generation_client.h
index 4e68424a..915b5700 100644
--- a/src/client/linux/crash_generation/crash_generation_client.h
+++ b/src/client/linux/crash_generation/crash_generation_client.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2010 Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/client/linux/crash_generation/crash_generation_server.cc b/src/client/linux/crash_generation/crash_generation_server.cc
index 26c50a5c..56cc0cd7 100644
--- a/src/client/linux/crash_generation/crash_generation_server.cc
+++ b/src/client/linux/crash_generation/crash_generation_server.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2010 Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -229,7 +228,7 @@ CrashGenerationServer::ClientEvent(short revents)
// Walk the control payload and extract the file descriptor and validated pid.
pid_t crashing_pid = -1;
int signal_fd = -1;
- for (struct cmsghdr *hdr = CMSG_FIRSTHDR(&msg); hdr;
+ for (struct cmsghdr* hdr = CMSG_FIRSTHDR(&msg); hdr;
hdr = CMSG_NXTHDR(&msg, hdr)) {
if (hdr->cmsg_level != SOL_SOCKET)
continue;
@@ -248,7 +247,7 @@ CrashGenerationServer::ClientEvent(short revents)
signal_fd = reinterpret_cast<int*>(CMSG_DATA(hdr))[0];
}
} else if (hdr->cmsg_type == SCM_CREDENTIALS) {
- const struct ucred *cred =
+ const struct ucred* cred =
reinterpret_cast<struct ucred*>(CMSG_DATA(hdr));
crashing_pid = cred->pid;
}
@@ -324,7 +323,7 @@ CrashGenerationServer::MakeMinidumpFilename(string& outFilename)
// static
void*
-CrashGenerationServer::ThreadMain(void *arg)
+CrashGenerationServer::ThreadMain(void* arg)
{
reinterpret_cast<CrashGenerationServer*>(arg)->Run();
return NULL;
diff --git a/src/client/linux/crash_generation/crash_generation_server.h b/src/client/linux/crash_generation/crash_generation_server.h
index 483fb709..5f4cb3a7 100644
--- a/src/client/linux/crash_generation/crash_generation_server.h
+++ b/src/client/linux/crash_generation/crash_generation_server.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2010 Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/client/linux/dump_writer_common/mapping_info.h b/src/client/linux/dump_writer_common/mapping_info.h
index c09e48ab..759e7338 100644
--- a/src/client/linux/dump_writer_common/mapping_info.h
+++ b/src/client/linux/dump_writer_common/mapping_info.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2014, Google Inc.
-// All rights reserved.
+// Copyright 2014 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/client/linux/dump_writer_common/raw_context_cpu.h b/src/client/linux/dump_writer_common/raw_context_cpu.h
index 07d9171a..ea4b6f6a 100644
--- a/src/client/linux/dump_writer_common/raw_context_cpu.h
+++ b/src/client/linux/dump_writer_common/raw_context_cpu.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2014, Google Inc.
-// All rights reserved.
+// Copyright 2014 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -44,6 +43,14 @@ typedef MDRawContextARM RawContextCPU;
typedef MDRawContextARM64_Old RawContextCPU;
#elif defined(__mips__)
typedef MDRawContextMIPS RawContextCPU;
+#elif defined(__riscv)
+# if __riscv_xlen == 32
+typedef MDRawContextRISCV RawContextCPU;
+# elif __riscv_xlen == 64
+typedef MDRawContextRISCV64 RawContextCPU;
+# else
+# error "Unexpected __riscv_xlen"
+# endif
#else
#error "This code has not been ported to your platform yet."
#endif
diff --git a/src/client/linux/dump_writer_common/thread_info.cc b/src/client/linux/dump_writer_common/thread_info.cc
index aae1dc13..d8bf80b0 100644
--- a/src/client/linux/dump_writer_common/thread_info.cc
+++ b/src/client/linux/dump_writer_common/thread_info.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2014, Google Inc.
-// All rights reserved.
+// Copyright 2014 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -270,7 +269,74 @@ void ThreadInfo::FillCPUContext(RawContextCPU* out) const {
out->float_save.fir = mcontext.fpc_eir;
#endif
}
-#endif // __mips__
+
+#elif defined(__riscv)
+
+uintptr_t ThreadInfo::GetInstructionPointer() const {
+ return mcontext.__gregs[0];
+}
+
+void ThreadInfo::FillCPUContext(RawContextCPU* out) const {
+# if __riscv__xlen == 32
+ out->context_flags = MD_CONTEXT_RISCV_FULL;
+# elif __riscv_xlen == 64
+ out->context_flags = MD_CONTEXT_RISCV64_FULL;
+# else
+# error "Unexpected __riscv_xlen"
+# endif
+
+ out->pc = mcontext.__gregs[0];
+ out->ra = mcontext.__gregs[1];
+ out->sp = mcontext.__gregs[2];
+ out->gp = mcontext.__gregs[3];
+ out->tp = mcontext.__gregs[4];
+ out->t0 = mcontext.__gregs[5];
+ out->t1 = mcontext.__gregs[6];
+ out->t2 = mcontext.__gregs[7];
+ out->s0 = mcontext.__gregs[8];
+ out->s1 = mcontext.__gregs[9];
+ out->a0 = mcontext.__gregs[10];
+ out->a1 = mcontext.__gregs[11];
+ out->a2 = mcontext.__gregs[12];
+ out->a3 = mcontext.__gregs[13];
+ out->a4 = mcontext.__gregs[14];
+ out->a5 = mcontext.__gregs[15];
+ out->a6 = mcontext.__gregs[16];
+ out->a7 = mcontext.__gregs[17];
+ out->s2 = mcontext.__gregs[18];
+ out->s3 = mcontext.__gregs[19];
+ out->s4 = mcontext.__gregs[20];
+ out->s5 = mcontext.__gregs[21];
+ out->s6 = mcontext.__gregs[22];
+ out->s7 = mcontext.__gregs[23];
+ out->s8 = mcontext.__gregs[24];
+ out->s9 = mcontext.__gregs[25];
+ out->s10 = mcontext.__gregs[26];
+ out->s11 = mcontext.__gregs[27];
+ out->t3 = mcontext.__gregs[28];
+ out->t4 = mcontext.__gregs[29];
+ out->t5 = mcontext.__gregs[30];
+ out->t6 = mcontext.__gregs[31];
+
+# if __riscv_flen == 32
+ for(int i = 0; i < MD_FLOATINGSAVEAREA_RISCV_FPR_COUNT; i++)
+ out->float_save.regs[i] = mcontext.__fpregs.__f.__f[i];
+ out->float_save.fpcsr = mcontext.__fpregs.__f.__fcsr;
+# elif __riscv_flen == 64
+ for(int i = 0; i < MD_FLOATINGSAVEAREA_RISCV_FPR_COUNT; i++)
+ out->float_save.regs[i] = mcontext.__fpregs.__d.__f[i];
+ out->float_save.fpcsr = mcontext.__fpregs.__d.__fcsr;
+# elif __riscv_flen == 128
+ for(int i = 0; i < MD_FLOATINGSAVEAREA_RISCV_FPR_COUNT; i++) {
+ out->float_save.regs[i].high = mcontext.__fpregs.__q.__f[2*i];
+ out->float_save.regs[i].low = mcontext.__fpregs.__q.__f[2*i+1];
+ }
+ out->float_save.fpcsr = mcontext.__fpregs.__q.__fcsr;
+# else
+# error "Unexpected __riscv_flen"
+# endif
+}
+#endif // __riscv
void ThreadInfo::GetGeneralPurposeRegisters(void** gp_regs, size_t* size) {
assert(gp_regs || size);
@@ -279,6 +345,11 @@ void ThreadInfo::GetGeneralPurposeRegisters(void** gp_regs, size_t* size) {
*gp_regs = mcontext.gregs;
if (size)
*size = sizeof(mcontext.gregs);
+#elif defined(__riscv)
+ if (gp_regs)
+ *gp_regs = mcontext.__gregs;
+ if (size)
+ *size = sizeof(mcontext.__gregs);
#else
if (gp_regs)
*gp_regs = &regs;
@@ -294,6 +365,25 @@ void ThreadInfo::GetFloatingPointRegisters(void** fp_regs, size_t* size) {
*fp_regs = &mcontext.fpregs;
if (size)
*size = sizeof(mcontext.fpregs);
+#elif defined(__riscv)
+# if __riscv_flen == 32
+ if (fp_regs)
+ *fp_regs = &mcontext.__fpregs.__f.__f;
+ if (size)
+ *size = sizeof(mcontext.__fpregs.__f.__f);
+# elif __riscv_flen == 64
+ if (fp_regs)
+ *fp_regs = &mcontext.__fpregs.__d.__f;
+ if (size)
+ *size = sizeof(mcontext.__fpregs.__d.__f);
+# elif __riscv_flen == 128
+ if (fp_regs)
+ *fp_regs = &mcontext.__fpregs.__q.__f;
+ if (size)
+ *size = sizeof(mcontext.__fpregs.__q.__f);
+# else
+# error "Unexpected __riscv_flen"
+# endif
#else
if (fp_regs)
*fp_regs = &fpregs;
diff --git a/src/client/linux/dump_writer_common/thread_info.h b/src/client/linux/dump_writer_common/thread_info.h
index fb216fa6..af786bcc 100644
--- a/src/client/linux/dump_writer_common/thread_info.h
+++ b/src/client/linux/dump_writer_common/thread_info.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2014, Google Inc.
-// All rights reserved.
+// Copyright 2014 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -68,7 +67,7 @@ struct ThreadInfo {
// Use the structures defined in <sys/user.h>
struct user_regs_struct regs;
struct user_fpsimd_struct fpregs;
-#elif defined(__mips__)
+#elif defined(__mips__) || defined(__riscv)
// Use the structure defined in <sys/ucontext.h>.
mcontext_t mcontext;
#endif
diff --git a/src/client/linux/dump_writer_common/ucontext_reader.cc b/src/client/linux/dump_writer_common/ucontext_reader.cc
index ee515c41..97ed2a9f 100644
--- a/src/client/linux/dump_writer_common/ucontext_reader.cc
+++ b/src/client/linux/dump_writer_common/ucontext_reader.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2014, Google Inc.
-// All rights reserved.
+// Copyright 2014 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -48,7 +47,7 @@ uintptr_t UContextReader::GetInstructionPointer(const ucontext_t* uc) {
return uc->uc_mcontext.gregs[REG_EIP];
}
-void UContextReader::FillCPUContext(RawContextCPU *out, const ucontext_t *uc,
+void UContextReader::FillCPUContext(RawContextCPU* out, const ucontext_t* uc,
const fpstate_t* fp) {
const greg_t* regs = uc->uc_mcontext.gregs;
@@ -96,7 +95,7 @@ uintptr_t UContextReader::GetInstructionPointer(const ucontext_t* uc) {
return uc->uc_mcontext.gregs[REG_RIP];
}
-void UContextReader::FillCPUContext(RawContextCPU *out, const ucontext_t *uc,
+void UContextReader::FillCPUContext(RawContextCPU* out, const ucontext_t* uc,
const fpstate_t* fpregs) {
const greg_t* regs = uc->uc_mcontext.gregs;
@@ -153,7 +152,7 @@ uintptr_t UContextReader::GetInstructionPointer(const ucontext_t* uc) {
return uc->uc_mcontext.arm_pc;
}
-void UContextReader::FillCPUContext(RawContextCPU *out, const ucontext_t *uc) {
+void UContextReader::FillCPUContext(RawContextCPU* out, const ucontext_t* uc) {
out->context_flags = MD_CONTEXT_ARM_FULL;
out->iregs[0] = uc->uc_mcontext.arm_r0;
@@ -192,7 +191,7 @@ uintptr_t UContextReader::GetInstructionPointer(const ucontext_t* uc) {
return uc->uc_mcontext.pc;
}
-void UContextReader::FillCPUContext(RawContextCPU *out, const ucontext_t *uc,
+void UContextReader::FillCPUContext(RawContextCPU* out, const ucontext_t* uc,
const struct fpsimd_context* fpregs) {
out->context_flags = MD_CONTEXT_ARM64_FULL_OLD;
@@ -218,7 +217,7 @@ uintptr_t UContextReader::GetInstructionPointer(const ucontext_t* uc) {
return uc->uc_mcontext.pc;
}
-void UContextReader::FillCPUContext(RawContextCPU *out, const ucontext_t *uc) {
+void UContextReader::FillCPUContext(RawContextCPU* out, const ucontext_t* uc) {
#if _MIPS_SIM == _ABI64
out->context_flags = MD_CONTEXT_MIPS64_FULL;
#elif _MIPS_SIM == _ABIO32
@@ -254,6 +253,75 @@ void UContextReader::FillCPUContext(RawContextCPU *out, const ucontext_t *uc) {
out->float_save.fir = uc->uc_mcontext.fpc_eir; // Unused.
#endif
}
+
+#elif defined(__riscv)
+
+uintptr_t UContextReader::GetStackPointer(const ucontext_t* uc) {
+ return uc->uc_mcontext.__gregs[MD_CONTEXT_RISCV_REG_SP];
+}
+
+uintptr_t UContextReader::GetInstructionPointer(const ucontext_t* uc) {
+ return uc->uc_mcontext.__gregs[MD_CONTEXT_RISCV_REG_PC];
+}
+
+void UContextReader::FillCPUContext(RawContextCPU* out, const ucontext_t* uc) {
+# if __riscv__xlen == 32
+ out->context_flags = MD_CONTEXT_RISCV_FULL;
+# elif __riscv_xlen == 64
+ out->context_flags = MD_CONTEXT_RISCV64_FULL;
+# else
+# error "Unexpected __riscv_xlen"
+# endif
+
+ out->pc = uc->uc_mcontext.__gregs[0];
+ out->ra = uc->uc_mcontext.__gregs[1];
+ out->sp = uc->uc_mcontext.__gregs[2];
+ out->gp = uc->uc_mcontext.__gregs[3];
+ out->tp = uc->uc_mcontext.__gregs[4];
+ out->t0 = uc->uc_mcontext.__gregs[5];
+ out->t1 = uc->uc_mcontext.__gregs[6];
+ out->t2 = uc->uc_mcontext.__gregs[7];
+ out->s0 = uc->uc_mcontext.__gregs[8];
+ out->s1 = uc->uc_mcontext.__gregs[9];
+ out->a0 = uc->uc_mcontext.__gregs[10];
+ out->a1 = uc->uc_mcontext.__gregs[11];
+ out->a2 = uc->uc_mcontext.__gregs[12];
+ out->a3 = uc->uc_mcontext.__gregs[13];
+ out->a4 = uc->uc_mcontext.__gregs[14];
+ out->a5 = uc->uc_mcontext.__gregs[15];
+ out->a6 = uc->uc_mcontext.__gregs[16];
+ out->a7 = uc->uc_mcontext.__gregs[17];
+ out->s2 = uc->uc_mcontext.__gregs[18];
+ out->s3 = uc->uc_mcontext.__gregs[19];
+ out->s4 = uc->uc_mcontext.__gregs[20];
+ out->s5 = uc->uc_mcontext.__gregs[21];
+ out->s6 = uc->uc_mcontext.__gregs[22];
+ out->s7 = uc->uc_mcontext.__gregs[23];
+ out->s8 = uc->uc_mcontext.__gregs[24];
+ out->s9 = uc->uc_mcontext.__gregs[25];
+ out->s10 = uc->uc_mcontext.__gregs[26];
+ out->s11 = uc->uc_mcontext.__gregs[27];
+ out->t3 = uc->uc_mcontext.__gregs[28];
+ out->t4 = uc->uc_mcontext.__gregs[29];
+ out->t5 = uc->uc_mcontext.__gregs[30];
+ out->t6 = uc->uc_mcontext.__gregs[31];
+
+# if __riscv_flen == 32
+ for(int i = 0; i < MD_FLOATINGSAVEAREA_RISCV_FPR_COUNT; i++)
+ out->float_save.regs[i] = uc->uc_mcontext.__fpregs.__f.__f[i];
+ out->float_save.fpcsr = uc->uc_mcontext.__fpregs.__f.__fcsr;
+# elif __riscv_flen == 64
+ for(int i = 0; i < MD_FLOATINGSAVEAREA_RISCV_FPR_COUNT; i++)
+ out->float_save.regs[i] = uc->uc_mcontext.__fpregs.__d.__f[i];
+ out->float_save.fpcsr = uc->uc_mcontext.__fpregs.__d.__fcsr;
+# elif __riscv_flen == 128
+ for(int i = 0; i < MD_FLOATINGSAVEAREA_RISCV_FPR_COUNT; i++) {
+ out->float_save.regs[i].high = uc->uc_mcontext.__fpregs.__q.__f[2*i];
+ out->float_save.regs[i].low = uc->uc_mcontext.__fpregs.__q.__f[2*i+1];
+ }
+ out->float_save.fpcsr = uc->uc_mcontext.__fpregs.__q.__fcsr;
+# endif
+}
#endif
} // namespace google_breakpad
diff --git a/src/client/linux/dump_writer_common/ucontext_reader.h b/src/client/linux/dump_writer_common/ucontext_reader.h
index 8e74a8a5..60cbf900 100644
--- a/src/client/linux/dump_writer_common/ucontext_reader.h
+++ b/src/client/linux/dump_writer_common/ucontext_reader.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2014, Google Inc.
-// All rights reserved.
+// Copyright 2014 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -50,13 +49,13 @@ struct UContextReader {
// out: the minidump structure
// info: the collection of register structures.
#if defined(__i386__) || defined(__x86_64)
- static void FillCPUContext(RawContextCPU *out, const ucontext_t *uc,
+ static void FillCPUContext(RawContextCPU* out, const ucontext_t* uc,
const fpstate_t* fp);
#elif defined(__aarch64__)
- static void FillCPUContext(RawContextCPU *out, const ucontext_t *uc,
+ static void FillCPUContext(RawContextCPU* out, const ucontext_t* uc,
const struct fpsimd_context* fpregs);
#else
- static void FillCPUContext(RawContextCPU *out, const ucontext_t *uc);
+ static void FillCPUContext(RawContextCPU* out, const ucontext_t* uc);
#endif
};
diff --git a/src/client/linux/handler/exception_handler.cc b/src/client/linux/handler/exception_handler.cc
index c65feaa1..bbdb798b 100644
--- a/src/client/linux/handler/exception_handler.cc
+++ b/src/client/linux/handler/exception_handler.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2010 Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -138,7 +137,7 @@ void InstallAlternateStackLocked() {
// SIGSTKSZ may be too small to prevent the signal handlers from overrunning
// the alternative stack. Ensure that the size of the alternative stack is
// large enough.
- static const unsigned kSigStackSize = std::max(16384, SIGSTKSZ);
+ const unsigned kSigStackSize = std::max<unsigned>(16384, SIGSTKSZ);
// Only set an alternative stack if there isn't already one, or if the current
// one is too small.
@@ -419,8 +418,8 @@ struct ThreadArgument {
// This is the entry function for the cloned process. We are in a compromised
// context here: see the top of the file.
// static
-int ExceptionHandler::ThreadEntry(void *arg) {
- const ThreadArgument *thread_arg = reinterpret_cast<ThreadArgument*>(arg);
+int ExceptionHandler::ThreadEntry(void* arg) {
+ const ThreadArgument* thread_arg = reinterpret_cast<ThreadArgument*>(arg);
// Close the write end of the pipe. This allows us to fail if the parent dies
// while waiting for the continue signal.
@@ -461,10 +460,7 @@ bool ExceptionHandler::HandleSignal(int /*sig*/, siginfo_t* info, void* uc) {
memcpy(&g_crash_context_.float_state, fp_ptr,
sizeof(g_crash_context_.float_state));
}
-#elif !defined(__ARM_EABI__) && !defined(__mips__)
- // FP state is not part of user ABI on ARM Linux.
- // In case of MIPS Linux FP state is already part of ucontext_t
- // and 'float_state' is not a member of CrashContext.
+#elif GOOGLE_BREAKPAD_CRASH_CONTEXT_HAS_FLOAT_STATE
ucontext_t* uc_ptr = (ucontext_t*)uc;
if (uc_ptr->uc_mcontext.fpregs) {
memcpy(&g_crash_context_.float_state, uc_ptr->uc_mcontext.fpregs,
@@ -495,7 +491,7 @@ bool ExceptionHandler::SimulateSignalDelivery(int sig) {
}
// This function may run in a compromised context: see the top of the file.
-bool ExceptionHandler::GenerateDump(CrashContext *context) {
+bool ExceptionHandler::GenerateDump(CrashContext* context) {
if (IsOutOfProcess())
return crash_generation_client_->RequestDump(context, sizeof(*context));
@@ -701,8 +697,7 @@ bool ExceptionHandler::WriteMinidump() {
}
#endif
-#if !defined(__ARM_EABI__) && !defined(__aarch64__) && !defined(__mips__)
- // FPU state is not part of ARM EABI ucontext_t.
+#if GOOGLE_BREAKPAD_CRASH_CONTEXT_HAS_FLOAT_STATE && !defined(__aarch64__)
memcpy(&context.float_state, context.context.uc_mcontext.fpregs,
sizeof(context.float_state));
#endif
@@ -726,8 +721,11 @@ bool ExceptionHandler::WriteMinidump() {
#elif defined(__mips__)
context.siginfo.si_addr =
reinterpret_cast<void*>(context.context.uc_mcontext.pc);
+#elif defined(__riscv)
+ context.siginfo.si_addr =
+ reinterpret_cast<void*>(context.context.uc_mcontext.__gregs[REG_PC]);
#else
-#error "This code has not been ported to your platform yet."
+# error "This code has not been ported to your platform yet."
#endif
return GenerateDump(&context);
diff --git a/src/client/linux/handler/exception_handler.h b/src/client/linux/handler/exception_handler.h
index f44483ff..f8bc1ead 100644
--- a/src/client/linux/handler/exception_handler.h
+++ b/src/client/linux/handler/exception_handler.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2010 Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -44,6 +43,15 @@
#include "common/using_std_string.h"
#include "google_breakpad/common/minidump_format.h"
+#if !defined(__ARM_EABI__) && !defined(__mips__) && !defined(__riscv)
+// FP state is not part of user ABI for Linux ARM.
+// In case of MIPS and RISCV Linux FP state is already part of ucontext_t
+// so 'float_state' is not required.
+# define GOOGLE_BREAKPAD_CRASH_CONTEXT_HAS_FLOAT_STATE 1
+#else
+# define GOOGLE_BREAKPAD_CRASH_CONTEXT_HAS_FLOAT_STATE 0
+#endif
+
namespace google_breakpad {
// ExceptionHandler
@@ -82,7 +90,7 @@ class ExceptionHandler {
// attempting to write a minidump. If a FilterCallback returns false,
// Breakpad will immediately report the exception as unhandled without
// writing a minidump, allowing another handler the opportunity to handle it.
- typedef bool (*FilterCallback)(void *context);
+ typedef bool (*FilterCallback)(void* context);
// A callback function to run after the minidump has been written.
// |descriptor| contains the file descriptor or file path containing the
@@ -192,10 +200,7 @@ class ExceptionHandler {
siginfo_t siginfo;
pid_t tid; // the crashing thread.
ucontext_t context;
-#if !defined(__ARM_EABI__) && !defined(__mips__)
- // #ifdef this out because FP state is not part of user ABI for Linux ARM.
- // In case of MIPS Linux FP state is already part of ucontext_t so
- // 'float_state' is not required.
+#if GOOGLE_BREAKPAD_CRASH_CONTEXT_HAS_FLOAT_STATE
fpstate_t float_state;
#endif
};
@@ -234,7 +239,7 @@ class ExceptionHandler {
static void RestoreHandlersLocked();
void PreresolveSymbols();
- bool GenerateDump(CrashContext *context);
+ bool GenerateDump(CrashContext* context);
void SendContinueSignalToChild();
void WaitForContinueSignal();
diff --git a/src/client/linux/handler/exception_handler_unittest.cc b/src/client/linux/handler/exception_handler_unittest.cc
index 27808aa1..691ea133 100644
--- a/src/client/linux/handler/exception_handler_unittest.cc
+++ b/src/client/linux/handler/exception_handler_unittest.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2010 Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -201,7 +200,7 @@ static bool DoneCallback(const MinidumpDescriptor& descriptor,
// optimize them out. In the case of ExceptionHandlerTest::ExternalDumper,
// GCC-4.9 optimized out the entire set up of ExceptionHandler, causing
// test failure.
-volatile int *p_null; // external linkage, so GCC can't tell that it
+volatile int* p_null; // external linkage, so GCC can't tell that it
// remains NULL. Volatile just for a good measure.
static void DoNullPointerDereference() {
*p_null = 1;
@@ -306,8 +305,22 @@ TEST(ExceptionHandlerTest, ParallelChildCrashesDontHang) {
}
}
- // Wait a while until the child should have crashed.
- usleep(1000000);
+ // Poll the child to see if it crashed.
+ int status, wp_pid;
+ for (int i = 0; i < 100; i++) {
+ wp_pid = HANDLE_EINTR(waitpid(child, &status, WNOHANG));
+ ASSERT_NE(-1, wp_pid);
+ if (wp_pid > 0) {
+ ASSERT_TRUE(WIFSIGNALED(status));
+ // If the child process terminated by itself,
+ // it will have returned SIGSEGV.
+ ASSERT_EQ(SIGSEGV, WTERMSIG(status));
+ return;
+ } else {
+ usleep(100000);
+ }
+ }
+
// Kill the child if it is still running.
kill(child, SIGKILL);
@@ -649,7 +662,7 @@ TEST(ExceptionHandlerTest, InstructionPointerMemory) {
memset(prefix_bytes, 0, sizeof(prefix_bytes));
memset(suffix_bytes, 0, sizeof(suffix_bytes));
EXPECT_TRUE(memcmp(bytes, prefix_bytes, sizeof(prefix_bytes)) == 0);
- EXPECT_TRUE(memcmp(bytes + kOffset, kIllegalInstruction,
+ EXPECT_TRUE(memcmp(bytes + kOffset, kIllegalInstruction,
sizeof(kIllegalInstruction)) == 0);
EXPECT_TRUE(memcmp(bytes + kOffset + sizeof(kIllegalInstruction),
suffix_bytes, sizeof(suffix_bytes)) == 0);
@@ -738,7 +751,7 @@ TEST(ExceptionHandlerTest, InstructionPointerMemoryMinBound) {
uint8_t suffix_bytes[kMemorySize / 2 - sizeof(kIllegalInstruction)];
memset(suffix_bytes, 0, sizeof(suffix_bytes));
- EXPECT_TRUE(memcmp(bytes + kOffset, kIllegalInstruction,
+ EXPECT_TRUE(memcmp(bytes + kOffset, kIllegalInstruction,
sizeof(kIllegalInstruction)) == 0);
EXPECT_TRUE(memcmp(bytes + kOffset + sizeof(kIllegalInstruction),
suffix_bytes, sizeof(suffix_bytes)) == 0);
@@ -994,7 +1007,7 @@ CrashHandler(const void* crash_context, size_t crash_context_size,
msg.msg_control = cmsg;
msg.msg_controllen = sizeof(cmsg);
- struct cmsghdr *hdr = CMSG_FIRSTHDR(&msg);
+ struct cmsghdr* hdr = CMSG_FIRSTHDR(&msg);
hdr->cmsg_level = SOL_SOCKET;
hdr->cmsg_type = SCM_RIGHTS;
hdr->cmsg_len = CMSG_LEN(sizeof(int));
@@ -1003,7 +1016,7 @@ CrashHandler(const void* crash_context, size_t crash_context_size,
hdr->cmsg_level = SOL_SOCKET;
hdr->cmsg_type = SCM_CREDENTIALS;
hdr->cmsg_len = CMSG_LEN(sizeof(struct ucred));
- struct ucred *cred = reinterpret_cast<struct ucred*>(CMSG_DATA(hdr));
+ struct ucred* cred = reinterpret_cast<struct ucred*>(CMSG_DATA(hdr));
cred->uid = getuid();
cred->gid = getgid();
cred->pid = getpid();
@@ -1056,7 +1069,7 @@ TEST(ExceptionHandlerTest, ExternalDumper) {
pid_t crashing_pid = -1;
int signal_fd = -1;
- for (struct cmsghdr *hdr = CMSG_FIRSTHDR(&msg); hdr;
+ for (struct cmsghdr* hdr = CMSG_FIRSTHDR(&msg); hdr;
hdr = CMSG_NXTHDR(&msg, hdr)) {
if (hdr->cmsg_level != SOL_SOCKET)
continue;
@@ -1066,7 +1079,7 @@ TEST(ExceptionHandlerTest, ExternalDumper) {
ASSERT_EQ(sizeof(int), len);
signal_fd = *(reinterpret_cast<int*>(CMSG_DATA(hdr)));
} else if (hdr->cmsg_type == SCM_CREDENTIALS) {
- const struct ucred *cred =
+ const struct ucred* cred =
reinterpret_cast<struct ucred*>(CMSG_DATA(hdr));
crashing_pid = cred->pid;
}
diff --git a/src/client/linux/handler/microdump_extra_info.h b/src/client/linux/handler/microdump_extra_info.h
index bf01f0c7..1da69d09 100644
--- a/src/client/linux/handler/microdump_extra_info.h
+++ b/src/client/linux/handler/microdump_extra_info.h
@@ -1,5 +1,4 @@
-// Copyright 2015 Google Inc.
-// All rights reserved.
+// Copyright 2015 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/client/linux/handler/minidump_descriptor.cc b/src/client/linux/handler/minidump_descriptor.cc
index bd94474e..517fce97 100644
--- a/src/client/linux/handler/minidump_descriptor.cc
+++ b/src/client/linux/handler/minidump_descriptor.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2012 Google Inc.
-// All rights reserved.
+// Copyright 2012 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/client/linux/handler/minidump_descriptor.h b/src/client/linux/handler/minidump_descriptor.h
index c7e4f2b3..d822c9d9 100644
--- a/src/client/linux/handler/minidump_descriptor.h
+++ b/src/client/linux/handler/minidump_descriptor.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2012 Google Inc.
-// All rights reserved.
+// Copyright 2012 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -33,6 +32,7 @@
#include <assert.h>
#include <sys/types.h>
+#include <cstdint>
#include <string>
#include "client/linux/handler/microdump_extra_info.h"
diff --git a/src/client/linux/log/log.cc b/src/client/linux/log/log.cc
index fc23aa6d..c45de64b 100644
--- a/src/client/linux/log/log.cc
+++ b/src/client/linux/log/log.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2012 Google Inc.
-// All rights reserved.
+// Copyright 2012 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -44,8 +43,8 @@ namespace {
// __android_log_buf_write() is not exported in the NDK and is being used by
// dynamic runtime linking. Its declaration is taken from Android's
// system/core/include/log/log.h.
-using AndroidLogBufferWriteFunc = int (*)(int bufID, int prio, const char *tag,
- const char *text);
+using AndroidLogBufferWriteFunc = int (*)(int bufID, int prio, const char* tag,
+ const char* text);
const int kAndroidCrashLogId = 4; // From LOG_ID_CRASH in log.h.
const char kAndroidLogTag[] = "google-breakpad";
diff --git a/src/client/linux/log/log.h b/src/client/linux/log/log.h
index f94bbd5f..93aeffcf 100644
--- a/src/client/linux/log/log.h
+++ b/src/client/linux/log/log.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2012, Google Inc.
-// All rights reserved.
+// Copyright 2012 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/client/linux/microdump_writer/microdump_writer.cc b/src/client/linux/microdump_writer/microdump_writer.cc
index 0aa30fbf..1f19d3bb 100644
--- a/src/client/linux/microdump_writer/microdump_writer.cc
+++ b/src/client/linux/microdump_writer/microdump_writer.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2014, Google Inc.
-// All rights reserved.
+// Copyright 2014 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -49,8 +48,8 @@
namespace {
using google_breakpad::auto_wasteful_vector;
+using google_breakpad::elf::kDefaultBuildIdSize;
using google_breakpad::ExceptionHandler;
-using google_breakpad::kDefaultBuildIdSize;
using google_breakpad::LinuxDumper;
using google_breakpad::LinuxPtraceDumper;
using google_breakpad::MappingInfo;
@@ -138,7 +137,7 @@ class MicrodumpWriter {
const MicrodumpExtraInfo& microdump_extra_info,
LinuxDumper* dumper)
: ucontext_(context ? &context->context : NULL),
-#if !defined(__ARM_EABI__) && !defined(__mips__)
+#if GOOGLE_BREAKPAD_CRASH_CONTEXT_HAS_FLOAT_STATE
float_state_(context ? &context->float_state : NULL),
#endif
dumper_(dumper),
@@ -336,9 +335,17 @@ class MicrodumpWriter {
const char kArch[] = "mips64";
# else
# error "This mips ABI is currently not supported (n32)"
-#endif
+# endif
+#elif defined(__riscv)
+# if __riscv_xlen == 32
+ const char kArch[] = "riscv32";
+# elif __riscv_xlen == 64
+ const char kArch[] = "riscv64";
+# else
+# error "Unexpected __riscv_xlen"
+# endif
#else
-#error "This code has not been ported to your platform yet"
+# error "This code has not been ported to your platform yet"
#endif
LogAppend("O ");
@@ -409,7 +416,7 @@ class MicrodumpWriter {
void DumpCPUState() {
RawContextCPU cpu;
my_memset(&cpu, 0, sizeof(RawContextCPU));
-#if !defined(__ARM_EABI__) && !defined(__mips__)
+#if GOOGLE_BREAKPAD_CRASH_CONTEXT_HAS_FLOAT_STATE
UContextReader::FillCPUContext(&cpu, ucontext_, float_state_);
#else
UContextReader::FillCPUContext(&cpu, ucontext_);
@@ -460,7 +467,7 @@ class MicrodumpWriter {
}
// Copy as many bytes of |identifier| as will fit into a MDGUID
- MDGUID module_identifier = {};
+ MDGUID module_identifier = {0};
memcpy(&module_identifier, &identifier_bytes[0],
std::min(sizeof(MDGUID), identifier_bytes.size()));
@@ -605,7 +612,7 @@ class MicrodumpWriter {
void* Alloc(unsigned bytes) { return dumper_->allocator()->Alloc(bytes); }
const ucontext_t* const ucontext_;
-#if !defined(__ARM_EABI__) && !defined(__mips__)
+#if GOOGLE_BREAKPAD_CRASH_CONTEXT_HAS_FLOAT_STATE
const google_breakpad::fpstate_t* const float_state_;
#endif
LinuxDumper* dumper_;
diff --git a/src/client/linux/microdump_writer/microdump_writer.h b/src/client/linux/microdump_writer/microdump_writer.h
index a1e53df6..47b03e8f 100644
--- a/src/client/linux/microdump_writer/microdump_writer.h
+++ b/src/client/linux/microdump_writer/microdump_writer.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2014, Google Inc.
-// All rights reserved.
+// Copyright 2014 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/client/linux/microdump_writer/microdump_writer_unittest.cc b/src/client/linux/microdump_writer/microdump_writer_unittest.cc
index 6339ac0c..84865664 100644
--- a/src/client/linux/microdump_writer/microdump_writer_unittest.cc
+++ b/src/client/linux/microdump_writer/microdump_writer_unittest.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2014 Google Inc.
-// All rights reserved.
+// Copyright 2014 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/client/linux/minidump_writer/cpu_set.h b/src/client/linux/minidump_writer/cpu_set.h
index 1cca9aa5..70c1c758 100644
--- a/src/client/linux/minidump_writer/cpu_set.h
+++ b/src/client/linux/minidump_writer/cpu_set.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2013, Google Inc.
-// All rights reserved.
+// Copyright 2013 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/client/linux/minidump_writer/cpu_set_unittest.cc b/src/client/linux/minidump_writer/cpu_set_unittest.cc
index e2274bd1..1db74410 100644
--- a/src/client/linux/minidump_writer/cpu_set_unittest.cc
+++ b/src/client/linux/minidump_writer/cpu_set_unittest.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2013, Google Inc.
-// All rights reserved.
+// Copyright 2013 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/client/linux/minidump_writer/directory_reader.h b/src/client/linux/minidump_writer/directory_reader.h
index a4bde180..62bba877 100644
--- a/src/client/linux/minidump_writer/directory_reader.h
+++ b/src/client/linux/minidump_writer/directory_reader.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2009, Google Inc.
-// All rights reserved.
+// Copyright 2009 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/client/linux/minidump_writer/directory_reader_unittest.cc b/src/client/linux/minidump_writer/directory_reader_unittest.cc
index 326f9e36..ffc5fbfd 100644
--- a/src/client/linux/minidump_writer/directory_reader_unittest.cc
+++ b/src/client/linux/minidump_writer/directory_reader_unittest.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2009, Google Inc.
-// All rights reserved.
+// Copyright 2009 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -47,7 +46,7 @@ typedef testing::Test DirectoryReaderTest;
TEST(DirectoryReaderTest, CompareResults) {
std::set<string> dent_set;
- DIR *const dir = opendir("/proc/self");
+ DIR* const dir = opendir("/proc/self");
ASSERT_TRUE(dir != NULL);
struct dirent* dent;
diff --git a/src/client/linux/minidump_writer/line_reader.h b/src/client/linux/minidump_writer/line_reader.h
index 779cfeb6..d54a67d0 100644
--- a/src/client/linux/minidump_writer/line_reader.h
+++ b/src/client/linux/minidump_writer/line_reader.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2009, Google Inc.
-// All rights reserved.
+// Copyright 2009 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -61,7 +60,7 @@ class LineReader {
//
// One must call |PopLine| after this function, otherwise you'll continue to
// get the same line over and over.
- bool GetNextLine(const char **line, unsigned *len) {
+ bool GetNextLine(const char** line, unsigned* len) {
for (;;) {
if (buf_used_ == 0 && hit_eof_)
return false;
diff --git a/src/client/linux/minidump_writer/line_reader_unittest.cc b/src/client/linux/minidump_writer/line_reader_unittest.cc
index 29686f04..3062c39f 100644
--- a/src/client/linux/minidump_writer/line_reader_unittest.cc
+++ b/src/client/linux/minidump_writer/line_reader_unittest.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2009, Google Inc.
-// All rights reserved.
+// Copyright 2009 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -59,7 +58,7 @@ TEST(LineReaderTest, EmptyFile) {
ASSERT_TRUE(file.IsOk());
LineReader reader(file.GetFd());
- const char *line;
+ const char* line;
unsigned len;
ASSERT_FALSE(reader.GetNextLine(&line, &len));
}
@@ -69,7 +68,7 @@ TEST(LineReaderTest, OneLineTerminated) {
ASSERT_TRUE(file.IsOk());
LineReader reader(file.GetFd());
- const char *line;
+ const char* line;
unsigned int len;
ASSERT_TRUE(reader.GetNextLine(&line, &len));
ASSERT_EQ((unsigned int)1, len);
@@ -85,7 +84,7 @@ TEST(LineReaderTest, OneLine) {
ASSERT_TRUE(file.IsOk());
LineReader reader(file.GetFd());
- const char *line;
+ const char* line;
unsigned len;
ASSERT_TRUE(reader.GetNextLine(&line, &len));
ASSERT_EQ((unsigned)1, len);
@@ -101,7 +100,7 @@ TEST(LineReaderTest, TwoLinesTerminated) {
ASSERT_TRUE(file.IsOk());
LineReader reader(file.GetFd());
- const char *line;
+ const char* line;
unsigned len;
ASSERT_TRUE(reader.GetNextLine(&line, &len));
ASSERT_EQ((unsigned)1, len);
@@ -123,7 +122,7 @@ TEST(LineReaderTest, TwoLines) {
ASSERT_TRUE(file.IsOk());
LineReader reader(file.GetFd());
- const char *line;
+ const char* line;
unsigned len;
ASSERT_TRUE(reader.GetNextLine(&line, &len));
ASSERT_EQ((unsigned)1, len);
@@ -147,7 +146,7 @@ TEST(LineReaderTest, MaxLength) {
ASSERT_TRUE(file.IsOk());
LineReader reader(file.GetFd());
- const char *line;
+ const char* line;
unsigned len;
ASSERT_TRUE(reader.GetNextLine(&line, &len));
ASSERT_EQ(sizeof(l), len);
@@ -163,7 +162,7 @@ TEST(LineReaderTest, TooLong) {
ASSERT_TRUE(file.IsOk());
LineReader reader(file.GetFd());
- const char *line;
+ const char* line;
unsigned len;
ASSERT_FALSE(reader.GetNextLine(&line, &len));
}
diff --git a/src/client/linux/minidump_writer/linux_core_dumper.cc b/src/client/linux/minidump_writer/linux_core_dumper.cc
index 41506898..2c507c1b 100644
--- a/src/client/linux/minidump_writer/linux_core_dumper.cc
+++ b/src/client/linux/minidump_writer/linux_core_dumper.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2012, Google Inc.
-// All rights reserved.
+// Copyright 2012 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -112,8 +111,11 @@ bool LinuxCoreDumper::GetThreadInfoByIndex(size_t index, ThreadInfo* info) {
#elif defined(__mips__)
stack_pointer =
reinterpret_cast<uint8_t*>(info->mcontext.gregs[MD_CONTEXT_MIPS_REG_SP]);
+#elif defined(__riscv)
+ stack_pointer = reinterpret_cast<uint8_t*>(
+ info->mcontext.__gregs[MD_CONTEXT_RISCV_REG_SP]);
#else
-#error "This code hasn't been ported to your platform yet."
+# error "This code hasn't been ported to your platform yet."
#endif
info->stack_pointer = reinterpret_cast<uintptr_t>(stack_pointer);
return true;
@@ -137,6 +139,16 @@ bool LinuxCoreDumper::EnumerateThreads() {
return false;
}
+ char proc_mem_path[NAME_MAX];
+ if (BuildProcPath(proc_mem_path, pid_, "mem")) {
+ int fd = open(proc_mem_path, O_RDONLY | O_LARGEFILE | O_CLOEXEC);
+ if (fd != -1) {
+ core_.SetProcMem(fd);
+ } else {
+ fprintf(stderr, "Cannot open %s (%s)\n", proc_mem_path, strerror(errno));
+ }
+ }
+
core_.SetContent(mapped_core_file_.content());
if (!core_.IsValid()) {
fprintf(stderr, "Invalid core dump file\n");
@@ -198,19 +210,22 @@ bool LinuxCoreDumper::EnumerateThreads() {
info.tgid = status->pr_pgrp;
info.ppid = status->pr_ppid;
#if defined(__mips__)
-#if defined(__ANDROID__)
+# if defined(__ANDROID__)
for (int i = EF_R0; i <= EF_R31; i++)
info.mcontext.gregs[i - EF_R0] = status->pr_reg[i];
-#else // __ANDROID__
+# else // __ANDROID__
for (int i = EF_REG0; i <= EF_REG31; i++)
info.mcontext.gregs[i - EF_REG0] = status->pr_reg[i];
-#endif // __ANDROID__
+# endif // __ANDROID__
info.mcontext.mdlo = status->pr_reg[EF_LO];
info.mcontext.mdhi = status->pr_reg[EF_HI];
info.mcontext.pc = status->pr_reg[EF_CP0_EPC];
-#else // __mips__
+#elif defined(__riscv)
+ memcpy(&info.mcontext.__gregs, status->pr_reg,
+ sizeof(info.mcontext.__gregs));
+#else // __riscv
memcpy(&info.regs, status->pr_reg, sizeof(info.regs));
-#endif // __mips__
+#endif
if (first_thread) {
crash_thread_ = pid;
crash_signal_ = status->pr_info.si_signo;
diff --git a/src/client/linux/minidump_writer/linux_core_dumper.h b/src/client/linux/minidump_writer/linux_core_dumper.h
index 8a7c924b..3fc71223 100644
--- a/src/client/linux/minidump_writer/linux_core_dumper.h
+++ b/src/client/linux/minidump_writer/linux_core_dumper.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2012, Google Inc.
-// All rights reserved.
+// Copyright 2012 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/client/linux/minidump_writer/linux_core_dumper_unittest.cc b/src/client/linux/minidump_writer/linux_core_dumper_unittest.cc
index 77448031..157e4f89 100644
--- a/src/client/linux/minidump_writer/linux_core_dumper_unittest.cc
+++ b/src/client/linux/minidump_writer/linux_core_dumper_unittest.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2012, Google Inc.
-// All rights reserved.
+// Copyright 2012 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/client/linux/minidump_writer/linux_dumper.cc b/src/client/linux/minidump_writer/linux_dumper.cc
index ef75260e..01b06fac 100644
--- a/src/client/linux/minidump_writer/linux_dumper.cc
+++ b/src/client/linux/minidump_writer/linux_dumper.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2010, Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -53,6 +52,8 @@
#include "google_breakpad/common/minidump_exception_linux.h"
#include "third_party/lss/linux_syscall_support.h"
+using google_breakpad::elf::FileID;
+
#if defined(__ANDROID__)
// Android packed relocations definitions are not yet available from the
@@ -135,7 +136,7 @@ const size_t kHpageMask = (~(kHpageSize - 1));
// next is backed by some file.
// curr and next are contiguous.
// offset(next) == sizeof(curr)
-void TryRecoverMappings(MappingInfo *curr, MappingInfo *next) {
+void TryRecoverMappings(MappingInfo* curr, MappingInfo* next) {
// Merged segments are marked with size = 0.
if (curr->size == 0 || next->size == 0)
return;
@@ -167,8 +168,8 @@ void TryRecoverMappings(MappingInfo *curr, MappingInfo *next) {
// next and prev are backed by the same file.
// prev, curr and next are contiguous.
// offset(next) == offset(prev) + sizeof(prev) + sizeof(curr)
-void TryRecoverMappings(MappingInfo *prev, MappingInfo *curr,
- MappingInfo *next) {
+void TryRecoverMappings(MappingInfo* prev, MappingInfo* curr,
+ MappingInfo* next) {
// Merged segments are marked with size = 0.
if (prev->size == 0 || curr->size == 0 || next->size == 0)
return;
@@ -551,11 +552,11 @@ bool LinuxDumper::EnumerateMappings() {
// See http://www.trilithium.com/johan/2005/08/linux-gate/ for more
// information.
const void* linux_gate_loc =
- reinterpret_cast<void *>(auxv_[AT_SYSINFO_EHDR]);
+ reinterpret_cast<void*>(auxv_[AT_SYSINFO_EHDR]);
// Although the initial executable is usually the first mapping, it's not
// guaranteed (see http://crosbug.com/25355); therefore, try to use the
// actual entry point to find the mapping.
- const void* entry_point_loc = reinterpret_cast<void *>(auxv_[AT_ENTRY]);
+ const void* entry_point_loc = reinterpret_cast<void*>(auxv_[AT_ENTRY]);
const int fd = sys_open(maps_path, O_RDONLY, 0);
if (fd < 0)
@@ -943,7 +944,7 @@ bool LinuxDumper::HandleDeletedFileInMapping(char* path) const {
char exe_link[NAME_MAX];
if (!BuildProcPath(exe_link, pid_, "exe"))
return false;
- MappingInfo new_mapping = {};
+ MappingInfo new_mapping = {0};
if (!SafeReadLink(exe_link, new_mapping.name))
return false;
char new_path[PATH_MAX];
diff --git a/src/client/linux/minidump_writer/linux_dumper.h b/src/client/linux/minidump_writer/linux_dumper.h
index f4a75d90..2d5b2e52 100644
--- a/src/client/linux/minidump_writer/linux_dumper.h
+++ b/src/client/linux/minidump_writer/linux_dumper.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2010, Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -60,10 +59,12 @@ namespace google_breakpad {
// Typedef for our parsing of the auxv variables in /proc/pid/auxv.
#if defined(__i386) || defined(__ARM_EABI__) || \
- (defined(__mips__) && _MIPS_SIM == _ABIO32)
+ (defined(__mips__) && _MIPS_SIM == _ABIO32) || \
+ (defined(__riscv) && __riscv_xlen == 32)
typedef Elf32_auxv_t elf_aux_entry;
#elif defined(__x86_64) || defined(__aarch64__) || \
- (defined(__mips__) && _MIPS_SIM != _ABIO32)
+ (defined(__mips__) && _MIPS_SIM != _ABIO32) || \
+ (defined(__riscv) && __riscv_xlen == 64)
typedef Elf64_auxv_t elf_aux_entry;
#endif
@@ -110,8 +111,8 @@ class LinuxDumper {
}
// These are only valid after a call to |Init|.
- const wasteful_vector<pid_t> &threads() { return threads_; }
- const wasteful_vector<MappingInfo*> &mappings() { return mappings_; }
+ const wasteful_vector<pid_t>& threads() { return threads_; }
+ const wasteful_vector<MappingInfo*>& mappings() { return mappings_; }
const MappingInfo* FindMapping(const void* address) const;
// Find the mapping which the given memory address falls in. Unlike
// FindMapping, this method uses the unadjusted mapping address
diff --git a/src/client/linux/minidump_writer/linux_dumper_unittest_helper.cc b/src/client/linux/minidump_writer/linux_dumper_unittest_helper.cc
index 3ad48e50..bc1e4fbe 100644
--- a/src/client/linux/minidump_writer/linux_dumper_unittest_helper.cc
+++ b/src/client/linux/minidump_writer/linux_dumper_unittest_helper.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2010, Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -51,12 +50,14 @@
#define TID_PTR_REGISTER "rcx"
#elif defined(__mips__)
#define TID_PTR_REGISTER "$1"
+#elif defined(__riscv)
+#define TID_PTR_REGISTER "x4"
#else
#error This test has not been ported to this platform.
#endif
-void *thread_function(void *data) {
- int pipefd = *static_cast<int *>(data);
+void* thread_function(void* data) {
+ int pipefd = *static_cast<int*>(data);
volatile pid_t* thread_id = new pid_t;
*thread_id = syscall(__NR_gettid);
// Signal parent that a thread has started.
@@ -65,13 +66,13 @@ void *thread_function(void *data) {
perror("ERROR: parent notification failed");
return NULL;
}
- register volatile pid_t *thread_id_ptr asm(TID_PTR_REGISTER) = thread_id;
+ register volatile pid_t* thread_id_ptr asm(TID_PTR_REGISTER) = thread_id;
while (true)
asm volatile ("" : : "r" (thread_id_ptr));
return NULL;
}
-int main(int argc, char *argv[]) {
+int main(int argc, char* argv[]) {
if (argc < 3) {
fprintf(stderr,
"usage: linux_dumper_unittest_helper <pipe fd> <# of threads>\n");
diff --git a/src/client/linux/minidump_writer/linux_ptrace_dumper.cc b/src/client/linux/minidump_writer/linux_ptrace_dumper.cc
index e3ddb81a..718fab7c 100644
--- a/src/client/linux/minidump_writer/linux_ptrace_dumper.cc
+++ b/src/client/linux/minidump_writer/linux_ptrace_dumper.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2012, Google Inc.
-// All rights reserved.
+// Copyright 2012 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -298,8 +297,11 @@ bool LinuxPtraceDumper::GetThreadInfoByIndex(size_t index, ThreadInfo* info) {
#elif defined(__mips__)
stack_pointer =
reinterpret_cast<uint8_t*>(info->mcontext.gregs[MD_CONTEXT_MIPS_REG_SP]);
+#elif defined(__riscv)
+ stack_pointer = reinterpret_cast<uint8_t*>(
+ info->mcontext.__gregs[MD_CONTEXT_RISCV_REG_SP]);
#else
-#error "This code hasn't been ported to your platform yet."
+# error "This code hasn't been ported to your platform yet."
#endif
info->stack_pointer = reinterpret_cast<uintptr_t>(stack_pointer);
diff --git a/src/client/linux/minidump_writer/linux_ptrace_dumper.h b/src/client/linux/minidump_writer/linux_ptrace_dumper.h
index cee58178..7828934f 100644
--- a/src/client/linux/minidump_writer/linux_ptrace_dumper.h
+++ b/src/client/linux/minidump_writer/linux_ptrace_dumper.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2012, Google Inc.
-// All rights reserved.
+// Copyright 2012 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/client/linux/minidump_writer/linux_ptrace_dumper_unittest.cc b/src/client/linux/minidump_writer/linux_ptrace_dumper_unittest.cc
index ea6b9a12..a8455165 100644
--- a/src/client/linux/minidump_writer/linux_ptrace_dumper_unittest.cc
+++ b/src/client/linux/minidump_writer/linux_ptrace_dumper_unittest.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2009, Google Inc.
-// All rights reserved.
+// Copyright 2009 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -63,6 +62,8 @@
#endif
using namespace google_breakpad;
+using google_breakpad::elf::FileID;
+using google_breakpad::elf::kDefaultBuildIdSize;
namespace {
@@ -337,7 +338,7 @@ TEST_F(LinuxPtraceDumperChildTest, MappingsIncludeLinuxGate) {
ASSERT_TRUE(dumper.Init());
void* linux_gate_loc =
- reinterpret_cast<void *>(dumper.auxv()[AT_SYSINFO_EHDR]);
+ reinterpret_cast<void*>(dumper.auxv()[AT_SYSINFO_EHDR]);
ASSERT_TRUE(linux_gate_loc);
bool found_linux_gate = false;
@@ -462,6 +463,9 @@ TEST(LinuxPtraceDumperTest, VerifyStackReadWithMultipleThreads) {
#elif defined(__mips__)
pid_t* process_tid_location =
reinterpret_cast<pid_t*>(one_thread.mcontext.gregs[1]);
+#elif defined(__riscv)
+ pid_t* process_tid_location =
+ reinterpret_cast<pid_t*>(one_thread.mcontext.__gregs[4]);
#else
#error This test has not been ported to this platform.
#endif
@@ -559,6 +563,8 @@ TEST_F(LinuxPtraceDumperTest, SanitizeStackCopy) {
uintptr_t heap_addr = thread_info.regs.rcx;
#elif defined(__mips__)
uintptr_t heap_addr = thread_info.mcontext.gregs[1];
+#elif defined(__riscv)
+ uintptr_t heap_addr = thread_info.mcontext.__gregs[4];
#else
#error This test has not been ported to this platform.
#endif
diff --git a/src/client/linux/minidump_writer/minidump_writer.cc b/src/client/linux/minidump_writer/minidump_writer.cc
index f8cdf2a1..a5f9b841 100644
--- a/src/client/linux/minidump_writer/minidump_writer.cc
+++ b/src/client/linux/minidump_writer/minidump_writer.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2010, Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -71,6 +70,8 @@
#include "client/linux/minidump_writer/line_reader.h"
#include "client/linux/minidump_writer/linux_dumper.h"
#include "client/linux/minidump_writer/linux_ptrace_dumper.h"
+#include "client/linux/minidump_writer/pe_file.h"
+#include "client/linux/minidump_writer/pe_structs.h"
#include "client/linux/minidump_writer/proc_cpuinfo_reader.h"
#include "client/minidump_file_writer.h"
#include "common/linux/file_id.h"
@@ -83,9 +84,9 @@ namespace {
using google_breakpad::AppMemoryList;
using google_breakpad::auto_wasteful_vector;
+using google_breakpad::elf::kDefaultBuildIdSize;
using google_breakpad::ExceptionHandler;
using google_breakpad::CpuSet;
-using google_breakpad::kDefaultBuildIdSize;
using google_breakpad::LineReader;
using google_breakpad::LinuxDumper;
using google_breakpad::LinuxPtraceDumper;
@@ -95,8 +96,11 @@ using google_breakpad::MappingInfo;
using google_breakpad::MappingList;
using google_breakpad::MinidumpFileWriter;
using google_breakpad::PageAllocator;
+using google_breakpad::PEFile;
+using google_breakpad::PEFileFormat;
using google_breakpad::ProcCpuInfoReader;
using google_breakpad::RawContextCPU;
+using google_breakpad::RSDS_DEBUG_FORMAT;
using google_breakpad::ThreadInfo;
using google_breakpad::TypedMDRVA;
using google_breakpad::UContextReader;
@@ -136,7 +140,7 @@ class MinidumpWriter {
: fd_(minidump_fd),
path_(minidump_path),
ucontext_(context ? &context->context : NULL),
-#if !defined(__ARM_EABI__) && !defined(__mips__)
+#if GOOGLE_BREAKPAD_CRASH_CONTEXT_HAS_FLOAT_STATE
float_state_(context ? &context->float_state : NULL),
#endif
dumper_(dumper),
@@ -468,7 +472,7 @@ class MinidumpWriter {
if (!cpu.Allocate())
return false;
my_memset(cpu.get(), 0, sizeof(RawContextCPU));
-#if !defined(__ARM_EABI__) && !defined(__mips__)
+#if GOOGLE_BREAKPAD_CRASH_CONTEXT_HAS_FLOAT_STATE
UContextReader::FillCPUContext(cpu.get(), ucontext_, float_state_);
#else
UContextReader::FillCPUContext(cpu.get(), ucontext_);
@@ -632,40 +636,88 @@ class MinidumpWriter {
mod->base_of_image = mapping.start_addr;
mod->size_of_image = mapping.size;
- auto_wasteful_vector<uint8_t, kDefaultBuildIdSize> identifier_bytes(
- dumper_->allocator());
+ char file_name[NAME_MAX];
+ char file_path[NAME_MAX];
- if (identifier) {
- // GUID was provided by caller.
- identifier_bytes.insert(identifier_bytes.end(),
- identifier,
- identifier + sizeof(MDGUID));
- } else {
- // Note: ElfFileIdentifierForMapping() can manipulate the |mapping.name|.
- dumper_->ElfFileIdentifierForMapping(mapping,
- member,
- mapping_id,
- identifier_bytes);
- }
+ dumper_->GetMappingEffectiveNameAndPath(mapping, file_path,
+ sizeof(file_path), file_name,
+ sizeof(file_name));
- if (!identifier_bytes.empty()) {
- UntypedMDRVA cv(&minidump_writer_);
- if (!cv.Allocate(MDCVInfoELF_minsize + identifier_bytes.size()))
- return false;
+ RSDS_DEBUG_FORMAT rsds;
+ PEFileFormat file_format = PEFile::TryGetDebugInfo(file_path, &rsds);
+
+ if (file_format == PEFileFormat::notPeCoff) {
+ // The module is not a PE/COFF file, process as an ELF.
+ auto_wasteful_vector<uint8_t, kDefaultBuildIdSize> identifier_bytes(
+ dumper_->allocator());
- const uint32_t cv_signature = MD_CVINFOELF_SIGNATURE;
- cv.Copy(&cv_signature, sizeof(cv_signature));
- cv.Copy(cv.position() + sizeof(cv_signature), &identifier_bytes[0],
- identifier_bytes.size());
+ if (identifier) {
+ // GUID was provided by caller.
+ identifier_bytes.insert(identifier_bytes.end(), identifier,
+ identifier + sizeof(MDGUID));
+ } else {
+ // Note: ElfFileIdentifierForMapping() can manipulate the
+ // |mapping.name|, that is why we need to call the method
+ // GetMappingEffectiveNameAndPath again.
+ dumper_->ElfFileIdentifierForMapping(mapping, member, mapping_id,
+ identifier_bytes);
+ dumper_->GetMappingEffectiveNameAndPath(mapping, file_path,
+ sizeof(file_path), file_name,
+ sizeof(file_name));
+ }
+
+ if (!identifier_bytes.empty()) {
+ UntypedMDRVA cv(&minidump_writer_);
+ if (!cv.Allocate(MDCVInfoELF_minsize + identifier_bytes.size()))
+ return false;
+
+ const uint32_t cv_signature = MD_CVINFOELF_SIGNATURE;
+ cv.Copy(&cv_signature, sizeof(cv_signature));
+ cv.Copy(cv.position() + sizeof(cv_signature), &identifier_bytes[0],
+ identifier_bytes.size());
+
+ mod->cv_record = cv.location();
+ }
+ } else {
+ // The module is a PE/COFF file. Create MDCVInfoPDB70 struct for it.
+ size_t file_name_length = strlen(file_name);
+ TypedMDRVA<MDCVInfoPDB70> cv(&minidump_writer_);
+ if (!cv.AllocateObjectAndArray(file_name_length + 1, sizeof(uint8_t)))
+ return false;
+ if (!cv.CopyIndexAfterObject(0, file_name, file_name_length))
+ return false;
+ MDCVInfoPDB70* cv_ptr = cv.get();
+ cv_ptr->cv_signature = MD_CVINFOPDB70_SIGNATURE;
+ if (file_format == PEFileFormat::peWithBuildId) {
+ // Populate BuildId and age using RSDS instance.
+ cv_ptr->signature.data1 = static_cast<uint32_t>(rsds.guid[0]) << 24 |
+ static_cast<uint32_t>(rsds.guid[1]) << 16 |
+ static_cast<uint32_t>(rsds.guid[2]) << 8 |
+ static_cast<uint32_t>(rsds.guid[3]);
+ cv_ptr->signature.data2 =
+ static_cast<uint16_t>(rsds.guid[4]) << 8 | rsds.guid[5];
+ cv_ptr->signature.data3 =
+ static_cast<uint16_t>(rsds.guid[6]) << 8 | rsds.guid[7];
+ cv_ptr->signature.data4[0] = rsds.guid[8];
+ cv_ptr->signature.data4[1] = rsds.guid[9];
+ cv_ptr->signature.data4[2] = rsds.guid[10];
+ cv_ptr->signature.data4[3] = rsds.guid[11];
+ cv_ptr->signature.data4[4] = rsds.guid[12];
+ cv_ptr->signature.data4[5] = rsds.guid[13];
+ cv_ptr->signature.data4[6] = rsds.guid[14];
+ cv_ptr->signature.data4[7] = rsds.guid[15];
+ // The Age field should be reverted as well.
+ cv_ptr->age = static_cast<uint32_t>(rsds.age[0]) << 24 |
+ static_cast<uint32_t>(rsds.age[1]) << 16 |
+ static_cast<uint32_t>(rsds.age[2]) << 8 |
+ static_cast<uint32_t>(rsds.age[3]);
+ } else {
+ cv_ptr->age = 0;
+ }
mod->cv_record = cv.location();
}
- char file_name[NAME_MAX];
- char file_path[NAME_MAX];
- dumper_->GetMappingEffectiveNameAndPath(
- mapping, file_path, sizeof(file_path), file_name, sizeof(file_name));
-
MDLocationDescriptor ld;
if (!minidump_writer_.WriteString(file_path, my_strlen(file_path), &ld))
return false;
@@ -740,14 +792,14 @@ class MinidumpWriter {
}
bool WriteDSODebugStream(MDRawDirectory* dirent) {
- ElfW(Phdr)* phdr = reinterpret_cast<ElfW(Phdr) *>(dumper_->auxv()[AT_PHDR]);
+ ElfW(Phdr)* phdr = reinterpret_cast<ElfW(Phdr)*>(dumper_->auxv()[AT_PHDR]);
char* base;
int phnum = dumper_->auxv()[AT_PHNUM];
if (!phnum || !phdr)
return false;
// Assume the program base is at the beginning of the same page as the PHDR
- base = reinterpret_cast<char *>(reinterpret_cast<uintptr_t>(phdr) & ~0xfff);
+ base = reinterpret_cast<char*>(reinterpret_cast<uintptr_t>(phdr) & ~0xfff);
// Search for the program PT_DYNAMIC segment
ElfW(Addr) dyn_addr = 0;
@@ -768,7 +820,7 @@ class MinidumpWriter {
if (!dyn_addr)
return false;
- ElfW(Dyn) *dynamic = reinterpret_cast<ElfW(Dyn) *>(dyn_addr + base);
+ ElfW(Dyn)* dynamic = reinterpret_cast<ElfW(Dyn)*>(dyn_addr + base);
// The dynamic linker makes information available that helps gdb find all
// DSOs loaded into the program. If this information is indeed available,
@@ -1085,9 +1137,7 @@ class MinidumpWriter {
sys_close(fd);
cpus_present.IntersectWith(cpus_possible);
- int cpu_count = cpus_present.GetCount();
- if (cpu_count > 255)
- cpu_count = 255;
+ int cpu_count = std::min(255, cpus_present.GetCount());
sys_info->number_of_processors = static_cast<uint8_t>(cpu_count);
}
}
@@ -1205,6 +1255,59 @@ class MinidumpWriter {
return true;
}
+#elif defined(__riscv)
+ bool WriteCPUInformation(MDRawSystemInfo* sys_info) {
+ // processor_architecture should always be set, do this first
+# if __riscv_xlen == 32
+ sys_info->processor_architecture = MD_CPU_ARCHITECTURE_RISCV;
+# elif __riscv_xlen == 64
+ sys_info->processor_architecture = MD_CPU_ARCHITECTURE_RISCV64;
+# else
+# error "Unexpected __riscv_xlen"
+# endif
+
+ // /proc/cpuinfo is not readable under various sandboxed environments
+ // (e.g. Android services with the android:isolatedProcess attribute)
+ // prepare for this by setting default values now, which will be
+ // returned when this happens.
+ //
+ // Note: Bogus values are used to distinguish between failures (to
+ // read /sys and /proc files) and really badly configured kernels.
+ sys_info->number_of_processors = 0;
+ sys_info->processor_level = 0U;
+ sys_info->processor_revision = 42;
+ sys_info->cpu.other_cpu_info.processor_features[0] = 0;
+ sys_info->cpu.other_cpu_info.processor_features[1] = 0;
+
+ // Counting the number of CPUs involves parsing two sysfs files,
+ // because the content of /proc/cpuinfo will only mirror the number
+ // of 'online' cores, and thus will vary with time.
+ // See http://www.kernel.org/doc/Documentation/cputopology.txt
+ {
+ CpuSet cpus_present;
+ CpuSet cpus_possible;
+
+ int fd = sys_open("/sys/devices/system/cpu/present",
+ O_RDONLY | O_CLOEXEC, 0);
+ if (fd >= 0) {
+ cpus_present.ParseSysFile(fd);
+ sys_close(fd);
+
+ fd = sys_open("/sys/devices/system/cpu/possible",
+ O_RDONLY | O_CLOEXEC, 0);
+ if (fd >= 0) {
+ cpus_possible.ParseSysFile(fd);
+ sys_close(fd);
+
+ cpus_present.IntersectWith(cpus_possible);
+ int cpu_count = std::min(255, cpus_present.GetCount());
+ sys_info->number_of_processors = static_cast<uint8_t>(cpu_count);
+ }
+ }
+ }
+
+ return true;
+ }
#else
# error "Unsupported CPU"
#endif
@@ -1222,7 +1325,7 @@ class MinidumpWriter {
Buffers* next;
size_t len;
uint8_t data[kBufSize];
- } *buffers = reinterpret_cast<Buffers*>(Alloc(sizeof(Buffers)));
+ }* buffers = reinterpret_cast<Buffers*>(Alloc(sizeof(Buffers)));
buffers->next = NULL;
buffers->len = 0;
@@ -1333,7 +1436,7 @@ class MinidumpWriter {
const char* path_; // Path to the file where the minidum should be written.
const ucontext_t* const ucontext_; // also from the signal handler
-#if !defined(__ARM_EABI__) && !defined(__mips__)
+#if GOOGLE_BREAKPAD_CRASH_CONTEXT_HAS_FLOAT_STATE
const google_breakpad::fpstate_t* const float_state_; // ditto
#endif
LinuxDumper* dumper_;
diff --git a/src/client/linux/minidump_writer/minidump_writer.h b/src/client/linux/minidump_writer/minidump_writer.h
index e3b0b16d..24e3c7bd 100644
--- a/src/client/linux/minidump_writer/minidump_writer.h
+++ b/src/client/linux/minidump_writer/minidump_writer.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2009, Google Inc.
-// All rights reserved.
+// Copyright 2009 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/client/linux/minidump_writer/minidump_writer_unittest.cc b/src/client/linux/minidump_writer/minidump_writer_unittest.cc
index 3017a49a..2601d29b 100644
--- a/src/client/linux/minidump_writer/minidump_writer_unittest.cc
+++ b/src/client/linux/minidump_writer/minidump_writer_unittest.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2011 Google Inc.
-// All rights reserved.
+// Copyright 2011 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -54,6 +53,8 @@
#include "google_breakpad/processor/minidump.h"
using namespace google_breakpad;
+using google_breakpad::elf::FileID;
+using google_breakpad::elf::kDefaultBuildIdSize;
namespace {
@@ -299,10 +300,10 @@ TEST(MinidumpWriterTest, MinidumpStacksSkippedIfRequested) {
Minidump minidump(templ);
ASSERT_TRUE(minidump.Read());
- MinidumpThreadList *threads = minidump.GetThreadList();
+ MinidumpThreadList* threads = minidump.GetThreadList();
int threads_with_stacks = 0;
for (unsigned int i = 0; i < threads->thread_count(); ++i) {
- MinidumpThread *thread = threads->GetThreadAtIndex(i);
+ MinidumpThread* thread = threads->GetThreadAtIndex(i);
if (thread->GetMemory()) {
++threads_with_stacks;
}
@@ -353,13 +354,13 @@ TEST(MinidumpWriterTest, StacksAreSanitizedIfRequested) {
#else
0x0defaced;
#endif
- MinidumpThreadList *threads = minidump.GetThreadList();
+ MinidumpThreadList* threads = minidump.GetThreadList();
for (unsigned int i = 0; i < threads->thread_count(); ++i) {
- MinidumpThread *thread = threads->GetThreadAtIndex(i);
- MinidumpMemoryRegion *mem = thread->GetMemory();
+ MinidumpThread* thread = threads->GetThreadAtIndex(i);
+ MinidumpMemoryRegion* mem = thread->GetMemory();
ASSERT_TRUE(mem != nullptr);
uint32_t sz = mem->GetSize();
- const uint8_t *data = mem->GetMemory();
+ const uint8_t* data = mem->GetMemory();
ASSERT_TRUE(memmem(data, sz, &defaced, sizeof(defaced)) != nullptr);
}
close(fds[1]);
@@ -521,7 +522,7 @@ TEST(MinidumpWriterTest, DeletedBinary) {
// Copy binary to a temp file.
AutoTempDir temp_dir;
string binpath = temp_dir.path() + "/linux-dumper-unittest-helper";
- ASSERT_TRUE(CopyFile(helper_path.c_str(), binpath.c_str()))
+ ASSERT_TRUE(CopyFile(helper_path, binpath))
<< "Failed to copy " << helper_path << " to " << binpath;
ASSERT_EQ(0, chmod(binpath.c_str(), 0755));
@@ -715,6 +716,9 @@ TEST(MinidumpWriterTest, InvalidStackPointer) {
#elif defined(__mips__)
context.context.uc_mcontext.gregs[MD_CONTEXT_MIPS_REG_SP] =
invalid_stack_pointer;
+#elif defined(__riscv)
+ context.context.uc_mcontext.__gregs[MD_CONTEXT_RISCV_REG_SP] =
+ invalid_stack_pointer;
#else
# error "This code has not been ported to your platform yet."
#endif
diff --git a/src/client/linux/minidump_writer/minidump_writer_unittest_utils.cc b/src/client/linux/minidump_writer/minidump_writer_unittest_utils.cc
index 9f46fa65..92cae92e 100644
--- a/src/client/linux/minidump_writer/minidump_writer_unittest_utils.cc
+++ b/src/client/linux/minidump_writer/minidump_writer_unittest_utils.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2011 Google Inc.
-// All rights reserved.
+// Copyright 2011 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -41,7 +40,7 @@ namespace google_breakpad {
string GetHelperBinary() {
string helper_path;
- char *bindir = getenv("bindir");
+ char* bindir = getenv("bindir");
if (bindir) {
helper_path = string(bindir) + "/";
} else {
diff --git a/src/client/linux/minidump_writer/minidump_writer_unittest_utils.h b/src/client/linux/minidump_writer/minidump_writer_unittest_utils.h
index f16cc086..f93885ee 100644
--- a/src/client/linux/minidump_writer/minidump_writer_unittest_utils.h
+++ b/src/client/linux/minidump_writer/minidump_writer_unittest_utils.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2012, Google Inc.
-// All rights reserved.
+// Copyright 2012 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/client/linux/minidump_writer/pe_file.cc b/src/client/linux/minidump_writer/pe_file.cc
new file mode 100644
index 00000000..960b978b
--- /dev/null
+++ b/src/client/linux/minidump_writer/pe_file.cc
@@ -0,0 +1,147 @@
+// Copyright 2022 Google LLC
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google LLC nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <string.h>
+
+#include "client/linux/minidump_writer/pe_file.h"
+#include "client/linux/minidump_writer/pe_structs.h"
+#include "common/linux/memory_mapped_file.h"
+
+namespace google_breakpad {
+
+PEFileFormat PEFile::TryGetDebugInfo(const char* filename,
+ PRSDS_DEBUG_FORMAT debug_info) {
+ MemoryMappedFile mapped_file(filename, 0);
+ if (!mapped_file.data())
+ return PEFileFormat::notPeCoff;
+ const void* base = mapped_file.data();
+ const size_t file_size = mapped_file.size();
+
+ const IMAGE_DOS_HEADER* header =
+ TryReadStruct<IMAGE_DOS_HEADER>(base, 0, file_size);
+ if (!header || (header->e_magic != IMAGE_DOS_SIGNATURE)) {
+ return PEFileFormat::notPeCoff;
+ }
+
+ // NTHeader is at position 'e_lfanew'.
+ DWORD nt_header_offset = header->e_lfanew;
+ // First, read a common IMAGE_NT_HEADERS structure. It should contain a
+ // special flag marking whether PE module is x64 (OptionalHeader.Magic)
+ // and so-called NT_SIGNATURE in Signature field.
+ const IMAGE_NT_HEADERS* nt_header =
+ TryReadStruct<IMAGE_NT_HEADERS>(base, nt_header_offset, file_size);
+ if (!nt_header || (nt_header->Signature != IMAGE_NT_SIGNATURE)
+ || ((nt_header->OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR64_MAGIC)
+ && (nt_header->OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR32_MAGIC)))
+ return PEFileFormat::notPeCoff;
+
+ bool x64 = nt_header->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC;
+ WORD sections_number = nt_header->FileHeader.NumberOfSections;
+ DWORD debug_offset;
+ DWORD debug_size;
+ DWORD section_offset;
+ if (x64) {
+ const IMAGE_NT_HEADERS64* header_64 =
+ TryReadStruct<IMAGE_NT_HEADERS64>(base, nt_header_offset, file_size);
+ if (!header_64)
+ return PEFileFormat::peWithoutBuildId;
+ debug_offset =
+ header_64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG]
+ .VirtualAddress;
+ debug_size =
+ header_64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG]
+ .Size;
+ section_offset = nt_header_offset + sizeof(IMAGE_NT_HEADERS64);
+ } else {
+ const IMAGE_NT_HEADERS32* header_32 =
+ TryReadStruct<IMAGE_NT_HEADERS32>(base, nt_header_offset, file_size);
+ if (!header_32)
+ return PEFileFormat::peWithoutBuildId;
+ debug_offset =
+ header_32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG]
+ .VirtualAddress;
+ debug_size =
+ header_32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG]
+ .Size;
+ section_offset = nt_header_offset + sizeof(IMAGE_NT_HEADERS32);
+ }
+
+ DWORD debug_end_pos = debug_offset + debug_size;
+ while (debug_offset < debug_end_pos) {
+ for (WORD i = 0; i < sections_number; ++i) {
+ // Section headers are placed sequentially after the NT_HEADER (32/64).
+ const IMAGE_SECTION_HEADER* section =
+ TryReadStruct<IMAGE_SECTION_HEADER>(base, section_offset, file_size);
+ if (!section)
+ return PEFileFormat::peWithoutBuildId;
+
+ section_offset += sizeof(IMAGE_SECTION_HEADER);
+
+ // Current `debug_offset` should be inside a section, stop if we find
+ // a suitable one (we don't consider any malformed sections here).
+ if ((section->VirtualAddress <= debug_offset) &&
+ (debug_offset < section->VirtualAddress + section->SizeOfRawData)) {
+ DWORD offset =
+ section->PointerToRawData + debug_offset - section->VirtualAddress;
+ // Go to the position of current ImageDebugDirectory (offset).
+ const IMAGE_DEBUG_DIRECTORY* debug_directory =
+ TryReadStruct<IMAGE_DEBUG_DIRECTORY>(base, offset, file_size);
+ if (!debug_directory)
+ return PEFileFormat::peWithoutBuildId;
+ // Process ImageDebugDirectory with CodeViewRecord type and skip
+ // all others.
+ if (debug_directory->Type == IMAGE_DEBUG_TYPE_CODEVIEW) {
+ DWORD debug_directory_size = debug_directory->SizeOfData;
+ if (debug_directory_size < sizeof(RSDS_DEBUG_FORMAT))
+ // RSDS section is malformed.
+ return PEFileFormat::peWithoutBuildId;
+ // Go to the position of current ImageDebugDirectory Raw Data
+ // (debug_directory->PointerToRawData) and read the RSDS section.
+ const RSDS_DEBUG_FORMAT* rsds =
+ TryReadStruct<RSDS_DEBUG_FORMAT>(
+ base, debug_directory->PointerToRawData, file_size);
+
+ if (!rsds)
+ return PEFileFormat::peWithoutBuildId;
+
+ memcpy(debug_info->guid, rsds->guid, sizeof(rsds->guid));
+ memcpy(debug_info->age, rsds->age, sizeof(rsds->age));
+ return PEFileFormat::peWithBuildId;
+ }
+
+ break;
+ }
+ }
+
+ debug_offset += sizeof(IMAGE_DEBUG_DIRECTORY);
+ }
+
+ return PEFileFormat::peWithoutBuildId;
+}
+
+} // namespace google_breakpad \ No newline at end of file
diff --git a/src/client/linux/minidump_writer/pe_file.h b/src/client/linux/minidump_writer/pe_file.h
new file mode 100644
index 00000000..97984ab5
--- /dev/null
+++ b/src/client/linux/minidump_writer/pe_file.h
@@ -0,0 +1,76 @@
+// Copyright 2022 Google LLC
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google LLC nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef CLIENT_LINUX_MINIDUMP_WRITER_PE_FILE_H_
+#define CLIENT_LINUX_MINIDUMP_WRITER_PE_FILE_H_
+
+#include "client/linux/minidump_writer/pe_structs.h"
+
+namespace google_breakpad {
+
+typedef enum {
+ notPeCoff = 0,
+ peWithoutBuildId = 1,
+ peWithBuildId = 2
+} PEFileFormat;
+
+class PEFile {
+ public:
+ /**
+ * Attempts to parse RSDS_DEBUG_FORMAT record from a PE (Portable
+ * Executable) file. To do this we check whether the loaded file is a PE
+ * file, and if it is - try to find IMAGE_DEBUG_DIRECTORY structure with
+ * its type set to IMAGE_DEBUG_TYPE_CODEVIEW.
+ *
+ * @param filename Filename for the module to parse.
+ * @param debug_info RSDS_DEBUG_FORMAT struct to be populated with PE debug
+ * info (GUID and age).
+ * @return
+ * notPeCoff: not PE/COFF file;
+ * peWithoutBuildId: a PE/COFF file but build-id is not set;
+ * peWithBuildId: a PE/COFF file and build-id is set.
+ */
+ static PEFileFormat TryGetDebugInfo(const char* filename,
+ PRSDS_DEBUG_FORMAT debug_info);
+
+ private:
+ template <class TStruct>
+ static const TStruct* TryReadStruct(const void* base,
+ const DWORD position,
+ const size_t file_size) {
+ if (position + sizeof(TStruct) >= file_size){
+ return nullptr;
+ }
+
+ const void* ptr = static_cast<const char*>(base) + position;
+ return reinterpret_cast<const TStruct*>(ptr);
+ }
+};
+
+} // namespace google_breakpad
+#endif // CLIENT_LINUX_MINIDUMP_WRITER_PE_FILE_H_ \ No newline at end of file
diff --git a/src/client/linux/minidump_writer/pe_structs.h b/src/client/linux/minidump_writer/pe_structs.h
new file mode 100644
index 00000000..122cc295
--- /dev/null
+++ b/src/client/linux/minidump_writer/pe_structs.h
@@ -0,0 +1,225 @@
+// Copyright 2022 Google LLC
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google LLC nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef CLIENT_LINUX_MINIDUMP_WRITER_PE_STRUCTS_H_
+#define CLIENT_LINUX_MINIDUMP_WRITER_PE_STRUCTS_H_
+
+#include <cstdint>
+
+namespace google_breakpad {
+
+typedef uint8_t BYTE;
+typedef uint16_t WORD;
+typedef uint32_t DWORD;
+typedef uint64_t ULONGLONG;
+
+#define IMAGE_NT_OPTIONAL_HDR32_MAGIC 0x10b
+#define IMAGE_NT_OPTIONAL_HDR64_MAGIC 0x20b
+
+#define IMAGE_DEBUG_TYPE_CODEVIEW 2
+
+#define IMAGE_DOS_SIGNATURE 0x5A4D // MZ
+#define IMAGE_NT_SIGNATURE 0x00004550 // PE00
+
+#define IMAGE_NUMBEROF_DIRECTORY_ENTRIES 16
+#define IMAGE_DIRECTORY_ENTRY_DEBUG 6
+
+typedef struct _IMAGE_DOS_HEADER { // DOS .EXE header
+ WORD e_magic; // Magic number
+ WORD e_cblp; // Bytes on last page of file
+ WORD e_cp; // Pages in file
+ WORD e_crlc; // Relocations
+ WORD e_cparhdr; // Size of header in paragraphs
+ WORD e_minalloc; // Minimum extra paragraphs needed
+ WORD e_maxalloc; // Maximum extra paragraphs needed
+ WORD e_ss; // Initial (relative) SS value
+ WORD e_sp; // Initial SP value
+ WORD e_csum; // Checksum
+ WORD e_ip; // Initial IP value
+ WORD e_cs; // Initial (relative) CS value
+ WORD e_lfarlc; // File address of relocation table
+ WORD e_ovno; // Overlay number
+ WORD e_res[4]; // Reserved words
+ WORD e_oemid; // OEM identifier (for e_oeminfo)
+ WORD e_oeminfo; // OEM information; e_oemid specific
+ WORD e_res2[10]; // Reserved words
+ DWORD e_lfanew; // File address of new exe header
+} IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;
+
+typedef struct _IMAGE_FILE_HEADER {
+ WORD Machine;
+ WORD NumberOfSections;
+ DWORD TimeDateStamp;
+ DWORD PointerToSymbolTable;
+ DWORD NumberOfSymbols;
+ WORD SizeOfOptionalHeader;
+ WORD Characteristics;
+} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;
+
+typedef struct _IMAGE_DATA_DIRECTORY {
+ DWORD VirtualAddress;
+ DWORD Size;
+} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;
+
+
+typedef struct _IMAGE_DEBUG_DIRECTORY {
+ DWORD Characteristics;
+ DWORD TimeDateStamp;
+ WORD MajorVersion;
+ WORD MinorVersion;
+ DWORD Type;
+ DWORD SizeOfData;
+ DWORD AddressOfRawData;
+ DWORD PointerToRawData;
+} IMAGE_DEBUG_DIRECTORY, *PIMAGE_DEBUG_DIRECTORY;
+
+typedef struct _IMAGE_OPTIONAL_HEADER64 {
+ //
+ // Standard fields - Magic.
+ //
+ WORD Magic;
+ BYTE MajorLinkerVersion;
+ BYTE MinorLinkerVersion;
+ DWORD SizeOfCode;
+ DWORD SizeOfInitializedData;
+ DWORD SizeOfUninitializedData;
+ DWORD AddressOfEntryPoint;
+ DWORD BaseOfCode;
+ //
+ // NT additional fields.
+ //
+ ULONGLONG ImageBase;
+ DWORD SectionAlignment;
+ DWORD FileAlignment;
+ WORD MajorOperatingSystemVersion;
+ WORD MinorOperatingSystemVersion;
+ WORD MajorImageVersion;
+ WORD MinorImageVersion;
+ WORD MajorSubsystemVersion;
+ WORD MinorSubsystemVersion;
+ DWORD Win32VersionValue;
+ DWORD SizeOfImage;
+ DWORD SizeOfHeaders;
+ DWORD CheckSum;
+ WORD Subsystem;
+ WORD DllCharacteristics;
+ ULONGLONG SizeOfStackReserve;
+ ULONGLONG SizeOfStackCommit;
+ ULONGLONG SizeOfHeapReserve;
+ ULONGLONG SizeOfHeapCommit;
+ DWORD LoaderFlags;
+ DWORD NumberOfRvaAndSizes;
+ IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
+} IMAGE_OPTIONAL_HEADER64, *PIMAGE_OPTIONAL_HEADER64;
+
+typedef struct _IMAGE_OPTIONAL_HEADER {
+ //
+ // Standard fields.
+ //
+ WORD Magic;
+ BYTE MajorLinkerVersion;
+ BYTE MinorLinkerVersion;
+ DWORD SizeOfCode;
+ DWORD SizeOfInitializedData;
+ DWORD SizeOfUninitializedData;
+ DWORD AddressOfEntryPoint;
+ DWORD BaseOfCode;
+ DWORD BaseOfData;
+ //
+ // NT additional fields.
+ //
+ DWORD ImageBase;
+ DWORD SectionAlignment;
+ DWORD FileAlignment;
+ WORD MajorOperatingSystemVersion;
+ WORD MinorOperatingSystemVersion;
+ WORD MajorImageVersion;
+ WORD MinorImageVersion;
+ WORD MajorSubsystemVersion;
+ WORD MinorSubsystemVersion;
+ DWORD Win32VersionValue;
+ DWORD SizeOfImage;
+ DWORD SizeOfHeaders;
+ DWORD CheckSum;
+ WORD Subsystem;
+ WORD DllCharacteristics;
+ DWORD SizeOfStackReserve;
+ DWORD SizeOfStackCommit;
+ DWORD SizeOfHeapReserve;
+ DWORD SizeOfHeapCommit;
+ DWORD LoaderFlags;
+ DWORD NumberOfRvaAndSizes;
+ IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
+} IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32;
+
+typedef struct _IMAGE_NT_HEADERS64 {
+ DWORD Signature;
+ IMAGE_FILE_HEADER FileHeader;
+ IMAGE_OPTIONAL_HEADER64 OptionalHeader;
+} IMAGE_NT_HEADERS64, *PIMAGE_NT_HEADERS64;
+
+typedef struct _IMAGE_NT_HEADERS32 {
+ DWORD Signature;
+ IMAGE_FILE_HEADER FileHeader;
+ IMAGE_OPTIONAL_HEADER32 OptionalHeader;
+} IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32;
+
+typedef struct _IMAGE_NT_HEADERS {
+ DWORD Signature;
+ IMAGE_FILE_HEADER FileHeader;
+ IMAGE_OPTIONAL_HEADER32 OptionalHeader;
+} IMAGE_NT_HEADERS, *PIMAGE_NT_HEADERS;
+
+#define IMAGE_SIZEOF_SHORT_NAME 8
+
+typedef struct _IMAGE_SECTION_HEADER {
+ BYTE Name[IMAGE_SIZEOF_SHORT_NAME];
+ union {
+ DWORD PhysicalAddress;
+ DWORD VirtualSize;
+ } Misc;
+ DWORD VirtualAddress;
+ DWORD SizeOfRawData;
+ DWORD PointerToRawData;
+ DWORD PointerToRelocations;
+ DWORD PointerToLinenumbers;
+ WORD NumberOfRelocations;
+ WORD NumberOfLinenumbers;
+ DWORD Characteristics;
+} IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;
+
+typedef struct _RSDS_DEBUG_FORMAT {
+ DWORD signature;
+ BYTE guid[16];
+ BYTE age[4];
+ char pdbpath[1];
+} RSDS_DEBUG_FORMAT, *PRSDS_DEBUG_FORMAT;
+
+} // namespace google_breakpad
+
+#endif // CLIENT_LINUX_MINIDUMP_WRITER_PE_STRUCTS_H_ \ No newline at end of file
diff --git a/src/client/linux/minidump_writer/proc_cpuinfo_reader.h b/src/client/linux/minidump_writer/proc_cpuinfo_reader.h
index d9461bf3..5ae16dfb 100644
--- a/src/client/linux/minidump_writer/proc_cpuinfo_reader.h
+++ b/src/client/linux/minidump_writer/proc_cpuinfo_reader.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2013, Google Inc.
-// All rights reserved.
+// Copyright 2013 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/client/linux/minidump_writer/proc_cpuinfo_reader_unittest.cc b/src/client/linux/minidump_writer/proc_cpuinfo_reader_unittest.cc
index 6037c7e6..f6d3e285 100644
--- a/src/client/linux/minidump_writer/proc_cpuinfo_reader_unittest.cc
+++ b/src/client/linux/minidump_writer/proc_cpuinfo_reader_unittest.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2013, Google Inc.
-// All rights reserved.
+// Copyright 2013 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -65,7 +64,7 @@ TEST(ProcCpuInfoReaderTest, EmptyFile) {
ASSERT_TRUE(file.IsOk());
ProcCpuInfoReader reader(file.GetFd());
- const char *field;
+ const char* field;
ASSERT_FALSE(reader.GetNextField(&field));
}
@@ -74,7 +73,7 @@ TEST(ProcCpuInfoReaderTest, OneLineTerminated) {
ASSERT_TRUE(file.IsOk());
ProcCpuInfoReader reader(file.GetFd());
- const char *field;
+ const char* field;
ASSERT_TRUE(reader.GetNextField(&field));
ASSERT_STREQ("foo", field);
ASSERT_STREQ("bar", reader.GetValue());
@@ -87,7 +86,7 @@ TEST(ProcCpuInfoReaderTest, OneLine) {
ASSERT_TRUE(file.IsOk());
ProcCpuInfoReader reader(file.GetFd());
- const char *field;
+ const char* field;
size_t value_len;
ASSERT_TRUE(reader.GetNextField(&field));
ASSERT_STREQ("foo", field);
diff --git a/src/client/linux/sender/google_crash_report_sender.cc b/src/client/linux/sender/google_crash_report_sender.cc
index f83a0e89..6f45d831 100644
--- a/src/client/linux/sender/google_crash_report_sender.cc
+++ b/src/client/linux/sender/google_crash_report_sender.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2009, Google Inc.
-// All rights reserved.
+// Copyright 2009 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -84,7 +83,7 @@ bool CheckForRequiredFlagsOrDie() {
return true;
}
-int main(int argc, char *argv[]) {
+int main(int argc, char* argv[]) {
google::InitGoogleLogging(argv[0]);
google::ParseCommandLineFlags(&argc, &argv, true);
if (!CheckForRequiredFlagsOrDie()) {
diff --git a/src/client/mac/Breakpad.xcodeproj/project.pbxproj b/src/client/mac/Breakpad.xcodeproj/project.pbxproj
index 10876535..ed782c91 100644
--- a/src/client/mac/Breakpad.xcodeproj/project.pbxproj
+++ b/src/client/mac/Breakpad.xcodeproj/project.pbxproj
@@ -149,6 +149,22 @@
D2F9A53F121383A1002747C1 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0867D69BFE84028FC02AAC07 /* Foundation.framework */; };
D2F9A541121383A1002747C1 /* libgtest.a in Frameworks */ = {isa = PBXBuildFile; fileRef = D2F9A41512131EF0002747C1 /* libgtest.a */; };
D2F9A553121383DC002747C1 /* crash_generation_server_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = D2F9A4CE121336F7002747C1 /* crash_generation_server_test.cc */; };
+ EB9CF8B924F01E1D00F9B6D1 /* encoding_util.m in Sources */ = {isa = PBXBuildFile; fileRef = EB9CF89F24F01E1D00F9B6D1 /* encoding_util.m */; };
+ EB9CF8BA24F01E1D00F9B6D1 /* minidump_upload.m in Sources */ = {isa = PBXBuildFile; fileRef = EB9CF8AD24F01E1D00F9B6D1 /* minidump_upload.m */; };
+ EB9CF8BB24F01E1D00F9B6D1 /* encoding_util.h in Headers */ = {isa = PBXBuildFile; fileRef = EB9CF8AE24F01E1D00F9B6D1 /* encoding_util.h */; };
+ EB9CF8BC24F01E1D00F9B6D1 /* HTTPSimplePostRequest.h in Headers */ = {isa = PBXBuildFile; fileRef = EB9CF8AF24F01E1D00F9B6D1 /* HTTPSimplePostRequest.h */; };
+ EB9CF8BD24F01E1D00F9B6D1 /* HTTPRequest.h in Headers */ = {isa = PBXBuildFile; fileRef = EB9CF8B024F01E1D00F9B6D1 /* HTTPRequest.h */; };
+ EB9CF8BE24F01E1D00F9B6D1 /* HTTPPutRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = EB9CF8B124F01E1D00F9B6D1 /* HTTPPutRequest.m */; };
+ EB9CF8BF24F01E1D00F9B6D1 /* HTTPRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = EB9CF8B224F01E1D00F9B6D1 /* HTTPRequest.m */; };
+ EB9CF8C024F01E1D00F9B6D1 /* SymbolCollectorClient.m in Sources */ = {isa = PBXBuildFile; fileRef = EB9CF8B324F01E1D00F9B6D1 /* SymbolCollectorClient.m */; };
+ EB9CF8C124F01E1D00F9B6D1 /* HTTPGetRequest.h in Headers */ = {isa = PBXBuildFile; fileRef = EB9CF8B424F01E1D00F9B6D1 /* HTTPGetRequest.h */; };
+ EB9CF8C224F01E1D00F9B6D1 /* HTTPGetRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = EB9CF8B524F01E1D00F9B6D1 /* HTTPGetRequest.m */; };
+ EB9CF8C324F01E1D00F9B6D1 /* HTTPSimplePostRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = EB9CF8B624F01E1D00F9B6D1 /* HTTPSimplePostRequest.m */; };
+ EB9CF8C424F01E1D00F9B6D1 /* SymbolCollectorClient.h in Headers */ = {isa = PBXBuildFile; fileRef = EB9CF8B724F01E1D00F9B6D1 /* SymbolCollectorClient.h */; };
+ EB9CF8C524F01E1D00F9B6D1 /* HTTPPutRequest.h in Headers */ = {isa = PBXBuildFile; fileRef = EB9CF8B824F01E1D00F9B6D1 /* HTTPPutRequest.h */; };
+ EB9CF8C624F01F1100F9B6D1 /* HTTPRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = EB9CF8B224F01E1D00F9B6D1 /* HTTPRequest.m */; };
+ EB9CF8C724F01F7600F9B6D1 /* encoding_util.m in Sources */ = {isa = PBXBuildFile; fileRef = EB9CF89F24F01E1D00F9B6D1 /* encoding_util.m */; };
+ EB9CF8C824F01FB900F9B6D1 /* HTTPMultipartUpload.m in Sources */ = {isa = PBXBuildFile; fileRef = F92C53770ECCE635009BE4BA /* HTTPMultipartUpload.m */; };
F4DAB1DD19F1027100A5A838 /* launch_reporter.cc in Sources */ = {isa = PBXBuildFile; fileRef = F4DAB1DB19F1027100A5A838 /* launch_reporter.cc */; };
F4DAB1DE19F1027100A5A838 /* launch_reporter.h in Headers */ = {isa = PBXBuildFile; fileRef = F4DAB1DC19F1027100A5A838 /* launch_reporter.h */; };
F4F916B619F10FFC00B83BE4 /* launch_reporter.cc in Sources */ = {isa = PBXBuildFile; fileRef = F4DAB1DB19F1027100A5A838 /* launch_reporter.cc */; };
@@ -634,6 +650,19 @@
DE43468E11C72971004F095F /* sl */ = {isa = PBXFileReference; fileEncoding = 10; lastKnownFileType = text.plist.strings; name = sl; path = sender/sl.lproj/InfoPlist.strings; sourceTree = "<group>"; };
DE43468F11C72973004F095F /* sv */ = {isa = PBXFileReference; fileEncoding = 10; lastKnownFileType = text.plist.strings; name = sv; path = sender/sv.lproj/InfoPlist.strings; sourceTree = "<group>"; };
DE43469011C72976004F095F /* tr */ = {isa = PBXFileReference; fileEncoding = 10; lastKnownFileType = text.plist.strings; name = tr; path = sender/tr.lproj/InfoPlist.strings; sourceTree = "<group>"; };
+ EB9CF89F24F01E1D00F9B6D1 /* encoding_util.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = encoding_util.m; path = ../../common/mac/encoding_util.m; sourceTree = "<group>"; };
+ EB9CF8AD24F01E1D00F9B6D1 /* minidump_upload.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = minidump_upload.m; path = ../../common/mac/minidump_upload.m; sourceTree = "<group>"; };
+ EB9CF8AE24F01E1D00F9B6D1 /* encoding_util.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = encoding_util.h; path = ../../common/mac/encoding_util.h; sourceTree = "<group>"; };
+ EB9CF8AF24F01E1D00F9B6D1 /* HTTPSimplePostRequest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = HTTPSimplePostRequest.h; path = ../../common/mac/HTTPSimplePostRequest.h; sourceTree = "<group>"; };
+ EB9CF8B024F01E1D00F9B6D1 /* HTTPRequest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = HTTPRequest.h; path = ../../common/mac/HTTPRequest.h; sourceTree = "<group>"; };
+ EB9CF8B124F01E1D00F9B6D1 /* HTTPPutRequest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = HTTPPutRequest.m; path = ../../common/mac/HTTPPutRequest.m; sourceTree = "<group>"; };
+ EB9CF8B224F01E1D00F9B6D1 /* HTTPRequest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = HTTPRequest.m; path = ../../common/mac/HTTPRequest.m; sourceTree = "<group>"; };
+ EB9CF8B324F01E1D00F9B6D1 /* SymbolCollectorClient.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = SymbolCollectorClient.m; path = ../../common/mac/SymbolCollectorClient.m; sourceTree = "<group>"; };
+ EB9CF8B424F01E1D00F9B6D1 /* HTTPGetRequest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = HTTPGetRequest.h; path = ../../common/mac/HTTPGetRequest.h; sourceTree = "<group>"; };
+ EB9CF8B524F01E1D00F9B6D1 /* HTTPGetRequest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = HTTPGetRequest.m; path = ../../common/mac/HTTPGetRequest.m; sourceTree = "<group>"; };
+ EB9CF8B624F01E1D00F9B6D1 /* HTTPSimplePostRequest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = HTTPSimplePostRequest.m; path = ../../common/mac/HTTPSimplePostRequest.m; sourceTree = "<group>"; };
+ EB9CF8B724F01E1D00F9B6D1 /* SymbolCollectorClient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SymbolCollectorClient.h; path = ../../common/mac/SymbolCollectorClient.h; sourceTree = "<group>"; };
+ EB9CF8B824F01E1D00F9B6D1 /* HTTPPutRequest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = HTTPPutRequest.h; path = ../../common/mac/HTTPPutRequest.h; sourceTree = "<group>"; };
F4DAB1DB19F1027100A5A838 /* launch_reporter.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = launch_reporter.cc; path = ../../common/mac/launch_reporter.cc; sourceTree = SOURCE_ROOT; };
F4DAB1DC19F1027100A5A838 /* launch_reporter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = launch_reporter.h; path = ../../common/mac/launch_reporter.h; sourceTree = SOURCE_ROOT; };
F91AF5CF0FD60393009D8BE2 /* BreakpadFramework_Test.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = BreakpadFramework_Test.mm; path = tests/BreakpadFramework_Test.mm; sourceTree = "<group>"; };
@@ -959,6 +988,19 @@
F92C53840ECCE68D009BE4BA /* mac */ = {
isa = PBXGroup;
children = (
+ EB9CF8AE24F01E1D00F9B6D1 /* encoding_util.h */,
+ EB9CF89F24F01E1D00F9B6D1 /* encoding_util.m */,
+ EB9CF8B424F01E1D00F9B6D1 /* HTTPGetRequest.h */,
+ EB9CF8B524F01E1D00F9B6D1 /* HTTPGetRequest.m */,
+ EB9CF8B824F01E1D00F9B6D1 /* HTTPPutRequest.h */,
+ EB9CF8B124F01E1D00F9B6D1 /* HTTPPutRequest.m */,
+ EB9CF8B024F01E1D00F9B6D1 /* HTTPRequest.h */,
+ EB9CF8B224F01E1D00F9B6D1 /* HTTPRequest.m */,
+ EB9CF8AF24F01E1D00F9B6D1 /* HTTPSimplePostRequest.h */,
+ EB9CF8B624F01E1D00F9B6D1 /* HTTPSimplePostRequest.m */,
+ EB9CF8AD24F01E1D00F9B6D1 /* minidump_upload.m */,
+ EB9CF8B724F01E1D00F9B6D1 /* SymbolCollectorClient.h */,
+ EB9CF8B324F01E1D00F9B6D1 /* SymbolCollectorClient.m */,
162F64F0161C577500CD68D5 /* arch_utilities.cc */,
162F64F1161C577500CD68D5 /* arch_utilities.h */,
8B31007011F0CD3C00FCF3E4 /* GTMDefines.h */,
@@ -1155,13 +1197,19 @@
buildActionMask = 2147483647;
files = (
F92C55D00ECD0064009BE4BA /* Breakpad.h in Headers */,
+ EB9CF8BC24F01E1D00F9B6D1 /* HTTPSimplePostRequest.h in Headers */,
+ EB9CF8BB24F01E1D00F9B6D1 /* encoding_util.h in Headers */,
F92C56330ECD0DF1009BE4BA /* OnDemandServer.h in Headers */,
+ EB9CF8BD24F01E1D00F9B6D1 /* HTTPRequest.h in Headers */,
D2F9A4C9121336C7002747C1 /* client_info.h in Headers */,
+ EB9CF8C524F01E1D00F9B6D1 /* HTTPPutRequest.h in Headers */,
D2F9A4CA121336C7002747C1 /* crash_generation_client.h in Headers */,
D2F9A4CC121336C7002747C1 /* crash_generation_server.h in Headers */,
163201D61443019E00C4DBF5 /* ConfigFile.h in Headers */,
+ EB9CF8C424F01E1D00F9B6D1 /* SymbolCollectorClient.h in Headers */,
16C7C918147D45AE00776EAD /* BreakpadDefines.h in Headers */,
421BC5BD21110C0300B8042E /* convert_old_arm64_context.h in Headers */,
+ EB9CF8C124F01E1D00F9B6D1 /* HTTPGetRequest.h in Headers */,
162F64F3161C577500CD68D5 /* arch_utilities.h in Headers */,
F4DAB1DE19F1027100A5A838 /* launch_reporter.h in Headers */,
1EEEB6241720829E00F7E689 /* simple_string_dictionary.h in Headers */,
@@ -1684,8 +1732,12 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
+ EB9CF8C824F01FB900F9B6D1 /* HTTPMultipartUpload.m in Sources */,
+ EB9CF8C224F01E1D00F9B6D1 /* HTTPGetRequest.m in Sources */,
F92C565F0ECD116B009BE4BA /* protected_memory_allocator.cc in Sources */,
+ EB9CF8BA24F01E1D00F9B6D1 /* minidump_upload.m in Sources */,
F92C56630ECD1179009BE4BA /* exception_handler.cc in Sources */,
+ EB9CF8BE24F01E1D00F9B6D1 /* HTTPPutRequest.m in Sources */,
F92C55D10ECD0064009BE4BA /* Breakpad.mm in Sources */,
F4DAB1DD19F1027100A5A838 /* launch_reporter.cc in Sources */,
F92C56340ECD0DF1009BE4BA /* OnDemandServer.mm in Sources */,
@@ -1694,6 +1746,10 @@
163201D71443019E00C4DBF5 /* ConfigFile.mm in Sources */,
162F64F2161C577500CD68D5 /* arch_utilities.cc in Sources */,
1EEEB6231720829E00F7E689 /* simple_string_dictionary.cc in Sources */,
+ EB9CF8C324F01E1D00F9B6D1 /* HTTPSimplePostRequest.m in Sources */,
+ EB9CF8B924F01E1D00F9B6D1 /* encoding_util.m in Sources */,
+ EB9CF8BF24F01E1D00F9B6D1 /* HTTPRequest.m in Sources */,
+ EB9CF8C024F01E1D00F9B6D1 /* SymbolCollectorClient.m in Sources */,
421BC5BC21110C0300B8042E /* convert_old_arm64_context.cc in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
@@ -1800,6 +1856,8 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
+ EB9CF8C724F01F7600F9B6D1 /* encoding_util.m in Sources */,
+ EB9CF8C624F01F1100F9B6D1 /* HTTPRequest.m in Sources */,
F9C44EA20EF09F93003AEBAA /* HTTPMultipartUpload.m in Sources */,
F92C56A90ECE04C5009BE4BA /* crash_report_sender.m in Sources */,
F9C44EE90EF0A3C1003AEBAA /* GTMLogger.m in Sources */,
@@ -2794,4 +2852,4 @@
/* End XCConfigurationList section */
};
rootObject = 0867D690FE84028FC02AAC07 /* Project object */;
-}
+} \ No newline at end of file
diff --git a/src/client/mac/Framework/Breakpad.h b/src/client/mac/Framework/Breakpad.h
index dc7e45d1..e2b48aa1 100644
--- a/src/client/mac/Framework/Breakpad.h
+++ b/src/client/mac/Framework/Breakpad.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2006, Google Inc.
-// All rights reserved.
+// Copyright 2006 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -45,7 +44,7 @@
// OnDemandServer and restored in Inspector.
#define BREAKPAD_BOOTSTRAP_PARENT_PORT "com.Breakpad.BootstrapParent"
-typedef void *BreakpadRef;
+typedef void* BreakpadRef;
#ifdef __cplusplus
extern "C" {
@@ -65,7 +64,7 @@ extern "C" {
typedef bool (*BreakpadFilterCallback)(int exception_type,
int exception_code,
mach_port_t crashing_thread,
- void *context);
+ void* context);
// Create a new BreakpadRef object and install it as an exception
// handler. The |parameters| will typically be the contents of your
@@ -226,7 +225,7 @@ typedef bool (*BreakpadFilterCallback)(int exception_type,
// Only used in crash_report_sender.
// Returns a new BreakpadRef object on success, NULL otherwise.
-BreakpadRef BreakpadCreate(NSDictionary *parameters);
+BreakpadRef BreakpadCreate(NSDictionary* parameters);
// Uninstall and release the data associated with |ref|.
void BreakpadRelease(BreakpadRef ref);
@@ -238,7 +237,7 @@ void BreakpadRelease(BreakpadRef ref);
// Context is a pointer to arbitrary data to make the callback with.
void BreakpadSetFilterCallback(BreakpadRef ref,
BreakpadFilterCallback callback,
- void *context);
+ void* context);
// User defined key and value string storage. Generally this is used
// to configure Breakpad's internal operation, such as whether the
@@ -259,23 +258,23 @@ void BreakpadSetFilterCallback(BreakpadRef ref,
// TODO (nealsid): separate server parameter dictionary from the
// dictionary used to configure Breakpad, and document limits for each
// independently.
-void BreakpadSetKeyValue(BreakpadRef ref, NSString *key, NSString *value);
-NSString *BreakpadKeyValue(BreakpadRef ref, NSString *key);
-void BreakpadRemoveKeyValue(BreakpadRef ref, NSString *key);
+void BreakpadSetKeyValue(BreakpadRef ref, NSString* key, NSString* value);
+NSString* BreakpadKeyValue(BreakpadRef ref, NSString* key);
+void BreakpadRemoveKeyValue(BreakpadRef ref, NSString* key);
// You can use this method to specify parameters that will be uploaded
// to the crash server. They will be automatically encoded as
// necessary. Note that as mentioned above there are limits on both
// the number of keys and their length.
-void BreakpadAddUploadParameter(BreakpadRef ref, NSString *key,
- NSString *value);
+void BreakpadAddUploadParameter(BreakpadRef ref, NSString* key,
+ NSString* value);
// This method will remove a previously-added parameter from the
// upload parameter set.
-void BreakpadRemoveUploadParameter(BreakpadRef ref, NSString *key);
+void BreakpadRemoveUploadParameter(BreakpadRef ref, NSString* key);
// Add a log file for Breakpad to read and send upon crash dump
-void BreakpadAddLogFile(BreakpadRef ref, NSString *logPathname);
+void BreakpadAddLogFile(BreakpadRef ref, NSString* logPathname);
// Generate a minidump and send
void BreakpadGenerateAndSendReport(BreakpadRef ref);
diff --git a/src/client/mac/Framework/Breakpad.mm b/src/client/mac/Framework/Breakpad.mm
index b2140549..def43b7d 100644
--- a/src/client/mac/Framework/Breakpad.mm
+++ b/src/client/mac/Framework/Breakpad.mm
@@ -1,5 +1,4 @@
-// Copyright (c) 2006, Google Inc.
-// All rights reserved.
+// Copyright 2006 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -81,9 +80,9 @@ using google_breakpad::SimpleStringDictionary;
// allocation of C++ objects. Note that we don't use operator delete()
// but instead call the objects destructor directly: object->~ClassName();
//
-ProtectedMemoryAllocator *gMasterAllocator = NULL;
-ProtectedMemoryAllocator *gKeyValueAllocator = NULL;
-ProtectedMemoryAllocator *gBreakpadAllocator = NULL;
+ProtectedMemoryAllocator* gMasterAllocator = NULL;
+ProtectedMemoryAllocator* gKeyValueAllocator = NULL;
+ProtectedMemoryAllocator* gBreakpadAllocator = NULL;
// Mutex for thread-safe access to the key/value dictionary used by breakpad.
// It's a global instead of an instance variable of Breakpad
@@ -98,8 +97,8 @@ pthread_mutex_t gDictionaryMutex;
// Its destructor will first re-protect the memory then release the lock.
class ProtectedMemoryLocker {
public:
- ProtectedMemoryLocker(pthread_mutex_t *mutex,
- ProtectedMemoryAllocator *allocator)
+ ProtectedMemoryLocker(pthread_mutex_t* mutex,
+ ProtectedMemoryAllocator* allocator)
: mutex_(mutex),
allocator_(allocator) {
// Lock the mutex
@@ -124,17 +123,17 @@ class ProtectedMemoryLocker {
ProtectedMemoryLocker(const ProtectedMemoryLocker&);
ProtectedMemoryLocker& operator=(const ProtectedMemoryLocker&);
- pthread_mutex_t *mutex_;
- ProtectedMemoryAllocator *allocator_;
+ pthread_mutex_t* mutex_;
+ ProtectedMemoryAllocator* allocator_;
};
//=============================================================================
class Breakpad {
public:
// factory method
- static Breakpad *Create(NSDictionary *parameters) {
+ static Breakpad* Create(NSDictionary* parameters) {
// Allocate from our special allocation pool
- Breakpad *breakpad =
+ Breakpad* breakpad =
new (gBreakpadAllocator->Allocate(sizeof(Breakpad)))
Breakpad();
@@ -152,13 +151,13 @@ class Breakpad {
~Breakpad();
- void SetKeyValue(NSString *key, NSString *value);
- NSString *KeyValue(NSString *key);
- void RemoveKeyValue(NSString *key);
+ void SetKeyValue(NSString* key, NSString* value);
+ NSString* KeyValue(NSString* key);
+ void RemoveKeyValue(NSString* key);
void GenerateAndSendReport();
- void SetFilterCallback(BreakpadFilterCallback callback, void *context) {
+ void SetFilterCallback(BreakpadFilterCallback callback, void* context) {
filter_callback_ = callback;
filter_callback_context_ = context;
}
@@ -173,14 +172,14 @@ class Breakpad {
inspector_path_[0] = 0;
}
- bool Initialize(NSDictionary *parameters);
- bool InitializeInProcess(NSDictionary *parameters);
- bool InitializeOutOfProcess(NSDictionary *parameters);
+ bool Initialize(NSDictionary* parameters);
+ bool InitializeInProcess(NSDictionary* parameters);
+ bool InitializeOutOfProcess(NSDictionary* parameters);
- bool ExtractParameters(NSDictionary *parameters);
+ bool ExtractParameters(NSDictionary* parameters);
// Dispatches to HandleException()
- static bool ExceptionHandlerDirectCallback(void *context,
+ static bool ExceptionHandlerDirectCallback(void* context,
int exception_type,
int exception_code,
int exception_subcode,
@@ -194,28 +193,28 @@ class Breakpad {
// Dispatches to HandleMinidump().
// This gets called instead of ExceptionHandlerDirectCallback when running
// with the BREAKPAD_IN_PROCESS option.
- static bool HandleMinidumpCallback(const char *dump_dir,
- const char *minidump_id,
- void *context,
+ static bool HandleMinidumpCallback(const char* dump_dir,
+ const char* minidump_id,
+ void* context,
bool succeeded);
// This is only used when BREAKPAD_IN_PROCESS is YES.
- bool HandleMinidump(const char *dump_dir, const char *minidump_id);
+ bool HandleMinidump(const char* dump_dir, const char* minidump_id);
// Since ExceptionHandler (w/o namespace) is defined as typedef in OSX's
// MachineExceptions.h, we have to explicitly name the handler.
- google_breakpad::ExceptionHandler *handler_; // The actual handler (STRONG)
+ google_breakpad::ExceptionHandler* handler_; // The actual handler (STRONG)
char inspector_path_[PATH_MAX]; // Path to inspector tool
- SimpleStringDictionary *config_params_; // Create parameters (STRONG)
+ SimpleStringDictionary* config_params_; // Create parameters (STRONG)
OnDemandServer inspector_;
bool send_and_exit_; // Exit after sending, if true
BreakpadFilterCallback filter_callback_;
- void *filter_callback_context_;
+ void* filter_callback_context_;
};
#pragma mark -
@@ -227,14 +226,14 @@ class Breakpad {
//=============================================================================
static BOOL IsDebuggerActive() {
BOOL result = NO;
- NSUserDefaults *stdDefaults = [NSUserDefaults standardUserDefaults];
+ NSUserDefaults* stdDefaults = [NSUserDefaults standardUserDefaults];
// We check both defaults and the environment variable here
BOOL ignoreDebugger = [stdDefaults boolForKey:@IGNORE_DEBUGGER];
if (!ignoreDebugger) {
- char *ignoreDebuggerStr = getenv(IGNORE_DEBUGGER);
+ char* ignoreDebuggerStr = getenv(IGNORE_DEBUGGER);
ignoreDebugger = (ignoreDebuggerStr ? strtol(ignoreDebuggerStr, NULL, 10) : 0) != 0;
}
@@ -245,7 +244,7 @@ static BOOL IsDebuggerActive() {
size_t actualSize;
if (sysctl(mib, mibSize, NULL, &actualSize, NULL, 0) == 0) {
- struct kinfo_proc *info = (struct kinfo_proc *)malloc(actualSize);
+ struct kinfo_proc* info = (struct kinfo_proc*)malloc(actualSize);
if (info) {
// This comes from looking at the Darwin xnu Kernel
@@ -261,12 +260,12 @@ static BOOL IsDebuggerActive() {
}
//=============================================================================
-bool Breakpad::ExceptionHandlerDirectCallback(void *context,
- int exception_type,
- int exception_code,
- int exception_subcode,
- mach_port_t crashing_thread) {
- Breakpad *breakpad = (Breakpad *)context;
+bool Breakpad::ExceptionHandlerDirectCallback(void* context,
+ int exception_type,
+ int exception_code,
+ int exception_subcode,
+ mach_port_t crashing_thread) {
+ Breakpad* breakpad = (Breakpad*)context;
// If our context is damaged or something, just return false to indicate that
// the handler should continue without us.
@@ -280,11 +279,11 @@ bool Breakpad::ExceptionHandlerDirectCallback(void *context,
}
//=============================================================================
-bool Breakpad::HandleMinidumpCallback(const char *dump_dir,
- const char *minidump_id,
- void *context,
+bool Breakpad::HandleMinidumpCallback(const char* dump_dir,
+ const char* minidump_id,
+ void* context,
bool succeeded) {
- Breakpad *breakpad = (Breakpad *)context;
+ Breakpad* breakpad = (Breakpad*)context;
// If our context is damaged or something, just return false to indicate that
// the handler should continue without us.
@@ -307,9 +306,9 @@ bool Breakpad::HandleMinidumpCallback(const char *dump_dir,
// simple non-static C name
//
extern "C" {
-NSString * GetResourcePath();
-NSString * GetResourcePath() {
- NSString *resourcePath = nil;
+NSString* GetResourcePath();
+NSString* GetResourcePath() {
+ NSString* resourcePath = nil;
// If there are multiple breakpads installed then calling bundleWithIdentifier
// will not work properly, so only use that as a backup plan.
@@ -320,17 +319,17 @@ NSString * GetResourcePath() {
// Get the pathname to the code which contains this function
Dl_info info;
if (dladdr((const void*)GetResourcePath, &info) != 0) {
- NSFileManager *filemgr = [NSFileManager defaultManager];
- NSString *filePath =
+ NSFileManager* filemgr = [NSFileManager defaultManager];
+ NSString* filePath =
[filemgr stringWithFileSystemRepresentation:info.dli_fname
length:strlen(info.dli_fname)];
- NSString *bundlePath = [filePath stringByDeletingLastPathComponent];
+ NSString* bundlePath = [filePath stringByDeletingLastPathComponent];
// The "Resources" directory should be in the same directory as the
// executable code, since that's how the Breakpad framework is built.
resourcePath = [bundlePath stringByAppendingPathComponent:@"Resources/"];
} else {
// fallback plan
- NSBundle *bundle =
+ NSBundle* bundle =
[NSBundle bundleWithIdentifier:@"com.Google.BreakpadFramework"];
resourcePath = [bundle resourcePath];
}
@@ -340,7 +339,7 @@ NSString * GetResourcePath() {
} // extern "C"
//=============================================================================
-bool Breakpad::Initialize(NSDictionary *parameters) {
+bool Breakpad::Initialize(NSDictionary* parameters) {
// Initialize
config_params_ = NULL;
handler_ = NULL;
@@ -375,7 +374,7 @@ bool Breakpad::InitializeInProcess(NSDictionary* parameters) {
//=============================================================================
bool Breakpad::InitializeOutOfProcess(NSDictionary* parameters) {
// Get path to Inspector executable.
- NSString *inspectorPathString = KeyValue(@BREAKPAD_INSPECTOR_LOCATION);
+ NSString* inspectorPathString = KeyValue(@BREAKPAD_INSPECTOR_LOCATION);
// Standardize path (resolve symlinkes, etc.) and escape spaces
inspectorPathString = [inspectorPathString stringByStandardizingPath];
@@ -434,34 +433,34 @@ Breakpad::~Breakpad() {
}
//=============================================================================
-bool Breakpad::ExtractParameters(NSDictionary *parameters) {
- NSUserDefaults *stdDefaults = [NSUserDefaults standardUserDefaults];
- NSString *skipConfirm = [stdDefaults stringForKey:@BREAKPAD_SKIP_CONFIRM];
- NSString *sendAndExit = [stdDefaults stringForKey:@BREAKPAD_SEND_AND_EXIT];
-
- NSString *serverType = [parameters objectForKey:@BREAKPAD_SERVER_TYPE];
- NSString *display = [parameters objectForKey:@BREAKPAD_PRODUCT_DISPLAY];
- NSString *product = [parameters objectForKey:@BREAKPAD_PRODUCT];
- NSString *version = [parameters objectForKey:@BREAKPAD_VERSION];
- NSString *urlStr = [parameters objectForKey:@BREAKPAD_URL];
- NSString *interval = [parameters objectForKey:@BREAKPAD_REPORT_INTERVAL];
- NSString *inspectorPathString =
+bool Breakpad::ExtractParameters(NSDictionary* parameters) {
+ NSUserDefaults* stdDefaults = [NSUserDefaults standardUserDefaults];
+ NSString* skipConfirm = [stdDefaults stringForKey:@BREAKPAD_SKIP_CONFIRM];
+ NSString* sendAndExit = [stdDefaults stringForKey:@BREAKPAD_SEND_AND_EXIT];
+
+ NSString* serverType = [parameters objectForKey:@BREAKPAD_SERVER_TYPE];
+ NSString* display = [parameters objectForKey:@BREAKPAD_PRODUCT_DISPLAY];
+ NSString* product = [parameters objectForKey:@BREAKPAD_PRODUCT];
+ NSString* version = [parameters objectForKey:@BREAKPAD_VERSION];
+ NSString* urlStr = [parameters objectForKey:@BREAKPAD_URL];
+ NSString* interval = [parameters objectForKey:@BREAKPAD_REPORT_INTERVAL];
+ NSString* inspectorPathString =
[parameters objectForKey:@BREAKPAD_INSPECTOR_LOCATION];
- NSString *reporterPathString =
+ NSString* reporterPathString =
[parameters objectForKey:@BREAKPAD_REPORTER_EXE_LOCATION];
- NSString *timeout = [parameters objectForKey:@BREAKPAD_CONFIRM_TIMEOUT];
- NSArray *logFilePaths = [parameters objectForKey:@BREAKPAD_LOGFILES];
- NSString *logFileTailSize =
+ NSString* timeout = [parameters objectForKey:@BREAKPAD_CONFIRM_TIMEOUT];
+ NSArray* logFilePaths = [parameters objectForKey:@BREAKPAD_LOGFILES];
+ NSString* logFileTailSize =
[parameters objectForKey:@BREAKPAD_LOGFILE_UPLOAD_SIZE];
- NSString *requestUserText =
+ NSString* requestUserText =
[parameters objectForKey:@BREAKPAD_REQUEST_COMMENTS];
- NSString *requestEmail = [parameters objectForKey:@BREAKPAD_REQUEST_EMAIL];
- NSString *vendor =
+ NSString* requestEmail = [parameters objectForKey:@BREAKPAD_REQUEST_EMAIL];
+ NSString* vendor =
[parameters objectForKey:@BREAKPAD_VENDOR];
- NSString *dumpSubdirectory =
+ NSString* dumpSubdirectory =
[parameters objectForKey:@BREAKPAD_DUMP_DIRECTORY];
- NSDictionary *serverParameters =
+ NSDictionary* serverParameters =
[parameters objectForKey:@BREAKPAD_SERVER_PARAMETER_DICT];
// These may have been set above as user prefs, which take priority.
@@ -536,7 +535,7 @@ bool Breakpad::ExtractParameters(NSDictionary *parameters) {
}
// Find the helper applications if not specified in user config.
- NSString *resourcePath = nil;
+ NSString* resourcePath = nil;
if (!inspectorPathString || !reporterPathString) {
resourcePath = GetResourcePath();
if (!resourcePath) {
@@ -591,7 +590,7 @@ bool Breakpad::ExtractParameters(NSDictionary *parameters) {
new (gKeyValueAllocator->Allocate(sizeof(SimpleStringDictionary)) )
SimpleStringDictionary();
- SimpleStringDictionary &dictionary = *config_params_;
+ SimpleStringDictionary& dictionary = *config_params_;
dictionary.SetKeyValue(BREAKPAD_SERVER_TYPE, [serverType UTF8String]);
dictionary.SetKeyValue(BREAKPAD_PRODUCT_DISPLAY, [display UTF8String]);
@@ -633,8 +632,8 @@ bool Breakpad::ExtractParameters(NSDictionary *parameters) {
if (serverParameters) {
// For each key-value pair, call BreakpadAddUploadParameter()
- NSEnumerator *keyEnumerator = [serverParameters keyEnumerator];
- NSString *aParameter;
+ NSEnumerator* keyEnumerator = [serverParameters keyEnumerator];
+ NSString* aParameter;
while ((aParameter = [keyEnumerator nextObject])) {
BreakpadAddUploadParameter(this, aParameter,
[serverParameters objectForKey:aParameter]);
@@ -644,7 +643,7 @@ bool Breakpad::ExtractParameters(NSDictionary *parameters) {
}
//=============================================================================
-void Breakpad::SetKeyValue(NSString *key, NSString *value) {
+void Breakpad::SetKeyValue(NSString* key, NSString* value) {
// We allow nil values. This is the same as removing the keyvalue.
if (!config_params_ || !key)
return;
@@ -653,16 +652,16 @@ void Breakpad::SetKeyValue(NSString *key, NSString *value) {
}
//=============================================================================
-NSString *Breakpad::KeyValue(NSString *key) {
+NSString* Breakpad::KeyValue(NSString* key) {
if (!config_params_ || !key)
return nil;
- const char *value = config_params_->GetValueForKey([key UTF8String]);
+ const char* value = config_params_->GetValueForKey([key UTF8String]);
return value ? [NSString stringWithUTF8String:value] : nil;
}
//=============================================================================
-void Breakpad::RemoveKeyValue(NSString *key) {
+void Breakpad::RemoveKeyValue(NSString* key) {
if (!config_params_ || !key) return;
config_params_->RemoveKey([key UTF8String]);
@@ -722,7 +721,7 @@ bool Breakpad::HandleException(int exception_type,
if (result == KERN_SUCCESS) {
// Now, send a series of key-value pairs to the Inspector.
- const SimpleStringDictionary::Entry *entry = NULL;
+ const SimpleStringDictionary::Entry* entry = NULL;
SimpleStringDictionary::Iterator iter(*config_params_);
while ( (entry = iter.Next()) ) {
@@ -759,7 +758,7 @@ bool Breakpad::HandleException(int exception_type,
}
//=============================================================================
-bool Breakpad::HandleMinidump(const char *dump_dir, const char *minidump_id) {
+bool Breakpad::HandleMinidump(const char* dump_dir, const char* minidump_id) {
google_breakpad::ConfigFile config_file;
config_file.WriteFile(dump_dir, config_params_, dump_dir, minidump_id);
google_breakpad::LaunchReporter(
@@ -775,7 +774,7 @@ bool Breakpad::HandleMinidump(const char *dump_dir, const char *minidump_id) {
#pragma mark Public API
//=============================================================================
-BreakpadRef BreakpadCreate(NSDictionary *parameters) {
+BreakpadRef BreakpadCreate(NSDictionary* parameters) {
try {
// This is confusing. Our two main allocators for breakpad memory are:
// - gKeyValueAllocator for the key/value memory
@@ -815,8 +814,8 @@ BreakpadRef BreakpadCreate(NSDictionary *parameters) {
ProtectedMemoryAllocator(breakpad_pool_size);
// Stack-based autorelease pool for Breakpad::Create() obj-c code.
- NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
- Breakpad *breakpad = Breakpad::Create(parameters);
+ NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
+ Breakpad* breakpad = Breakpad::Create(parameters);
if (breakpad) {
// Make read-only to protect against memory smashers
@@ -856,7 +855,7 @@ BreakpadRef BreakpadCreate(NSDictionary *parameters) {
//=============================================================================
void BreakpadRelease(BreakpadRef ref) {
try {
- Breakpad *breakpad = (Breakpad *)ref;
+ Breakpad* breakpad = (Breakpad*)ref;
if (gMasterAllocator) {
gMasterAllocator->Unprotect();
@@ -889,10 +888,10 @@ void BreakpadRelease(BreakpadRef ref) {
}
//=============================================================================
-void BreakpadSetKeyValue(BreakpadRef ref, NSString *key, NSString *value) {
+void BreakpadSetKeyValue(BreakpadRef ref, NSString* key, NSString* value) {
try {
// Not called at exception time
- Breakpad *breakpad = (Breakpad *)ref;
+ Breakpad* breakpad = (Breakpad*)ref;
if (breakpad && key && gKeyValueAllocator) {
ProtectedMemoryLocker locker(&gDictionaryMutex, gKeyValueAllocator);
@@ -905,20 +904,20 @@ void BreakpadSetKeyValue(BreakpadRef ref, NSString *key, NSString *value) {
}
void BreakpadAddUploadParameter(BreakpadRef ref,
- NSString *key,
- NSString *value) {
+ NSString* key,
+ NSString* value) {
// The only difference, internally, between an upload parameter and
// a key value one that is set with BreakpadSetKeyValue is that we
// prepend the keyname with a special prefix. This informs the
// crash sender that the parameter should be sent along with the
// POST of the crash dump upload.
try {
- Breakpad *breakpad = (Breakpad *)ref;
+ Breakpad* breakpad = (Breakpad*)ref;
if (breakpad && key && gKeyValueAllocator) {
ProtectedMemoryLocker locker(&gDictionaryMutex, gKeyValueAllocator);
- NSString *prefixedKey = [@BREAKPAD_SERVER_PARAMETER_PREFIX
+ NSString* prefixedKey = [@BREAKPAD_SERVER_PARAMETER_PREFIX
stringByAppendingString:key];
breakpad->SetKeyValue(prefixedKey, value);
}
@@ -928,15 +927,15 @@ void BreakpadAddUploadParameter(BreakpadRef ref,
}
void BreakpadRemoveUploadParameter(BreakpadRef ref,
- NSString *key) {
+ NSString* key) {
try {
// Not called at exception time
- Breakpad *breakpad = (Breakpad *)ref;
+ Breakpad* breakpad = (Breakpad*)ref;
if (breakpad && key && gKeyValueAllocator) {
ProtectedMemoryLocker locker(&gDictionaryMutex, gKeyValueAllocator);
- NSString *prefixedKey = [NSString stringWithFormat:@"%@%@",
+ NSString* prefixedKey = [NSString stringWithFormat:@"%@%@",
@BREAKPAD_SERVER_PARAMETER_PREFIX, key];
breakpad->RemoveKeyValue(prefixedKey);
}
@@ -945,12 +944,12 @@ void BreakpadRemoveUploadParameter(BreakpadRef ref,
}
}
//=============================================================================
-NSString *BreakpadKeyValue(BreakpadRef ref, NSString *key) {
- NSString *value = nil;
+NSString* BreakpadKeyValue(BreakpadRef ref, NSString* key) {
+ NSString* value = nil;
try {
// Not called at exception time
- Breakpad *breakpad = (Breakpad *)ref;
+ Breakpad* breakpad = (Breakpad*)ref;
if (!breakpad || !key || !gKeyValueAllocator)
return nil;
@@ -966,10 +965,10 @@ NSString *BreakpadKeyValue(BreakpadRef ref, NSString *key) {
}
//=============================================================================
-void BreakpadRemoveKeyValue(BreakpadRef ref, NSString *key) {
+void BreakpadRemoveKeyValue(BreakpadRef ref, NSString* key) {
try {
// Not called at exception time
- Breakpad *breakpad = (Breakpad *)ref;
+ Breakpad* breakpad = (Breakpad*)ref;
if (breakpad && key && gKeyValueAllocator) {
ProtectedMemoryLocker locker(&gDictionaryMutex, gKeyValueAllocator);
@@ -984,7 +983,7 @@ void BreakpadRemoveKeyValue(BreakpadRef ref, NSString *key) {
//=============================================================================
void BreakpadGenerateAndSendReport(BreakpadRef ref) {
try {
- Breakpad *breakpad = (Breakpad *)ref;
+ Breakpad* breakpad = (Breakpad*)ref;
if (breakpad && gKeyValueAllocator) {
ProtectedMemoryLocker locker(&gDictionaryMutex, gKeyValueAllocator);
@@ -1001,10 +1000,10 @@ void BreakpadGenerateAndSendReport(BreakpadRef ref) {
//=============================================================================
void BreakpadSetFilterCallback(BreakpadRef ref,
BreakpadFilterCallback callback,
- void *context) {
+ void* context) {
try {
- Breakpad *breakpad = (Breakpad *)ref;
+ Breakpad* breakpad = (Breakpad*)ref;
if (breakpad && gBreakpadAllocator) {
// share the dictionary mutex here (we really don't need a mutex)
@@ -1018,14 +1017,14 @@ void BreakpadSetFilterCallback(BreakpadRef ref,
}
//============================================================================
-void BreakpadAddLogFile(BreakpadRef ref, NSString *logPathname) {
+void BreakpadAddLogFile(BreakpadRef ref, NSString* logPathname) {
int logFileCounter = 0;
- NSString *logFileKey = [NSString stringWithFormat:@"%@%d",
+ NSString* logFileKey = [NSString stringWithFormat:@"%@%d",
@BREAKPAD_LOGFILE_KEY_PREFIX,
logFileCounter];
- NSString *existingLogFilename = nil;
+ NSString* existingLogFilename = nil;
existingLogFilename = BreakpadKeyValue(ref, logFileKey);
// Find the first log file key that we can use by testing for existence
while (existingLogFilename) {
diff --git a/src/client/mac/Framework/OnDemandServer.h b/src/client/mac/Framework/OnDemandServer.h
index d4db5d3a..e7a52e7d 100644
--- a/src/client/mac/Framework/OnDemandServer.h
+++ b/src/client/mac/Framework/OnDemandServer.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2007, Google Inc.
-// All rights reserved.
+// Copyright 2007 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -41,7 +40,7 @@
// Example Usage :
//
// kern_return_t result;
-// OnDemandServer *server = OnDemandServer::Create("/tmp/myserver",
+// OnDemandServer* server = OnDemandServer::Create("/tmp/myserver",
// "com.MyCompany.MyServiceName",
// true,
// &result);
@@ -88,8 +87,8 @@ class OnDemandServer {
}
// Creates the bootstrap server and service
- kern_return_t Initialize(const char *server_command,
- const char *service_name,
+ kern_return_t Initialize(const char* server_command,
+ const char* service_name,
bool unregister_on_cleanup);
// Returns an OnDemandServer object if successful, or NULL if there's
@@ -110,10 +109,10 @@ class OnDemandServer {
// out_result : if non-NULL, returns the result
// this value will be KERN_SUCCESS if Create() returns non-NULL
//
- static OnDemandServer *Create(const char *server_command,
- const char *service_name,
+ static OnDemandServer* Create(const char *server_command,
+ const char* service_name,
bool unregister_on_cleanup,
- kern_return_t *out_result);
+ kern_return_t* out_result);
// Cleans up and if LaunchOnDemand() has not yet been called then
// the bootstrap service will be unregistered.
diff --git a/src/client/mac/Framework/OnDemandServer.mm b/src/client/mac/Framework/OnDemandServer.mm
index a2ffa434..d2f3a283 100644
--- a/src/client/mac/Framework/OnDemandServer.mm
+++ b/src/client/mac/Framework/OnDemandServer.mm
@@ -1,5 +1,4 @@
-// Copyright (c) 2007, Google Inc.
-// All rights reserved.
+// Copyright 2007 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -49,11 +48,11 @@
#endif
//==============================================================================
-OnDemandServer *OnDemandServer::Create(const char *server_command,
- const char *service_name,
+OnDemandServer* OnDemandServer::Create(const char* server_command,
+ const char* service_name,
bool unregister_on_cleanup,
- kern_return_t *out_result) {
- OnDemandServer *server = new OnDemandServer();
+ kern_return_t* out_result) {
+ OnDemandServer* server = new OnDemandServer();
if (!server) return NULL;
@@ -74,22 +73,22 @@ OnDemandServer *OnDemandServer::Create(const char *server_command,
}
//==============================================================================
-kern_return_t OnDemandServer::Initialize(const char *server_command,
- const char *service_name,
+kern_return_t OnDemandServer::Initialize(const char* server_command,
+ const char* service_name,
bool unregister_on_cleanup) {
unregister_on_cleanup_ = unregister_on_cleanup;
mach_port_t self_task = mach_task_self();
- mach_port_t bootstrap_port;
- kern_return_t kr = task_get_bootstrap_port(self_task, &bootstrap_port);
+ mach_port_t self_bootstrap_port;
+ kern_return_t kr = task_get_bootstrap_port(self_task, &self_bootstrap_port);
if (kr != KERN_SUCCESS) {
PRINT_MACH_RESULT(kr, "task_get_bootstrap_port(): ");
return kr;
}
mach_port_t bootstrap_subset_port;
- kr = bootstrap_subset(bootstrap_port, self_task, &bootstrap_subset_port);
+ kr = bootstrap_subset(self_bootstrap_port, self_task, &bootstrap_subset_port);
if (kr != BOOTSTRAP_SUCCESS) {
PRINT_BOOTSTRAP_RESULT(kr, "bootstrap_subset(): ");
return kr;
@@ -105,7 +104,7 @@ kern_return_t OnDemandServer::Initialize(const char *server_command,
kr = breakpad::BootstrapRegister(
bootstrap_subset_port,
const_cast<char*>(BREAKPAD_BOOTSTRAP_PARENT_PORT),
- bootstrap_port);
+ self_bootstrap_port);
if (kr != BOOTSTRAP_SUCCESS) {
PRINT_BOOTSTRAP_RESULT(kr, "bootstrap_register(): ");
return kr;
@@ -135,7 +134,8 @@ kern_return_t OnDemandServer::Initialize(const char *server_command,
PRINT_BOOTSTRAP_RESULT(kr, "bootstrap_create_service(): ");
// perhaps the service has already been created - try to look it up
- kr = bootstrap_look_up(bootstrap_port, (char*)service_name, &service_port_);
+ kr = bootstrap_look_up(self_bootstrap_port, (char*)service_name,
+ &service_port_);
if (kr != BOOTSTRAP_SUCCESS) {
PRINT_BOOTSTRAP_RESULT(kr, "bootstrap_look_up(): ");
diff --git a/src/client/mac/crash_generation/ConfigFile.h b/src/client/mac/crash_generation/ConfigFile.h
index f2da7c24..4a4ed984 100644
--- a/src/client/mac/crash_generation/ConfigFile.h
+++ b/src/client/mac/crash_generation/ConfigFile.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2011, Google Inc.
-// All rights reserved.
+// Copyright 2011 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -35,7 +34,7 @@
namespace google_breakpad {
-BOOL EnsureDirectoryPathExists(NSString *dirPath);
+BOOL EnsureDirectoryPathExists(NSString* dirPath);
//=============================================================================
class ConfigFile {
@@ -50,11 +49,11 @@ class ConfigFile {
}
void WriteFile(const char* directory,
- const SimpleStringDictionary *configurationParameters,
- const char *dump_dir,
- const char *minidump_id);
+ const SimpleStringDictionary* configurationParameters,
+ const char* dump_dir,
+ const char* minidump_id);
- const char *GetFilePath() { return config_file_path_; }
+ const char* GetFilePath() { return config_file_path_; }
void Unlink() {
if (config_file_ != -1)
@@ -64,16 +63,16 @@ class ConfigFile {
}
private:
- BOOL WriteData(const void *data, size_t length);
+ BOOL WriteData(const void* data, size_t length);
- BOOL AppendConfigData(const char *key,
- const void *data,
+ BOOL AppendConfigData(const char* key,
+ const void* data,
size_t length);
- BOOL AppendConfigString(const char *key,
- const char *value);
+ BOOL AppendConfigString(const char* key,
+ const char* value);
- BOOL AppendCrashTimeParameters(const char *processStartTimeString);
+ BOOL AppendCrashTimeParameters(const char* processStartTimeString);
int config_file_; // descriptor for config file
char config_file_path_[PATH_MAX]; // Path to configuration file
diff --git a/src/client/mac/crash_generation/ConfigFile.mm b/src/client/mac/crash_generation/ConfigFile.mm
index acab7de8..fe89e858 100644
--- a/src/client/mac/crash_generation/ConfigFile.mm
+++ b/src/client/mac/crash_generation/ConfigFile.mm
@@ -1,5 +1,4 @@
-// Copyright (c) 2011, Google Inc.
-// All rights reserved.
+// Copyright 2011 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -42,10 +41,10 @@
namespace google_breakpad {
//=============================================================================
-BOOL EnsureDirectoryPathExists(NSString *dirPath) {
- NSFileManager *mgr = [NSFileManager defaultManager];
+BOOL EnsureDirectoryPathExists(NSString* dirPath) {
+ NSFileManager* mgr = [NSFileManager defaultManager];
- NSDictionary *attrs =
+ NSDictionary* attrs =
[NSDictionary dictionaryWithObject:[NSNumber numberWithUnsignedLong:0750]
forKey:NSFilePosixPermissions];
@@ -56,15 +55,15 @@ BOOL EnsureDirectoryPathExists(NSString *dirPath) {
}
//=============================================================================
-BOOL ConfigFile::WriteData(const void *data, size_t length) {
+BOOL ConfigFile::WriteData(const void* data, size_t length) {
size_t result = write(config_file_, data, length);
return result == length;
}
//=============================================================================
-BOOL ConfigFile::AppendConfigData(const char *key,
- const void *data, size_t length) {
+BOOL ConfigFile::AppendConfigData(const char* key,
+ const void* data, size_t length) {
assert(config_file_ != -1);
if (!key) {
@@ -88,13 +87,13 @@ BOOL ConfigFile::AppendConfigData(const char *key,
}
//=============================================================================
-BOOL ConfigFile::AppendConfigString(const char *key,
- const char *value) {
+BOOL ConfigFile::AppendConfigString(const char* key,
+ const char* value) {
return AppendConfigData(key, value, strlen(value));
}
//=============================================================================
-BOOL ConfigFile::AppendCrashTimeParameters(const char *processStartTimeString) {
+BOOL ConfigFile::AppendCrashTimeParameters(const char* processStartTimeString) {
// Set process uptime parameter
struct timeval tv;
gettimeofday(&tv, NULL);
@@ -105,22 +104,23 @@ BOOL ConfigFile::AppendCrashTimeParameters(const char *processStartTimeString) {
time_t processStartTime = strtol(processStartTimeString, NULL, 10);
time_t processUptime = tv.tv_sec - processStartTime;
// Store the uptime in milliseconds.
- sprintf(processUptimeString, "%llu",
- static_cast<unsigned long long int>(processUptime) * 1000);
+ snprintf(processUptimeString, sizeof(processUptimeString), "%llu",
+ static_cast<unsigned long long int>(processUptime) * 1000);
if (!AppendConfigString(BREAKPAD_PROCESS_UP_TIME, processUptimeString))
return false;
}
- sprintf(processCrashtimeString, "%zd", tv.tv_sec);
+ snprintf(processCrashtimeString, sizeof(processCrashtimeString), "%llu",
+ static_cast<unsigned long long int>(tv.tv_sec));
return AppendConfigString(BREAKPAD_PROCESS_CRASH_TIME,
processCrashtimeString);
}
//=============================================================================
void ConfigFile::WriteFile(const char* directory,
- const SimpleStringDictionary *configurationParameters,
- const char *dump_dir,
- const char *minidump_id) {
+ const SimpleStringDictionary* configurationParameters,
+ const char* dump_dir,
+ const char* minidump_id) {
assert(config_file_ == -1);
@@ -146,9 +146,9 @@ void ConfigFile::WriteFile(const char* directory,
// Write out the configuration parameters
BOOL result = YES;
- const SimpleStringDictionary &dictionary = *configurationParameters;
+ const SimpleStringDictionary& dictionary = *configurationParameters;
- const SimpleStringDictionary::Entry *entry = NULL;
+ const SimpleStringDictionary::Entry* entry = NULL;
SimpleStringDictionary::Iterator iter(dictionary);
while ((entry = iter.Next())) {
diff --git a/src/client/mac/crash_generation/Inspector.h b/src/client/mac/crash_generation/Inspector.h
index 7f923ed6..fb9240c2 100644
--- a/src/client/mac/crash_generation/Inspector.h
+++ b/src/client/mac/crash_generation/Inspector.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2007, Google Inc.
-// All rights reserved.
+// Copyright 2007 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -63,7 +62,7 @@ struct KeyValueMessageData {
public:
KeyValueMessageData() {}
explicit KeyValueMessageData(
- const google_breakpad::SimpleStringDictionary::Entry &inEntry) {
+ const google_breakpad::SimpleStringDictionary::Entry& inEntry) {
strlcpy(key, inEntry.key, sizeof(key) );
strlcpy(value, inEntry.value, sizeof(value) );
}
@@ -80,7 +79,7 @@ namespace google_breakpad {
//=============================================================================
class MinidumpLocation {
public:
- MinidumpLocation(NSString *minidumpDir) {
+ MinidumpLocation(NSString* minidumpDir) {
// Ensure that the path exists. Fallback to /tmp if unable to locate path.
assert(minidumpDir);
if (!EnsureDirectoryPathExists(minidumpDir)) {
@@ -100,8 +99,8 @@ class MinidumpLocation {
strlcpy(minidump_id_, next_minidump_id.c_str(), sizeof(minidump_id_));
}
- const char *GetPath() { return minidump_dir_path_; }
- const char *GetID() { return minidump_id_; }
+ const char* GetPath() { return minidump_dir_path_; }
+ const char* GetID() { return minidump_id_; }
private:
char minidump_dir_path_[PATH_MAX]; // Path to minidump directory
@@ -116,7 +115,7 @@ class Inspector {
// given a bootstrap service name, receives mach messages
// from a crashed process, then inspects it, creates a minidump file
// and asks the user if he wants to upload it to a server.
- void Inspect(const char *receive_port_name);
+ void Inspect(const char* receive_port_name);
private:
// The Inspector is invoked with its bootstrap port set to the bootstrap
@@ -131,8 +130,8 @@ class Inspector {
// ServiceCheckOut.
kern_return_t ResetBootstrapPort();
- kern_return_t ServiceCheckIn(const char *receive_port_name);
- kern_return_t ServiceCheckOut(const char *receive_port_name);
+ kern_return_t ServiceCheckIn(const char* receive_port_name);
+ kern_return_t ServiceCheckOut(const char* receive_port_name);
kern_return_t ReadMessages();
diff --git a/src/client/mac/crash_generation/Inspector.mm b/src/client/mac/crash_generation/Inspector.mm
index dc6f4808..8d4e3e98 100644
--- a/src/client/mac/crash_generation/Inspector.mm
+++ b/src/client/mac/crash_generation/Inspector.mm
@@ -1,5 +1,4 @@
-// Copyright (c) 2007, Google Inc.
-// All rights reserved.
+// Copyright 2007 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -52,7 +51,7 @@
namespace google_breakpad {
//=============================================================================
-void Inspector::Inspect(const char *receive_port_name) {
+void Inspector::Inspect(const char* receive_port_name) {
kern_return_t result = ResetBootstrapPort();
if (result != KERN_SUCCESS) {
return;
@@ -143,7 +142,7 @@ kern_return_t Inspector::ResetBootstrapPort() {
}
//=============================================================================
-kern_return_t Inspector::ServiceCheckIn(const char *receive_port_name) {
+kern_return_t Inspector::ServiceCheckIn(const char* receive_port_name) {
// We need to get the mach port representing this service, so we can
// get information from the crashed process.
kern_return_t kr = bootstrap_check_in(bootstrap_subset_port_,
@@ -160,7 +159,7 @@ kern_return_t Inspector::ServiceCheckIn(const char *receive_port_name) {
}
//=============================================================================
-kern_return_t Inspector::ServiceCheckOut(const char *receive_port_name) {
+kern_return_t Inspector::ServiceCheckOut(const char* receive_port_name) {
// We're done receiving mach messages from the crashed process,
// so clean up a bit.
kern_return_t kr;
@@ -198,7 +197,7 @@ kern_return_t Inspector::ReadMessages() {
kern_return_t result = receive_port.WaitForMessage(&message, 1000);
if (result == KERN_SUCCESS) {
- InspectorInfo &info = (InspectorInfo &)*message.GetData();
+ InspectorInfo& info = (InspectorInfo&)*message.GetData();
exception_type_ = info.exception_type;
exception_code_ = info.exception_code;
exception_subcode_ = info.exception_subcode;
@@ -237,7 +236,7 @@ kern_return_t Inspector::ReadMessages() {
result = receive_port.WaitForMessage(&parameter_message, 1000);
if(result == KERN_SUCCESS) {
- KeyValueMessageData &key_value_data =
+ KeyValueMessageData& key_value_data =
(KeyValueMessageData&)*parameter_message.GetData();
// If we get a blank key, make sure we don't increment the
// parameter count; in some cases (notably on-demand generation
@@ -267,27 +266,27 @@ bool Inspector::InspectTask() {
// keep the task quiet while we're looking at it
task_suspend(remote_task_);
- NSString *minidumpDir;
+ NSString* minidumpDir;
- const char *minidumpDirectory =
+ const char* minidumpDirectory =
config_params_.GetValueForKey(BREAKPAD_DUMP_DIRECTORY);
// If the client app has not specified a minidump directory,
// use a default of Library/<kDefaultLibrarySubdirectory>/<Product Name>
if (!minidumpDirectory || 0 == strlen(minidumpDirectory)) {
- NSArray *libraryDirectories =
+ NSArray* libraryDirectories =
NSSearchPathForDirectoriesInDomains(NSLibraryDirectory,
NSUserDomainMask,
YES);
- NSString *applicationSupportDirectory =
+ NSString* applicationSupportDirectory =
[libraryDirectories objectAtIndex:0];
- NSString *library_subdirectory = [NSString
+ NSString* library_subdirectory = [NSString
stringWithUTF8String:kDefaultLibrarySubdirectory];
- NSString *breakpad_product = [NSString
+ NSString* breakpad_product = [NSString
stringWithUTF8String:config_params_.GetValueForKey(BREAKPAD_PRODUCT)];
- NSArray *path_components = [NSArray
+ NSArray* path_components = [NSArray
arrayWithObjects:applicationSupportDirectory,
library_subdirectory,
breakpad_product,
@@ -306,11 +305,11 @@ bool Inspector::InspectTask() {
// assumes system encoding and in RTL locales will prepend an LTR override
// character for paths beginning with '/' which fileSystemRepresentation does
// not remove. Filed as rdar://6889706 .
- NSString *path_ns = [NSString
+ NSString* path_ns = [NSString
stringWithUTF8String:minidumpLocation.GetPath()];
- NSString *pathid_ns = [NSString
+ NSString* pathid_ns = [NSString
stringWithUTF8String:minidumpLocation.GetID()];
- NSString *minidumpPath = [path_ns stringByAppendingPathComponent:pathid_ns];
+ NSString* minidumpPath = [path_ns stringByAppendingPathComponent:pathid_ns];
minidumpPath = [minidumpPath
stringByAppendingPathExtension:@"dmp"];
diff --git a/src/client/mac/crash_generation/InspectorMain.mm b/src/client/mac/crash_generation/InspectorMain.mm
index 137c6a1e..fb3199d3 100644
--- a/src/client/mac/crash_generation/InspectorMain.mm
+++ b/src/client/mac/crash_generation/InspectorMain.mm
@@ -1,5 +1,4 @@
-// Copyright (c) 2007, Google Inc.
-// All rights reserved.
+// Copyright 2007 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/client/mac/crash_generation/client_info.h b/src/client/mac/crash_generation/client_info.h
index a3a95dca..30870f17 100644
--- a/src/client/mac/crash_generation/client_info.h
+++ b/src/client/mac/crash_generation/client_info.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2010 Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/client/mac/crash_generation/crash_generation_client.cc b/src/client/mac/crash_generation/crash_generation_client.cc
index ceeb3b32..32f1c827 100644
--- a/src/client/mac/crash_generation/crash_generation_client.cc
+++ b/src/client/mac/crash_generation/crash_generation_client.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2010 Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/client/mac/crash_generation/crash_generation_client.h b/src/client/mac/crash_generation/crash_generation_client.h
index 527f577a..06cc0a31 100644
--- a/src/client/mac/crash_generation/crash_generation_client.h
+++ b/src/client/mac/crash_generation/crash_generation_client.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2010 Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/client/mac/crash_generation/crash_generation_server.cc b/src/client/mac/crash_generation/crash_generation_server.cc
index 451e8d9c..6bbd4bb5 100644
--- a/src/client/mac/crash_generation/crash_generation_server.cc
+++ b/src/client/mac/crash_generation/crash_generation_server.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2010 Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -38,15 +37,15 @@
namespace google_breakpad {
CrashGenerationServer::CrashGenerationServer(
- const char *mach_port_name,
+ const char* mach_port_name,
FilterCallback filter,
- void *filter_context,
+ void* filter_context,
OnClientDumpRequestCallback dump_callback,
- void *dump_context,
+ void* dump_context,
OnClientExitingCallback exit_callback,
- void *exit_context,
+ void* exit_context,
bool generate_dumps,
- const std::string &dump_path)
+ const std::string& dump_path)
: filter_(filter),
filter_context_(filter_context),
dump_callback_(dump_callback),
@@ -90,8 +89,8 @@ bool CrashGenerationServer::Stop() {
}
// static
-void *CrashGenerationServer::WaitForMessages(void *server) {
- CrashGenerationServer *self =
+void* CrashGenerationServer::WaitForMessages(void* server) {
+ CrashGenerationServer* self =
reinterpret_cast<CrashGenerationServer*>(server);
while (self->WaitForOneMessage()) {}
return NULL;
@@ -104,7 +103,7 @@ bool CrashGenerationServer::WaitForOneMessage() {
if (result == KERN_SUCCESS) {
switch (message.GetMessageID()) {
case kDumpRequestMessage: {
- ExceptionInfo &info = (ExceptionInfo &)*message.GetData();
+ ExceptionInfo& info = (ExceptionInfo&)*message.GetData();
mach_port_t remote_task = message.GetTranslatedPort(0);
mach_port_t crashing_thread = message.GetTranslatedPort(1);
diff --git a/src/client/mac/crash_generation/crash_generation_server.h b/src/client/mac/crash_generation/crash_generation_server.h
index 85bd5b5e..2c4b56cf 100644
--- a/src/client/mac/crash_generation/crash_generation_server.h
+++ b/src/client/mac/crash_generation/crash_generation_server.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2010 Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -59,14 +58,14 @@ class CrashGenerationServer {
// WARNING: callbacks may be invoked on a different thread
// than that which creates the CrashGenerationServer. They must
// be thread safe.
- typedef void (*OnClientDumpRequestCallback)(void *context,
- const ClientInfo &client_info,
- const std::string &file_path);
+ typedef void (*OnClientDumpRequestCallback)(void* context,
+ const ClientInfo& client_info,
+ const std::string& file_path);
- typedef void (*OnClientExitingCallback)(void *context,
- const ClientInfo &client_info);
+ typedef void (*OnClientExitingCallback)(void* context,
+ const ClientInfo& client_info);
// If a FilterCallback returns false, the dump will not be written.
- typedef bool (*FilterCallback)(void *context);
+ typedef bool (*FilterCallback)(void* context);
// Create an instance with the given parameters.
//
@@ -83,15 +82,15 @@ class CrashGenerationServer {
// passed for this parameter.
// dump_path: Path for generating dumps; required only if true is
// passed for generateDumps parameter; NULL can be passed otherwise.
- CrashGenerationServer(const char *mach_port_name,
+ CrashGenerationServer(const char* mach_port_name,
FilterCallback filter,
- void *filter_context,
+ void* filter_context,
OnClientDumpRequestCallback dump_callback,
- void *dump_context,
+ void* dump_context,
OnClientExitingCallback exit_callback,
- void *exit_context,
+ void* exit_context,
bool generate_dumps,
- const std::string &dump_path);
+ const std::string& dump_path);
~CrashGenerationServer();
@@ -105,24 +104,24 @@ class CrashGenerationServer {
private:
// Return a unique filename at which a minidump can be written.
- bool MakeMinidumpFilename(std::string &outFilename);
+ bool MakeMinidumpFilename(std::string& outFilename);
// Loop reading client messages and responding to them until
// a quit message is received.
- static void *WaitForMessages(void *server);
+ static void* WaitForMessages(void* server);
// Wait for a single client message and respond to it. Returns false
// if a quit message was received or if an error occurred.
bool WaitForOneMessage();
FilterCallback filter_;
- void *filter_context_;
+ void* filter_context_;
OnClientDumpRequestCallback dump_callback_;
- void *dump_context_;
+ void* dump_context_;
OnClientExitingCallback exit_callback_;
- void *exit_context_;
+ void* exit_context_;
bool generate_dumps_;
diff --git a/src/client/mac/handler/breakpad_nlist_64.cc b/src/client/mac/handler/breakpad_nlist_64.cc
index 3492b823..b4f04c91 100644
--- a/src/client/mac/handler/breakpad_nlist_64.cc
+++ b/src/client/mac/handler/breakpad_nlist_64.cc
@@ -131,7 +131,7 @@ struct MachBits<nlist64> {
template<typename nlist_type>
int
-__breakpad_fdnlist(int fd, nlist_type *list, const char **symbolNames,
+__breakpad_fdnlist(int fd, nlist_type* list, const char** symbolNames,
cpu_type_t cpu_type);
/*
@@ -139,9 +139,9 @@ __breakpad_fdnlist(int fd, nlist_type *list, const char **symbolNames,
*/
template <typename nlist_type>
-int breakpad_nlist_common(const char *name,
- nlist_type *list,
- const char **symbolNames,
+int breakpad_nlist_common(const char* name,
+ nlist_type* list,
+ const char** symbolNames,
cpu_type_t cpu_type) {
int fd = open(name, O_RDONLY, 0);
if (fd < 0)
@@ -151,16 +151,16 @@ int breakpad_nlist_common(const char *name,
return n;
}
-int breakpad_nlist(const char *name,
- struct nlist *list,
- const char **symbolNames,
+int breakpad_nlist(const char* name,
+ struct nlist* list,
+ const char** symbolNames,
cpu_type_t cpu_type) {
return breakpad_nlist_common(name, list, symbolNames, cpu_type);
}
-int breakpad_nlist(const char *name,
- struct nlist_64 *list,
- const char **symbolNames,
+int breakpad_nlist(const char* name,
+ struct nlist_64* list,
+ const char** symbolNames,
cpu_type_t cpu_type) {
return breakpad_nlist_common(name, list, symbolNames, cpu_type);
}
@@ -168,7 +168,7 @@ int breakpad_nlist(const char *name,
/* Note: __fdnlist() is called from kvm_nlist in libkvm's kvm.c */
template<typename nlist_type>
-int __breakpad_fdnlist(int fd, nlist_type *list, const char **symbolNames,
+int __breakpad_fdnlist(int fd, nlist_type* list, const char** symbolNames,
cpu_type_t cpu_type) {
typedef typename MachBits<nlist_type>::mach_header_type mach_header_type;
typedef typename MachBits<nlist_type>::word_type word_type;
@@ -189,9 +189,9 @@ int __breakpad_fdnlist(int fd, nlist_type *list, const char **symbolNames,
}
struct exec buf;
- if (read(fd, (char *)&buf, sizeof(buf)) != sizeof(buf) ||
- (N_BADMAG(buf) && *((uint32_t *)&buf) != magic &&
- CFSwapInt32BigToHost(*((uint32_t *)&buf)) != FAT_MAGIC &&
+ if (read(fd, (char*)&buf, sizeof(buf)) != sizeof(buf) ||
+ (N_BADMAG(buf) && *((uint32_t*)&buf) != magic &&
+ CFSwapInt32BigToHost(*((uint32_t*)&buf)) != FAT_MAGIC &&
/* The following is the big-endian ppc64 check */
(*((uint32_t*)&buf)) != FAT_MAGIC)) {
return -1;
@@ -199,15 +199,15 @@ int __breakpad_fdnlist(int fd, nlist_type *list, const char **symbolNames,
/* Deal with fat file if necessary */
unsigned arch_offset = 0;
- if (CFSwapInt32BigToHost(*((uint32_t *)&buf)) == FAT_MAGIC ||
+ if (CFSwapInt32BigToHost(*((uint32_t*)&buf)) == FAT_MAGIC ||
/* The following is the big-endian ppc64 check */
- *((unsigned int *)&buf) == FAT_MAGIC) {
+ *((unsigned int*)&buf) == FAT_MAGIC) {
/* Read in the fat header */
struct fat_header fh;
if (lseek(fd, 0, SEEK_SET) == -1) {
return -1;
}
- if (read(fd, (char *)&fh, sizeof(fh)) != sizeof(fh)) {
+ if (read(fd, (char*)&fh, sizeof(fh)) != sizeof(fh)) {
return -1;
}
@@ -215,12 +215,12 @@ int __breakpad_fdnlist(int fd, nlist_type *list, const char **symbolNames,
fh.nfat_arch = CFSwapInt32BigToHost(fh.nfat_arch);
/* Read in the fat archs */
- struct fat_arch *fat_archs =
- (struct fat_arch *)malloc(fh.nfat_arch * sizeof(struct fat_arch));
+ struct fat_arch* fat_archs =
+ (struct fat_arch*)malloc(fh.nfat_arch * sizeof(struct fat_arch));
if (fat_archs == NULL) {
return -1;
}
- if (read(fd, (char *)fat_archs,
+ if (read(fd, (char*)fat_archs,
sizeof(struct fat_arch) * fh.nfat_arch) !=
(ssize_t)(sizeof(struct fat_arch) * fh.nfat_arch)) {
free(fat_archs);
@@ -244,7 +244,7 @@ int __breakpad_fdnlist(int fd, nlist_type *list, const char **symbolNames,
CFSwapInt32BigToHost(fat_archs[i].align);
}
- struct fat_arch *fap = NULL;
+ struct fat_arch* fap = NULL;
for (unsigned i = 0; i < fh.nfat_arch; i++) {
if (fat_archs[i].cputype == cpu_type) {
fap = &fat_archs[i];
@@ -263,7 +263,7 @@ int __breakpad_fdnlist(int fd, nlist_type *list, const char **symbolNames,
if (lseek(fd, arch_offset, SEEK_SET) == -1) {
return -1;
}
- if (read(fd, (char *)&buf, sizeof(buf)) != sizeof(buf)) {
+ if (read(fd, (char*)&buf, sizeof(buf)) != sizeof(buf)) {
return -1;
}
}
@@ -271,48 +271,45 @@ int __breakpad_fdnlist(int fd, nlist_type *list, const char **symbolNames,
off_t sa; /* symbol address */
off_t ss; /* start of strings */
register_t n;
- if (*((unsigned int *)&buf) == magic) {
+ if (*((unsigned int*)&buf) == magic) {
if (lseek(fd, arch_offset, SEEK_SET) == -1) {
return -1;
}
mach_header_type mh;
- if (read(fd, (char *)&mh, sizeof(mh)) != sizeof(mh)) {
+ if (read(fd, (char*)&mh, sizeof(mh)) != sizeof(mh)) {
return -1;
}
- struct load_command *load_commands =
- (struct load_command *)malloc(mh.sizeofcmds);
+ struct load_command* load_commands =
+ (struct load_command*)malloc(mh.sizeofcmds);
if (load_commands == NULL) {
return -1;
}
- if (read(fd, (char *)load_commands, mh.sizeofcmds) !=
+ if (read(fd, (char*)load_commands, mh.sizeofcmds) !=
(ssize_t)mh.sizeofcmds) {
free(load_commands);
return -1;
}
- struct symtab_command *stp = NULL;
- struct load_command *lcp = load_commands;
+ struct symtab_command* stp = NULL;
+ struct load_command* lcp = load_commands;
// iterate through all load commands, looking for
// LC_SYMTAB load command
for (uint32_t i = 0; i < mh.ncmds; i++) {
if (lcp->cmdsize % sizeof(word_type) != 0 ||
lcp->cmdsize <= 0 ||
- (char *)lcp + lcp->cmdsize >
- (char *)load_commands + mh.sizeofcmds) {
+ (char*)lcp + lcp->cmdsize > (char*)load_commands + mh.sizeofcmds) {
free(load_commands);
return -1;
}
if (lcp->cmd == LC_SYMTAB) {
- if (lcp->cmdsize !=
- sizeof(struct symtab_command)) {
+ if (lcp->cmdsize != sizeof(struct symtab_command)) {
free(load_commands);
return -1;
}
- stp = (struct symtab_command *)lcp;
+ stp = (struct symtab_command*)lcp;
break;
}
- lcp = (struct load_command *)
- ((char *)lcp + lcp->cmdsize);
+ lcp = (struct load_command*)((char*)lcp + lcp->cmdsize);
}
if (stp == NULL) {
free(load_commands);
@@ -347,7 +344,7 @@ int __breakpad_fdnlist(int fd, nlist_type *list, const char **symbolNames,
if (n < m)
m = n;
- if (read(fd, (char *)space, m) != m)
+ if (read(fd, (char*)space, m) != m)
break;
n -= m;
off_t savpos = lseek(fd, 0, SEEK_CUR);
@@ -368,13 +365,13 @@ int __breakpad_fdnlist(int fd, nlist_type *list, const char **symbolNames,
if (read(fd, nambuf, maxlen+1) == -1) {
return -1;
}
- const char *s2 = nambuf;
- for (nlist_type *p = list;
+ const char* s2 = nambuf;
+ for (nlist_type* p = list;
symbolNames[p-list] && symbolNames[p-list][0];
p++) {
// get the symbol name the user has passed in that
// corresponds to the nlist entry that we're looking at
- const char *s1 = symbolNames[p - list];
+ const char* s1 = symbolNames[p - list];
while (*s1) {
if (*s1++ != *s2++)
goto cont;
diff --git a/src/client/mac/handler/breakpad_nlist_64.h b/src/client/mac/handler/breakpad_nlist_64.h
index e8e2e083..7093d284 100644
--- a/src/client/mac/handler/breakpad_nlist_64.h
+++ b/src/client/mac/handler/breakpad_nlist_64.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2008, Google Inc.
-// All rights reserved
+// Copyright 2008 Google LLC
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
@@ -10,7 +9,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -36,13 +35,13 @@
#include <mach/machine.h>
-int breakpad_nlist(const char *name,
- struct nlist *list,
- const char **symbolNames,
+int breakpad_nlist(const char* name,
+ struct nlist* list,
+ const char** symbolNames,
cpu_type_t cpu_type);
-int breakpad_nlist(const char *name,
- struct nlist_64 *list,
- const char **symbolNames,
+int breakpad_nlist(const char* name,
+ struct nlist_64* list,
+ const char** symbolNames,
cpu_type_t cpu_type);
#endif /* CLIENT_MAC_HANDLER_BREAKPAD_NLIST_H__ */
diff --git a/src/client/mac/handler/dynamic_images.cc b/src/client/mac/handler/dynamic_images.cc
index cdba6df4..b1d2c464 100644
--- a/src/client/mac/handler/dynamic_images.cc
+++ b/src/client/mac/handler/dynamic_images.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2007, Google Inc.
-// All rights reserved.
+// Copyright 2007 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -66,7 +65,7 @@ struct task_dyld_info {
mach_vm_size_t all_image_info_size;
};
typedef struct task_dyld_info task_dyld_info_data_t;
-typedef struct task_dyld_info *task_dyld_info_t;
+typedef struct task_dyld_info* task_dyld_info_t;
#define TASK_DYLD_INFO_COUNT (sizeof(task_dyld_info_data_t) / sizeof(natural_t))
#endif
@@ -88,7 +87,7 @@ using std::vector;
//
static mach_vm_size_t GetMemoryRegionSize(task_port_t target_task,
const uint64_t address,
- mach_vm_size_t *size_to_end) {
+ mach_vm_size_t* size_to_end) {
mach_vm_address_t region_base = (mach_vm_address_t)address;
mach_vm_size_t region_size;
natural_t nesting_level = 0;
@@ -182,7 +181,7 @@ static string ReadTaskString(task_port_t target_task,
kern_return_t ReadTaskMemory(task_port_t target_task,
const uint64_t address,
size_t length,
- vector<uint8_t> &bytes) {
+ vector<uint8_t>& bytes) {
int systemPageSize = getpagesize();
// use the negative of the page size for the mask to find the page address
@@ -250,16 +249,16 @@ bool FindTextSection(DynamicImage& image) {
return false;
}
- const struct load_command *cmd =
- reinterpret_cast<const struct load_command *>(header + 1);
+ const struct load_command* cmd =
+ reinterpret_cast<const struct load_command*>(header + 1);
bool found_text_section = false;
bool found_dylib_id_command = false;
for (unsigned int i = 0; cmd && (i < header->ncmds); ++i) {
if (!found_text_section) {
if (cmd->cmd == MachBits::segment_load_command) {
- const mach_segment_command_type *seg =
- reinterpret_cast<const mach_segment_command_type *>(cmd);
+ const mach_segment_command_type* seg =
+ reinterpret_cast<const mach_segment_command_type*>(cmd);
if (!strcmp(seg->segname, "__TEXT")) {
image.vmaddr_ = static_cast<mach_vm_address_t>(seg->vmaddr);
@@ -277,8 +276,8 @@ bool FindTextSection(DynamicImage& image) {
if (!found_dylib_id_command) {
if (cmd->cmd == LC_ID_DYLIB) {
- const struct dylib_command *dc =
- reinterpret_cast<const struct dylib_command *>(cmd);
+ const struct dylib_command* dc =
+ reinterpret_cast<const struct dylib_command*>(cmd);
image.version_ = dc->dylib.current_version;
found_dylib_id_command = true;
@@ -289,8 +288,8 @@ bool FindTextSection(DynamicImage& image) {
return true;
}
- cmd = reinterpret_cast<const struct load_command *>
- (reinterpret_cast<const char *>(cmd) + cmd->cmdsize);
+ cmd = reinterpret_cast<const struct load_command*>
+ (reinterpret_cast<const char*>(cmd) + cmd->cmdsize);
}
return false;
@@ -349,8 +348,8 @@ static uint64_t LookupSymbol(const char* symbol_name,
typedef typename MachBits::nlist_type nlist_type;
nlist_type symbol_info[8] = {};
- const char *symbolNames[2] = { symbol_name, "\0" };
- nlist_type &list = symbol_info[0];
+ const char* symbolNames[2] = { symbol_name, "\0" };
+ nlist_type& list = symbol_info[0];
int invalidEntriesCount = breakpad_nlist(filename,
&list,
symbolNames,
@@ -396,8 +395,8 @@ uint64_t DynamicImages::GetDyldAllImageInfosPointer() {
return (uint64_t)task_dyld_info.all_image_info_addr;
} else {
- const char *imageSymbolName = "_dyld_all_image_infos";
- const char *dyldPath = "/usr/lib/dyld";
+ const char* imageSymbolName = "_dyld_all_image_infos";
+ const char* dyldPath = "/usr/lib/dyld";
if (Is64Bit())
return LookupSymbol<MachO64>(imageSymbolName, dyldPath, cpu_type_);
@@ -428,7 +427,7 @@ void ReadImageInfo(DynamicImages& images,
dyld_all_info_bytes) != KERN_SUCCESS)
return;
- dyld_all_image_infos *dyldInfo =
+ dyld_all_image_infos* dyldInfo =
reinterpret_cast<dyld_all_image_infos*>(&dyld_all_info_bytes[0]);
// number of loaded images
@@ -443,12 +442,12 @@ void ReadImageInfo(DynamicImages& images,
dyld_info_array_bytes) != KERN_SUCCESS)
return;
- dyld_image_info *infoArray =
+ dyld_image_info* infoArray =
reinterpret_cast<dyld_image_info*>(&dyld_info_array_bytes[0]);
images.image_list_.reserve(count);
for (int i = 0; i < count; ++i) {
- dyld_image_info &info = infoArray[i];
+ dyld_image_info& info = infoArray[i];
// First read just the mach_header from the image in the task.
vector<uint8_t> mach_header_bytes;
@@ -458,7 +457,7 @@ void ReadImageInfo(DynamicImages& images,
mach_header_bytes) != KERN_SUCCESS)
continue; // bail on this dynamic image
- mach_header_type *header =
+ mach_header_type* header =
reinterpret_cast<mach_header_type*>(&mach_header_bytes[0]);
// Now determine the total amount necessary to read the header
@@ -482,7 +481,7 @@ void ReadImageInfo(DynamicImages& images,
}
// Create an object representing this image and add it to our list.
- DynamicImage *new_image;
+ DynamicImage* new_image;
new_image = new DynamicImage(&mach_header_bytes[0],
header_size,
info.load_address_,
@@ -522,7 +521,7 @@ void DynamicImages::ReadImageInfoForTask() {
}
//==============================================================================
-DynamicImage *DynamicImages::GetExecutableImage() {
+DynamicImage* DynamicImages::GetExecutableImage() {
int executable_index = GetExecutableImageIndex();
if (executable_index >= 0) {
@@ -538,7 +537,7 @@ int DynamicImages::GetExecutableImageIndex() {
int image_count = GetImageCount();
for (int i = 0; i < image_count; ++i) {
- DynamicImage *image = GetImage(i);
+ DynamicImage* image = GetImage(i);
if (image->GetFileType() == MH_EXECUTE) {
return i;
}
diff --git a/src/client/mac/handler/dynamic_images.h b/src/client/mac/handler/dynamic_images.h
index 65147900..b5af7584 100644
--- a/src/client/mac/handler/dynamic_images.h
+++ b/src/client/mac/handler/dynamic_images.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2007, Google Inc.
-// All rights reserved.
+// Copyright 2007 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -108,7 +107,7 @@ uint32_t GetFileTypeFromHeader(DynamicImage& image);
// Represents a single dynamically loaded mach-o image
class DynamicImage {
public:
- DynamicImage(uint8_t *header, // data is copied
+ DynamicImage(uint8_t* header, // data is copied
size_t header_size, // includes load commands
uint64_t load_address,
string file_path,
@@ -163,7 +162,7 @@ class DynamicImage {
uint32_t GetVersion() {return version_;}
// For sorting
- bool operator<(const DynamicImage &inInfo) {
+ bool operator<(const DynamicImage& inInfo) {
return GetLoadAddress() < inInfo.GetLoadAddress();
}
@@ -171,8 +170,8 @@ class DynamicImage {
bool IsValid() {return GetVMSize() != 0;}
private:
- DynamicImage(const DynamicImage &);
- DynamicImage &operator=(const DynamicImage &);
+ DynamicImage(const DynamicImage&);
+ DynamicImage& operator=(const DynamicImage&);
friend class DynamicImages;
template<typename MachBits>
@@ -205,26 +204,27 @@ class DynamicImage {
//
class DynamicImageRef {
public:
- explicit DynamicImageRef(DynamicImage *inP) : p(inP) {}
+ explicit DynamicImageRef(DynamicImage* inP) : p(inP) {}
// The copy constructor is required by STL
- DynamicImageRef(const DynamicImageRef &inRef) : p(inRef.p) {}
+ DynamicImageRef(const DynamicImageRef& inRef) = default;
+ DynamicImageRef& operator=(const DynamicImageRef& inRef) = default;
- bool operator<(const DynamicImageRef &inRef) const {
+ bool operator<(const DynamicImageRef& inRef) const {
return (*const_cast<DynamicImageRef*>(this)->p)
< (*const_cast<DynamicImageRef&>(inRef).p);
}
- bool operator==(const DynamicImageRef &inInfo) const {
+ bool operator==(const DynamicImageRef& inInfo) const {
return (*const_cast<DynamicImageRef*>(this)->p).GetLoadAddress() ==
(*const_cast<DynamicImageRef&>(inInfo)).GetLoadAddress();
}
// Be just like DynamicImage*
- DynamicImage *operator->() {return p;}
+ DynamicImage* operator->() {return p;}
operator DynamicImage*() {return p;}
private:
- DynamicImage *p;
+ DynamicImage* p;
};
// Helper function to deal with 32-bit/64-bit Mach-O differences.
@@ -250,7 +250,7 @@ class DynamicImages {
int GetImageCount() const {return static_cast<int>(image_list_.size());}
// Returns an individual image.
- DynamicImage *GetImage(int i) {
+ DynamicImage* GetImage(int i) {
if (i < (int)image_list_.size()) {
return image_list_[i];
}
@@ -258,7 +258,7 @@ class DynamicImages {
}
// Returns the image corresponding to the main executable.
- DynamicImage *GetExecutableImage();
+ DynamicImage* GetExecutableImage();
int GetExecutableImageIndex();
// Returns the task which we're looking at.
@@ -312,7 +312,7 @@ class DynamicImages {
kern_return_t ReadTaskMemory(task_port_t target_task,
const uint64_t address,
size_t length,
- vector<uint8_t> &bytes);
+ vector<uint8_t>& bytes);
} // namespace google_breakpad
diff --git a/src/client/mac/handler/exception_handler.cc b/src/client/mac/handler/exception_handler.cc
index 2a19d46a..c091209f 100644
--- a/src/client/mac/handler/exception_handler.cc
+++ b/src/client/mac/handler/exception_handler.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2006, Google Inc.
-// All rights reserved.
+// Copyright 2006 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -220,7 +219,7 @@ kern_return_t catch_exception_raise(mach_port_t port, mach_port_t failed_thread,
}
#endif
-ExceptionHandler::ExceptionHandler(const string &dump_path,
+ExceptionHandler::ExceptionHandler(const string& dump_path,
FilterCallback filter,
MinidumpCallback callback,
void* callback_context,
@@ -304,7 +303,7 @@ bool ExceptionHandler::WriteMinidump(bool write_exception_stream) {
}
// static
-bool ExceptionHandler::WriteMinidump(const string &dump_path,
+bool ExceptionHandler::WriteMinidump(const string& dump_path,
bool write_exception_stream,
MinidumpCallback callback,
void* callback_context) {
@@ -316,7 +315,7 @@ bool ExceptionHandler::WriteMinidump(const string &dump_path,
// static
bool ExceptionHandler::WriteMinidumpForChild(mach_port_t child,
mach_port_t child_blamed_thread,
- const string &dump_path,
+ const string& dump_path,
MinidumpCallback callback,
void* callback_context) {
ScopedTaskSuspend suspend(child);
diff --git a/src/client/mac/handler/exception_handler.h b/src/client/mac/handler/exception_handler.h
index f1d9ae92..ec7ffe7e 100644
--- a/src/client/mac/handler/exception_handler.h
+++ b/src/client/mac/handler/exception_handler.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2006, Google Inc.
-// All rights reserved.
+// Copyright 2006 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -75,7 +74,7 @@ class ExceptionHandler {
// attempting to write a minidump. If a FilterCallback returns false, Breakpad
// will immediately report the exception as unhandled without writing a
// minidump, allowing another handler the opportunity to handle it.
- typedef bool (*FilterCallback)(void *context);
+ typedef bool (*FilterCallback)(void* context);
// A callback function to run after the minidump has been written.
// |minidump_id| is a unique id for the dump, so the minidump
@@ -85,18 +84,18 @@ class ExceptionHandler {
// Return true if the exception was fully handled and breakpad should exit.
// Return false to allow any other exception handlers to process the
// exception.
- typedef bool (*MinidumpCallback)(const char *dump_dir,
- const char *minidump_id,
- void *context, bool succeeded);
+ typedef bool (*MinidumpCallback)(const char* dump_dir,
+ const char* minidump_id,
+ void* context, bool succeeded);
// A callback function which will be called directly if an exception occurs.
// This bypasses the minidump file writing and simply gives the client
// the exception information.
- typedef bool (*DirectCallback)( void *context,
- int exception_type,
- int exception_code,
- int exception_subcode,
- mach_port_t thread_name);
+ typedef bool (*DirectCallback)(void* context,
+ int exception_type,
+ int exception_code,
+ int exception_subcode,
+ mach_port_t thread_name);
// Creates a new ExceptionHandler instance to handle writing minidumps.
// Minidump files will be written to dump_path, and the optional callback
@@ -106,22 +105,22 @@ class ExceptionHandler {
// be written when WriteMinidump is called.
// If port_name is non-NULL, attempt to perform out-of-process dump generation
// If port_name is NULL, in-process dump generation will be used.
- ExceptionHandler(const string &dump_path,
+ ExceptionHandler(const string& dump_path,
FilterCallback filter, MinidumpCallback callback,
- void *callback_context, bool install_handler,
- const char *port_name);
+ void* callback_context, bool install_handler,
+ const char* port_name);
// A special constructor if we want to bypass minidump writing and
// simply get a callback with the exception information.
ExceptionHandler(DirectCallback callback,
- void *callback_context,
+ void* callback_context,
bool install_handler);
~ExceptionHandler();
// Get and set the minidump path.
string dump_path() const { return dump_path_; }
- void set_dump_path(const string &dump_path) {
+ void set_dump_path(const string& dump_path) {
dump_path_ = dump_path;
dump_path_c_ = dump_path_.c_str();
UpdateNextID(); // Necessary to put dump_path_ in next_minidump_path_.
@@ -137,23 +136,23 @@ class ExceptionHandler {
// Convenience form of WriteMinidump which does not require an
// ExceptionHandler instance.
- static bool WriteMinidump(const string &dump_path, MinidumpCallback callback,
- void *callback_context) {
+ static bool WriteMinidump(const string& dump_path, MinidumpCallback callback,
+ void* callback_context) {
return WriteMinidump(dump_path, false, callback, callback_context);
}
- static bool WriteMinidump(const string &dump_path,
+ static bool WriteMinidump(const string& dump_path,
bool write_exception_stream,
MinidumpCallback callback,
- void *callback_context);
+ void* callback_context);
// Write a minidump of child immediately. This can be used to capture
// the execution state of a child process independently of a crash.
static bool WriteMinidumpForChild(mach_port_t child,
- mach_port_t child_blamed_thread,
- const std::string &dump_path,
- MinidumpCallback callback,
- void *callback_context);
+ mach_port_t child_blamed_thread,
+ const std::string& dump_path,
+ MinidumpCallback callback,
+ void* callback_context);
// Returns whether out-of-process dump generation is used or not.
bool IsOutOfProcess() const {
@@ -189,21 +188,21 @@ class ExceptionHandler {
bool WriteMinidumpWithException(int exception_type,
int exception_code,
int exception_subcode,
- breakpad_ucontext_t *task_context,
+ breakpad_ucontext_t* task_context,
mach_port_t thread_name,
bool exit_after_write,
bool report_current_thread);
// When installed, this static function will be call from a newly created
// pthread with |this| as the argument
- static void *WaitForMessage(void *exception_handler_class);
+ static void* WaitForMessage(void* exception_handler_class);
// Signal handler for SIGABRT.
static void SignalHandler(int sig, siginfo_t* info, void* uc);
// disallow copy ctor and operator=
- explicit ExceptionHandler(const ExceptionHandler &);
- void operator=(const ExceptionHandler &);
+ explicit ExceptionHandler(const ExceptionHandler&);
+ void operator=(const ExceptionHandler&);
// Generates a new ID and stores it in next_minidump_id_, and stores the
// path of the next minidump to be written in next_minidump_path_.
@@ -224,15 +223,15 @@ class ExceptionHandler {
string next_minidump_path_;
// Pointers to the UTF-8 versions of above
- const char *dump_path_c_;
- const char *next_minidump_id_c_;
- const char *next_minidump_path_c_;
+ const char* dump_path_c_;
+ const char* next_minidump_id_c_;
+ const char* next_minidump_path_c_;
// The callback function and pointer to be passed back after the minidump
// has been written
FilterCallback filter_;
MinidumpCallback callback_;
- void *callback_context_;
+ void* callback_context_;
// The callback function to be passed back when we don't want a minidump
// file to be written
@@ -247,7 +246,7 @@ class ExceptionHandler {
// These variables save the previous exception handler's data so that it
// can be re-installed when this handler is uninstalled
- ExceptionParameters *previous_;
+ ExceptionParameters* previous_;
// True, if we've installed the exception handler
bool installed_exception_handler_;
diff --git a/src/client/mac/handler/mach_vm_compat.h b/src/client/mac/handler/mach_vm_compat.h
index 9e9028b9..b7dc159b 100644
--- a/src/client/mac/handler/mach_vm_compat.h
+++ b/src/client/mac/handler/mach_vm_compat.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2011, Google Inc.
-// All rights reserved.
+// Copyright 2011 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/client/mac/handler/minidump_generator.cc b/src/client/mac/handler/minidump_generator.cc
index 50df9002..3738416e 100644
--- a/src/client/mac/handler/minidump_generator.cc
+++ b/src/client/mac/handler/minidump_generator.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2006, Google Inc.
-// All rights reserved.
+// Copyright 2006 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -62,6 +61,8 @@ using MacStringUtils::IntegerValueAtIndex;
namespace google_breakpad {
+using mach_o::FileID;
+
#if defined(__LP64__) && __LP64__
#define LC_SEGMENT_ARCH LC_SEGMENT_64
#else
@@ -191,12 +192,12 @@ void MinidumpGenerator::GatherSystemInformation() {
os_build_number_ = IntegerValueAtIndex(product_str, 2);
}
-void MinidumpGenerator::SetTaskContext(breakpad_ucontext_t *task_context) {
+void MinidumpGenerator::SetTaskContext(breakpad_ucontext_t* task_context) {
task_context_ = task_context;
}
-string MinidumpGenerator::UniqueNameInDirectory(const string &dir,
- string *unique_name) {
+string MinidumpGenerator::UniqueNameInDirectory(const string& dir,
+ string* unique_name) {
CFUUIDRef uuid = CFUUIDCreate(NULL);
CFStringRef uuid_cfstr = CFUUIDCreateString(NULL, uuid);
CFRelease(uuid);
@@ -220,7 +221,7 @@ string MinidumpGenerator::UniqueNameInDirectory(const string &dir,
return path;
}
-bool MinidumpGenerator::Write(const char *path) {
+bool MinidumpGenerator::Write(const char* path) {
WriteStreamFN writers[] = {
&MinidumpGenerator::WriteThreadListStream,
&MinidumpGenerator::WriteMemoryListStream,
@@ -256,10 +257,10 @@ bool MinidumpGenerator::Write(const char *path) {
if (!dir.AllocateArray(writer_count))
return false;
- MDRawHeader *header_ptr = header.get();
+ MDRawHeader* header_ptr = header.get();
header_ptr->signature = MD_HEADER_SIGNATURE;
header_ptr->version = MD_HEADER_VERSION;
- time(reinterpret_cast<time_t *>(&(header_ptr->time_date_stamp)));
+ time(reinterpret_cast<time_t*>(&(header_ptr->time_date_stamp)));
header_ptr->stream_count = writer_count;
header_ptr->stream_directory_rva = dir.position();
@@ -335,7 +336,7 @@ size_t MinidumpGenerator::CalculateStackSize(mach_vm_address_t start_addr) {
bool MinidumpGenerator::WriteStackFromStartAddress(
mach_vm_address_t start_addr,
- MDMemoryDescriptor *stack_location) {
+ MDMemoryDescriptor* stack_location) {
UntypedMDRVA memory(&writer_);
bool result = false;
@@ -372,7 +373,7 @@ bool MinidumpGenerator::WriteStackFromStartAddress(
result = memory.Copy(&stack_memory[0], size);
} else {
- result = memory.Copy(reinterpret_cast<const void *>(start_addr), size);
+ result = memory.Copy(reinterpret_cast<const void*>(start_addr), size);
}
}
@@ -383,7 +384,7 @@ bool MinidumpGenerator::WriteStackFromStartAddress(
}
bool MinidumpGenerator::WriteStack(breakpad_thread_state_data_t state,
- MDMemoryDescriptor *stack_location) {
+ MDMemoryDescriptor* stack_location) {
switch (cpu_type_) {
#ifdef HAS_ARM_SUPPORT
case CPU_TYPE_ARM:
@@ -411,7 +412,7 @@ bool MinidumpGenerator::WriteStack(breakpad_thread_state_data_t state,
}
bool MinidumpGenerator::WriteContext(breakpad_thread_state_data_t state,
- MDLocationDescriptor *register_location) {
+ MDLocationDescriptor* register_location) {
switch (cpu_type_) {
#ifdef HAS_ARM_SUPPORT
case CPU_TYPE_ARM:
@@ -469,33 +470,33 @@ uint64_t MinidumpGenerator::CurrentPCForStack(
#ifdef HAS_ARM_SUPPORT
bool MinidumpGenerator::WriteStackARM(breakpad_thread_state_data_t state,
- MDMemoryDescriptor *stack_location) {
- arm_thread_state_t *machine_state =
- reinterpret_cast<arm_thread_state_t *>(state);
+ MDMemoryDescriptor* stack_location) {
+ arm_thread_state_t* machine_state =
+ reinterpret_cast<arm_thread_state_t*>(state);
mach_vm_address_t start_addr = REGISTER_FROM_THREADSTATE(machine_state, sp);
return WriteStackFromStartAddress(start_addr, stack_location);
}
uint64_t
MinidumpGenerator::CurrentPCForStackARM(breakpad_thread_state_data_t state) {
- arm_thread_state_t *machine_state =
- reinterpret_cast<arm_thread_state_t *>(state);
+ arm_thread_state_t* machine_state =
+ reinterpret_cast<arm_thread_state_t*>(state);
return REGISTER_FROM_THREADSTATE(machine_state, pc);
}
bool MinidumpGenerator::WriteContextARM(breakpad_thread_state_data_t state,
- MDLocationDescriptor *register_location)
+ MDLocationDescriptor* register_location)
{
TypedMDRVA<MDRawContextARM> context(&writer_);
- arm_thread_state_t *machine_state =
- reinterpret_cast<arm_thread_state_t *>(state);
+ arm_thread_state_t* machine_state =
+ reinterpret_cast<arm_thread_state_t*>(state);
if (!context.Allocate())
return false;
*register_location = context.location();
- MDRawContextARM *context_ptr = context.get();
+ MDRawContextARM* context_ptr = context.get();
context_ptr->context_flags = MD_CONTEXT_ARM_FULL;
#define AddGPR(a) context_ptr->iregs[a] = REGISTER_FROM_THREADSTATE(machine_state, r[a])
@@ -526,34 +527,34 @@ bool MinidumpGenerator::WriteContextARM(breakpad_thread_state_data_t state,
#ifdef HAS_ARM64_SUPPORT
bool MinidumpGenerator::WriteStackARM64(breakpad_thread_state_data_t state,
- MDMemoryDescriptor *stack_location) {
- arm_thread_state64_t *machine_state =
- reinterpret_cast<arm_thread_state64_t *>(state);
+ MDMemoryDescriptor* stack_location) {
+ arm_thread_state64_t* machine_state =
+ reinterpret_cast<arm_thread_state64_t*>(state);
mach_vm_address_t start_addr = REGISTER_FROM_THREADSTATE(machine_state, sp);
return WriteStackFromStartAddress(start_addr, stack_location);
}
uint64_t
MinidumpGenerator::CurrentPCForStackARM64(breakpad_thread_state_data_t state) {
- arm_thread_state64_t *machine_state =
- reinterpret_cast<arm_thread_state64_t *>(state);
+ arm_thread_state64_t* machine_state =
+ reinterpret_cast<arm_thread_state64_t*>(state);
return REGISTER_FROM_THREADSTATE(machine_state, pc);
}
bool
MinidumpGenerator::WriteContextARM64(breakpad_thread_state_data_t state,
- MDLocationDescriptor *register_location)
+ MDLocationDescriptor* register_location)
{
TypedMDRVA<MDRawContextARM64_Old> context(&writer_);
- arm_thread_state64_t *machine_state =
- reinterpret_cast<arm_thread_state64_t *>(state);
+ arm_thread_state64_t* machine_state =
+ reinterpret_cast<arm_thread_state64_t*>(state);
if (!context.Allocate())
return false;
*register_location = context.location();
- MDRawContextARM64_Old *context_ptr = context.get();
+ MDRawContextARM64_Old* context_ptr = context.get();
context_ptr->context_flags = MD_CONTEXT_ARM64_FULL_OLD;
#define AddGPR(a) \
@@ -602,49 +603,49 @@ MinidumpGenerator::WriteContextARM64(breakpad_thread_state_data_t state,
#ifdef HAS_PCC_SUPPORT
bool MinidumpGenerator::WriteStackPPC(breakpad_thread_state_data_t state,
- MDMemoryDescriptor *stack_location) {
- ppc_thread_state_t *machine_state =
- reinterpret_cast<ppc_thread_state_t *>(state);
+ MDMemoryDescriptor* stack_location) {
+ ppc_thread_state_t* machine_state =
+ reinterpret_cast<ppc_thread_state_t*>(state);
mach_vm_address_t start_addr = REGISTER_FROM_THREADSTATE(machine_state, r1);
return WriteStackFromStartAddress(start_addr, stack_location);
}
bool MinidumpGenerator::WriteStackPPC64(breakpad_thread_state_data_t state,
- MDMemoryDescriptor *stack_location) {
- ppc_thread_state64_t *machine_state =
- reinterpret_cast<ppc_thread_state64_t *>(state);
+ MDMemoryDescriptor* stack_location) {
+ ppc_thread_state64_t* machine_state =
+ reinterpret_cast<ppc_thread_state64_t*>(state);
mach_vm_address_t start_addr = REGISTER_FROM_THREADSTATE(machine_state, r1);
return WriteStackFromStartAddress(start_addr, stack_location);
}
uint64_t
MinidumpGenerator::CurrentPCForStackPPC(breakpad_thread_state_data_t state) {
- ppc_thread_state_t *machine_state =
- reinterpret_cast<ppc_thread_state_t *>(state);
+ ppc_thread_state_t* machine_state =
+ reinterpret_cast<ppc_thread_state_t*>(state);
return REGISTER_FROM_THREADSTATE(machine_state, srr0);
}
uint64_t
MinidumpGenerator::CurrentPCForStackPPC64(breakpad_thread_state_data_t state) {
- ppc_thread_state64_t *machine_state =
- reinterpret_cast<ppc_thread_state64_t *>(state);
+ ppc_thread_state64_t* machine_state =
+ reinterpret_cast<ppc_thread_state64_t*>(state);
return REGISTER_FROM_THREADSTATE(machine_state, srr0);
}
bool MinidumpGenerator::WriteContextPPC(breakpad_thread_state_data_t state,
- MDLocationDescriptor *register_location)
+ MDLocationDescriptor* register_location)
{
TypedMDRVA<MDRawContextPPC> context(&writer_);
- ppc_thread_state_t *machine_state =
- reinterpret_cast<ppc_thread_state_t *>(state);
+ ppc_thread_state_t* machine_state =
+ reinterpret_cast<ppc_thread_state_t*>(state);
if (!context.Allocate())
return false;
*register_location = context.location();
- MDRawContextPPC *context_ptr = context.get();
+ MDRawContextPPC* context_ptr = context.get();
context_ptr->context_flags = MD_CONTEXT_PPC_BASE;
#define AddReg(a) context_ptr->a = static_cast<__typeof__(context_ptr->a)>( \
@@ -701,16 +702,16 @@ bool MinidumpGenerator::WriteContextPPC(breakpad_thread_state_data_t state,
bool MinidumpGenerator::WriteContextPPC64(
breakpad_thread_state_data_t state,
- MDLocationDescriptor *register_location) {
+ MDLocationDescriptor* register_location) {
TypedMDRVA<MDRawContextPPC64> context(&writer_);
- ppc_thread_state64_t *machine_state =
- reinterpret_cast<ppc_thread_state64_t *>(state);
+ ppc_thread_state64_t* machine_state =
+ reinterpret_cast<ppc_thread_state64_t*>(state);
if (!context.Allocate())
return false;
*register_location = context.location();
- MDRawContextPPC64 *context_ptr = context.get();
+ MDRawContextPPC64* context_ptr = context.get();
context_ptr->context_flags = MD_CONTEXT_PPC_BASE;
#define AddReg(a) context_ptr->a = static_cast<__typeof__(context_ptr->a)>( \
@@ -768,18 +769,18 @@ bool MinidumpGenerator::WriteContextPPC64(
#ifdef HAS_X86_SUPPORT
bool MinidumpGenerator::WriteStackX86(breakpad_thread_state_data_t state,
- MDMemoryDescriptor *stack_location) {
- i386_thread_state_t *machine_state =
- reinterpret_cast<i386_thread_state_t *>(state);
+ MDMemoryDescriptor* stack_location) {
+ i386_thread_state_t* machine_state =
+ reinterpret_cast<i386_thread_state_t*>(state);
mach_vm_address_t start_addr = REGISTER_FROM_THREADSTATE(machine_state, esp);
return WriteStackFromStartAddress(start_addr, stack_location);
}
bool MinidumpGenerator::WriteStackX86_64(breakpad_thread_state_data_t state,
- MDMemoryDescriptor *stack_location) {
- x86_thread_state64_t *machine_state =
- reinterpret_cast<x86_thread_state64_t *>(state);
+ MDMemoryDescriptor* stack_location) {
+ x86_thread_state64_t* machine_state =
+ reinterpret_cast<x86_thread_state64_t*>(state);
mach_vm_address_t start_addr = static_cast<mach_vm_address_t>(
REGISTER_FROM_THREADSTATE(machine_state, rsp));
@@ -788,32 +789,32 @@ bool MinidumpGenerator::WriteStackX86_64(breakpad_thread_state_data_t state,
uint64_t
MinidumpGenerator::CurrentPCForStackX86(breakpad_thread_state_data_t state) {
- i386_thread_state_t *machine_state =
- reinterpret_cast<i386_thread_state_t *>(state);
+ i386_thread_state_t* machine_state =
+ reinterpret_cast<i386_thread_state_t*>(state);
return REGISTER_FROM_THREADSTATE(machine_state, eip);
}
uint64_t
MinidumpGenerator::CurrentPCForStackX86_64(breakpad_thread_state_data_t state) {
- x86_thread_state64_t *machine_state =
- reinterpret_cast<x86_thread_state64_t *>(state);
+ x86_thread_state64_t* machine_state =
+ reinterpret_cast<x86_thread_state64_t*>(state);
return REGISTER_FROM_THREADSTATE(machine_state, rip);
}
bool MinidumpGenerator::WriteContextX86(breakpad_thread_state_data_t state,
- MDLocationDescriptor *register_location)
+ MDLocationDescriptor* register_location)
{
TypedMDRVA<MDRawContextX86> context(&writer_);
- i386_thread_state_t *machine_state =
- reinterpret_cast<i386_thread_state_t *>(state);
+ i386_thread_state_t* machine_state =
+ reinterpret_cast<i386_thread_state_t*>(state);
if (!context.Allocate())
return false;
*register_location = context.location();
- MDRawContextX86 *context_ptr = context.get();
+ MDRawContextX86* context_ptr = context.get();
#define AddReg(a) context_ptr->a = static_cast<__typeof__(context_ptr->a)>( \
REGISTER_FROM_THREADSTATE(machine_state, a))
@@ -844,16 +845,16 @@ bool MinidumpGenerator::WriteContextX86(breakpad_thread_state_data_t state,
bool MinidumpGenerator::WriteContextX86_64(
breakpad_thread_state_data_t state,
- MDLocationDescriptor *register_location) {
+ MDLocationDescriptor* register_location) {
TypedMDRVA<MDRawContextAMD64> context(&writer_);
- x86_thread_state64_t *machine_state =
- reinterpret_cast<x86_thread_state64_t *>(state);
+ x86_thread_state64_t* machine_state =
+ reinterpret_cast<x86_thread_state64_t*>(state);
if (!context.Allocate())
return false;
*register_location = context.location();
- MDRawContextAMD64 *context_ptr = context.get();
+ MDRawContextAMD64* context_ptr = context.get();
#define AddReg(a) context_ptr->a = static_cast<__typeof__(context_ptr->a)>( \
REGISTER_FROM_THREADSTATE(machine_state, a))
@@ -892,7 +893,7 @@ bool MinidumpGenerator::WriteContextX86_64(
bool MinidumpGenerator::GetThreadState(thread_act_t target_thread,
thread_state_t state,
- mach_msg_type_number_t *count) {
+ mach_msg_type_number_t* count) {
if (task_context_ && target_thread == mach_thread_self()) {
switch (cpu_type_) {
#ifdef HAS_ARM_SUPPORT
@@ -963,7 +964,7 @@ bool MinidumpGenerator::GetThreadState(thread_act_t target_thread,
}
bool MinidumpGenerator::WriteThreadStream(mach_port_t thread_id,
- MDRawThread *thread) {
+ MDRawThread* thread) {
breakpad_thread_state_data_t state;
mach_msg_type_number_t state_count
= static_cast<mach_msg_type_number_t>(sizeof(state));
@@ -986,7 +987,7 @@ bool MinidumpGenerator::WriteThreadStream(mach_port_t thread_id,
}
bool MinidumpGenerator::WriteThreadListStream(
- MDRawDirectory *thread_list_stream) {
+ MDRawDirectory* thread_list_stream) {
TypedMDRVA<MDRawThreadList> list(&writer_);
thread_act_port_array_t threads_for_task;
mach_msg_type_number_t thread_count;
@@ -1027,7 +1028,7 @@ bool MinidumpGenerator::WriteThreadListStream(
}
bool MinidumpGenerator::WriteMemoryListStream(
- MDRawDirectory *memory_list_stream) {
+ MDRawDirectory* memory_list_stream) {
TypedMDRVA<MDRawMemoryList> list(&writer_);
// If the dump has an exception, include some memory around the
@@ -1119,7 +1120,7 @@ bool MinidumpGenerator::WriteMemoryListStream(
} else {
// In-process, just copy from local memory.
ip_memory.Copy(
- reinterpret_cast<const void *>(ip_memory_d.start_of_memory_range),
+ reinterpret_cast<const void*>(ip_memory_d.start_of_memory_range),
ip_memory_d.memory.data_size);
}
@@ -1133,7 +1134,7 @@ bool MinidumpGenerator::WriteMemoryListStream(
}
bool
-MinidumpGenerator::WriteExceptionStream(MDRawDirectory *exception_stream) {
+MinidumpGenerator::WriteExceptionStream(MDRawDirectory* exception_stream) {
TypedMDRVA<MDRawExceptionStream> exception(&writer_);
if (!exception.Allocate())
@@ -1141,7 +1142,7 @@ MinidumpGenerator::WriteExceptionStream(MDRawDirectory *exception_stream) {
exception_stream->stream_type = MD_EXCEPTION_STREAM;
exception_stream->location = exception.location();
- MDRawExceptionStream *exception_ptr = exception.get();
+ MDRawExceptionStream* exception_ptr = exception.get();
exception_ptr->thread_id = exception_thread_;
// This naming is confusing, but it is the proper translation from
@@ -1168,7 +1169,7 @@ MinidumpGenerator::WriteExceptionStream(MDRawDirectory *exception_stream) {
}
bool MinidumpGenerator::WriteSystemInfoStream(
- MDRawDirectory *system_info_stream) {
+ MDRawDirectory* system_info_stream) {
TypedMDRVA<MDRawSystemInfo> info(&writer_);
if (!info.Allocate())
@@ -1181,7 +1182,7 @@ bool MinidumpGenerator::WriteSystemInfoStream(
uint32_t number_of_processors;
size_t len = sizeof(number_of_processors);
sysctlbyname("hw.ncpu", &number_of_processors, &len, NULL, 0);
- MDRawSystemInfo *info_ptr = info.get();
+ MDRawSystemInfo* info_ptr = info.get();
switch (cpu_type_) {
#ifdef HAS_ARM_SUPPORT
@@ -1292,10 +1293,10 @@ bool MinidumpGenerator::WriteSystemInfoStream(
}
bool MinidumpGenerator::WriteModuleStream(unsigned int index,
- MDRawModule *module) {
+ MDRawModule* module) {
if (dynamic_images_) {
// we're in a different process than the crashed process
- DynamicImage *image = dynamic_images_->GetImage(index);
+ DynamicImage* image = dynamic_images_->GetImage(index);
if (!image)
return false;
@@ -1337,7 +1338,7 @@ bool MinidumpGenerator::WriteModuleStream(unsigned int index,
}
} else {
// Getting module info in the crashed process
- const breakpad_mach_header *header;
+ const breakpad_mach_header* header;
header = (breakpad_mach_header*)_dyld_get_image_header(index);
if (!header)
return false;
@@ -1357,16 +1358,16 @@ bool MinidumpGenerator::WriteModuleStream(unsigned int index,
int cpu_type = header->cputype;
unsigned long slide = _dyld_get_image_vmaddr_slide(index);
const char* name = _dyld_get_image_name(index);
- const struct load_command *cmd =
- reinterpret_cast<const struct load_command *>(header + 1);
+ const struct load_command* cmd =
+ reinterpret_cast<const struct load_command*>(header + 1);
memset(module, 0, sizeof(MDRawModule));
for (unsigned int i = 0; cmd && (i < header->ncmds); i++) {
if (cmd->cmd == LC_SEGMENT_ARCH) {
- const breakpad_mach_segment_command *seg =
- reinterpret_cast<const breakpad_mach_segment_command *>(cmd);
+ const breakpad_mach_segment_command* seg =
+ reinterpret_cast<const breakpad_mach_segment_command*>(cmd);
if (!strcmp(seg->segname, "__TEXT")) {
MDLocationDescriptor string_location;
@@ -1389,7 +1390,7 @@ bool MinidumpGenerator::WriteModuleStream(unsigned int index,
}
}
- cmd = reinterpret_cast<struct load_command*>((char *)cmd + cmd->cmdsize);
+ cmd = reinterpret_cast<struct load_command*>((char*)cmd + cmd->cmdsize);
}
}
@@ -1405,7 +1406,7 @@ int MinidumpGenerator::FindExecutableModule() {
}
} else {
int image_count = _dyld_image_count();
- const struct mach_header *header;
+ const struct mach_header* header;
for (int index = 0; index < image_count; ++index) {
header = _dyld_get_image_header(index);
@@ -1419,12 +1420,12 @@ int MinidumpGenerator::FindExecutableModule() {
return 0;
}
-bool MinidumpGenerator::WriteCVRecord(MDRawModule *module, int cpu_type,
- const char *module_path, bool in_memory) {
+bool MinidumpGenerator::WriteCVRecord(MDRawModule* module, int cpu_type,
+ const char* module_path, bool in_memory) {
TypedMDRVA<MDCVInfoPDB70> cv(&writer_);
// Only return the last path component of the full module path
- const char *module_name = strrchr(module_path, '/');
+ const char* module_name = strrchr(module_path, '/');
// Increment past the slash
if (module_name)
@@ -1441,7 +1442,7 @@ bool MinidumpGenerator::WriteCVRecord(MDRawModule *module, int cpu_type,
return false;
module->cv_record = cv.location();
- MDCVInfoPDB70 *cv_ptr = cv.get();
+ MDCVInfoPDB70* cv_ptr = cv.get();
cv_ptr->cv_signature = MD_CVINFOPDB70_SIGNATURE;
cv_ptr->age = 0;
@@ -1449,8 +1450,8 @@ bool MinidumpGenerator::WriteCVRecord(MDRawModule *module, int cpu_type,
unsigned char identifier[16];
bool result = false;
if (in_memory) {
- MacFileUtilities::MachoID macho(module_path,
- reinterpret_cast<void *>(module->base_of_image),
+ MacFileUtilities::MachoID macho(
+ reinterpret_cast<void*>(module->base_of_image),
static_cast<size_t>(module->size_of_image));
result = macho.UUIDCommand(cpu_type, CPU_SUBTYPE_MULTIPLE, identifier);
if (!result)
@@ -1487,7 +1488,7 @@ bool MinidumpGenerator::WriteCVRecord(MDRawModule *module, int cpu_type,
}
bool MinidumpGenerator::WriteModuleListStream(
- MDRawDirectory *module_list_stream) {
+ MDRawDirectory* module_list_stream) {
TypedMDRVA<MDRawModuleList> list(&writer_);
uint32_t image_count = dynamic_images_ ?
@@ -1525,7 +1526,7 @@ bool MinidumpGenerator::WriteModuleListStream(
return true;
}
-bool MinidumpGenerator::WriteMiscInfoStream(MDRawDirectory *misc_info_stream) {
+bool MinidumpGenerator::WriteMiscInfoStream(MDRawDirectory* misc_info_stream) {
TypedMDRVA<MDRawMiscInfo> info(&writer_);
if (!info.Allocate())
@@ -1534,7 +1535,7 @@ bool MinidumpGenerator::WriteMiscInfoStream(MDRawDirectory *misc_info_stream) {
misc_info_stream->stream_type = MD_MISC_INFO_STREAM;
misc_info_stream->location = info.location();
- MDRawMiscInfo *info_ptr = info.get();
+ MDRawMiscInfo* info_ptr = info.get();
info_ptr->size_of_info = static_cast<uint32_t>(sizeof(MDRawMiscInfo));
info_ptr->flags1 = MD_MISCINFO_FLAGS1_PROCESS_ID |
MD_MISCINFO_FLAGS1_PROCESS_TIMES |
@@ -1577,7 +1578,7 @@ bool MinidumpGenerator::WriteMiscInfoStream(MDRawDirectory *misc_info_stream) {
}
bool MinidumpGenerator::WriteBreakpadInfoStream(
- MDRawDirectory *breakpad_info_stream) {
+ MDRawDirectory* breakpad_info_stream) {
TypedMDRVA<MDRawBreakpadInfo> info(&writer_);
if (!info.Allocate())
@@ -1585,7 +1586,7 @@ bool MinidumpGenerator::WriteBreakpadInfoStream(
breakpad_info_stream->stream_type = MD_BREAKPAD_INFO_STREAM;
breakpad_info_stream->location = info.location();
- MDRawBreakpadInfo *info_ptr = info.get();
+ MDRawBreakpadInfo* info_ptr = info.get();
if (exception_thread_ && exception_type_) {
info_ptr->validity = MD_BREAKPAD_INFO_VALID_DUMP_THREAD_ID |
diff --git a/src/client/mac/handler/minidump_generator.h b/src/client/mac/handler/minidump_generator.h
index f3aa9bd3..efddfa9a 100644
--- a/src/client/mac/handler/minidump_generator.h
+++ b/src/client/mac/handler/minidump_generator.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2006, Google Inc.
-// All rights reserved.
+// Copyright 2006 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -106,12 +105,12 @@ class MinidumpGenerator {
// Return <dir>/<unique_name>.dmp
// Sets |unique_name| (if requested) to the unique name for the minidump
- static string UniqueNameInDirectory(const string &dir, string *unique_name);
+ static string UniqueNameInDirectory(const string& dir, string* unique_name);
// Write out the minidump into |path|
// All of the components of |path| must exist and be writable
// Return true if successful, false otherwise
- bool Write(const char *path);
+ bool Write(const char* path);
// Specify some exception information, if applicable
void SetExceptionInformation(int type, int code, int subcode,
@@ -125,7 +124,7 @@ class MinidumpGenerator {
// Specify the task context. If |task_context| is not NULL, it will be used
// to retrieve the context of the current thread, instead of using
// |thread_get_state|.
- void SetTaskContext(breakpad_ucontext_t *task_context);
+ void SetTaskContext(breakpad_ucontext_t* task_context);
// Gather system information. This should be call at least once before using
// the MinidumpGenerator class.
@@ -133,81 +132,81 @@ class MinidumpGenerator {
protected:
// Overridable Stream writers
- virtual bool WriteExceptionStream(MDRawDirectory *exception_stream);
+ virtual bool WriteExceptionStream(MDRawDirectory* exception_stream);
// Overridable Helper
- virtual bool WriteThreadStream(mach_port_t thread_id, MDRawThread *thread);
+ virtual bool WriteThreadStream(mach_port_t thread_id, MDRawThread* thread);
private:
- typedef bool (MinidumpGenerator::*WriteStreamFN)(MDRawDirectory *);
+ typedef bool (MinidumpGenerator::*WriteStreamFN)(MDRawDirectory*);
// Stream writers
- bool WriteThreadListStream(MDRawDirectory *thread_list_stream);
- bool WriteMemoryListStream(MDRawDirectory *memory_list_stream);
- bool WriteSystemInfoStream(MDRawDirectory *system_info_stream);
- bool WriteModuleListStream(MDRawDirectory *module_list_stream);
- bool WriteMiscInfoStream(MDRawDirectory *misc_info_stream);
- bool WriteBreakpadInfoStream(MDRawDirectory *breakpad_info_stream);
+ bool WriteThreadListStream(MDRawDirectory* thread_list_stream);
+ bool WriteMemoryListStream(MDRawDirectory* memory_list_stream);
+ bool WriteSystemInfoStream(MDRawDirectory* system_info_stream);
+ bool WriteModuleListStream(MDRawDirectory* module_list_stream);
+ bool WriteMiscInfoStream(MDRawDirectory* misc_info_stream);
+ bool WriteBreakpadInfoStream(MDRawDirectory* breakpad_info_stream);
// Helpers
uint64_t CurrentPCForStack(breakpad_thread_state_data_t state);
bool GetThreadState(thread_act_t target_thread, thread_state_t state,
- mach_msg_type_number_t *count);
+ mach_msg_type_number_t* count);
bool WriteStackFromStartAddress(mach_vm_address_t start_addr,
- MDMemoryDescriptor *stack_location);
+ MDMemoryDescriptor* stack_location);
bool WriteStack(breakpad_thread_state_data_t state,
- MDMemoryDescriptor *stack_location);
+ MDMemoryDescriptor* stack_location);
bool WriteContext(breakpad_thread_state_data_t state,
- MDLocationDescriptor *register_location);
- bool WriteCVRecord(MDRawModule *module, int cpu_type,
- const char *module_path, bool in_memory);
- bool WriteModuleStream(unsigned int index, MDRawModule *module);
+ MDLocationDescriptor* register_location);
+ bool WriteCVRecord(MDRawModule* module, int cpu_type,
+ const char* module_path, bool in_memory);
+ bool WriteModuleStream(unsigned int index, MDRawModule* module);
size_t CalculateStackSize(mach_vm_address_t start_addr);
int FindExecutableModule();
// Per-CPU implementations of these methods
#ifdef HAS_ARM_SUPPORT
bool WriteStackARM(breakpad_thread_state_data_t state,
- MDMemoryDescriptor *stack_location);
+ MDMemoryDescriptor* stack_location);
bool WriteContextARM(breakpad_thread_state_data_t state,
- MDLocationDescriptor *register_location);
+ MDLocationDescriptor* register_location);
uint64_t CurrentPCForStackARM(breakpad_thread_state_data_t state);
#endif
#ifdef HAS_ARM64_SUPPORT
bool WriteStackARM64(breakpad_thread_state_data_t state,
- MDMemoryDescriptor *stack_location);
+ MDMemoryDescriptor* stack_location);
bool WriteContextARM64(breakpad_thread_state_data_t state,
- MDLocationDescriptor *register_location);
+ MDLocationDescriptor* register_location);
uint64_t CurrentPCForStackARM64(breakpad_thread_state_data_t state);
#endif
#ifdef HAS_PPC_SUPPORT
bool WriteStackPPC(breakpad_thread_state_data_t state,
- MDMemoryDescriptor *stack_location);
+ MDMemoryDescriptor* stack_location);
bool WriteContextPPC(breakpad_thread_state_data_t state,
- MDLocationDescriptor *register_location);
+ MDLocationDescriptor* register_location);
uint64_t CurrentPCForStackPPC(breakpad_thread_state_data_t state);
bool WriteStackPPC64(breakpad_thread_state_data_t state,
- MDMemoryDescriptor *stack_location);
+ MDMemoryDescriptor* stack_location);
bool WriteContextPPC64(breakpad_thread_state_data_t state,
- MDLocationDescriptor *register_location);
+ MDLocationDescriptor* register_location);
uint64_t CurrentPCForStackPPC64(breakpad_thread_state_data_t state);
#endif
#ifdef HAS_X86_SUPPORT
bool WriteStackX86(breakpad_thread_state_data_t state,
- MDMemoryDescriptor *stack_location);
+ MDMemoryDescriptor* stack_location);
bool WriteContextX86(breakpad_thread_state_data_t state,
- MDLocationDescriptor *register_location);
+ MDLocationDescriptor* register_location);
uint64_t CurrentPCForStackX86(breakpad_thread_state_data_t state);
bool WriteStackX86_64(breakpad_thread_state_data_t state,
- MDMemoryDescriptor *stack_location);
+ MDMemoryDescriptor* stack_location);
bool WriteContextX86_64(breakpad_thread_state_data_t state,
- MDLocationDescriptor *register_location);
+ MDLocationDescriptor* register_location);
uint64_t CurrentPCForStackX86_64(breakpad_thread_state_data_t state);
#endif
// disallow copy ctor and operator=
- explicit MinidumpGenerator(const MinidumpGenerator &);
- void operator=(const MinidumpGenerator &);
+ explicit MinidumpGenerator(const MinidumpGenerator&);
+ void operator=(const MinidumpGenerator&);
protected:
// Use this writer to put the data to disk
@@ -232,10 +231,10 @@ class MinidumpGenerator {
static int os_build_number_;
// Context of the task to dump.
- breakpad_ucontext_t *task_context_;
+ breakpad_ucontext_t* task_context_;
// Information about dynamically loaded code
- DynamicImages *dynamic_images_;
+ DynamicImages* dynamic_images_;
// PageAllocator makes it possible to allocate memory
// directly from the system, even while handling an exception.
diff --git a/src/client/mac/handler/protected_memory_allocator.cc b/src/client/mac/handler/protected_memory_allocator.cc
index 6142ad12..83383263 100644
--- a/src/client/mac/handler/protected_memory_allocator.cc
+++ b/src/client/mac/handler/protected_memory_allocator.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2006, Google Inc.
-// All rights reserved.
+// Copyright 2006 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/client/mac/handler/protected_memory_allocator.h b/src/client/mac/handler/protected_memory_allocator.h
index 7e188db2..86413c87 100644
--- a/src/client/mac/handler/protected_memory_allocator.h
+++ b/src/client/mac/handler/protected_memory_allocator.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2006, Google Inc.
-// All rights reserved.
+// Copyright 2006 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/client/mac/handler/testcases/DynamicImagesTests.cc b/src/client/mac/handler/testcases/DynamicImagesTests.cc
index 0fc7825b..14ea88d2 100644
--- a/src/client/mac/handler/testcases/DynamicImagesTests.cc
+++ b/src/client/mac/handler/testcases/DynamicImagesTests.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2008, Google Inc.
-// All rights reserved
+// Copyright 2008 Google LLC
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
@@ -10,7 +9,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -31,7 +30,7 @@
// minidump_test
//
// Created by Neal Sidhwaney on 4/17/08.
-// Copyright 2008 Google Inc. All rights reserved.
+// Copyright 2008 Google LLC
//
#include "client/mac/handler/testcases/DynamicImagesTests.h"
@@ -42,7 +41,7 @@ DynamicImagesTests test2(TEST_INVOCATION(DynamicImagesTests,
DynamicImagesTests test3(TEST_INVOCATION(DynamicImagesTests,
ReadLibrariesFromLocalTaskTest));
-DynamicImagesTests::DynamicImagesTests(TestInvocation *invocation)
+DynamicImagesTests::DynamicImagesTests(TestInvocation* invocation)
: TestCase(invocation) {
}
@@ -54,7 +53,7 @@ void DynamicImagesTests::ReadTaskMemoryTest() {
// pick test2 as a symbol we know to be valid to read
// anything will work, really
- void *addr = reinterpret_cast<void*>(&test2);
+ void* addr = reinterpret_cast<void*>(&test2);
std::vector<uint8_t> buf(getpagesize());
fprintf(stderr, "reading 0x%p\n", addr);
@@ -71,7 +70,7 @@ void DynamicImagesTests::ReadTaskMemoryTest() {
void DynamicImagesTests::ReadLibrariesFromLocalTaskTest() {
mach_port_t me = mach_task_self();
- google_breakpad::DynamicImages *d = new google_breakpad::DynamicImages(me);
+ google_breakpad::DynamicImages* d = new google_breakpad::DynamicImages(me);
fprintf(stderr,"Local task image count: %d\n", d->GetImageCount());
diff --git a/src/client/mac/handler/testcases/DynamicImagesTests.h b/src/client/mac/handler/testcases/DynamicImagesTests.h
index e1e79993..f60ee69c 100644
--- a/src/client/mac/handler/testcases/DynamicImagesTests.h
+++ b/src/client/mac/handler/testcases/DynamicImagesTests.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2008, Google Inc.
-// All rights reserved
+// Copyright 2008 Google LLC
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
@@ -10,7 +9,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -31,7 +30,7 @@
// minidump_test
//
// Created by Neal Sidhwaney on 4/17/08.
-// Copyright 2008 Google Inc. All rights reserved.
+// Copyright 2008 Google LLC
//
//
diff --git a/src/client/mac/handler/testcases/breakpad_nlist_test.cc b/src/client/mac/handler/testcases/breakpad_nlist_test.cc
index e7332bfb..a89d8c44 100644
--- a/src/client/mac/handler/testcases/breakpad_nlist_test.cc
+++ b/src/client/mac/handler/testcases/breakpad_nlist_test.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2008, Google Inc.
-// All rights reserved
+// Copyright 2008 Google LLC
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
@@ -10,7 +9,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -31,7 +30,7 @@
// minidump_test
//
// Created by Neal Sidhwaney on 4/13/08.
-// Copyright 2008 Google Inc. All rights reserved.
+// Copyright 2008 Google LLC
//
#include "client/mac/handler/testcases/breakpad_nlist_test.h"
@@ -40,7 +39,7 @@
BreakpadNlistTest test1(TEST_INVOCATION(BreakpadNlistTest, CompareToNM));
-BreakpadNlistTest::BreakpadNlistTest(TestInvocation *invocation)
+BreakpadNlistTest::BreakpadNlistTest(TestInvocation* invocation)
: TestCase(invocation) {
}
@@ -55,7 +54,7 @@ void BreakpadNlistTest::CompareToNM() {
system("/usr/bin/nm -arch ppc64 /usr/lib/dyld > /tmp/dyld-namelist.txt");
#endif
- FILE *fd = fopen("/tmp/dyld-namelist.txt", "rt");
+ FILE* fd = fopen("/tmp/dyld-namelist.txt", "rt");
char oneNMAddr[30];
char symbolType;
@@ -63,10 +62,10 @@ void BreakpadNlistTest::CompareToNM() {
while (!feof(fd)) {
fscanf(fd, "%s %c %s", oneNMAddr, &symbolType, symbolName);
breakpad_nlist symbolList[2];
- breakpad_nlist &list = symbolList[0];
+ breakpad_nlist& list = symbolList[0];
memset(symbolList, 0, sizeof(breakpad_nlist)*2);
- const char *symbolNames[2];
+ const char* symbolNames[2];
symbolNames[0] = (const char*)symbolName;
symbolNames[1] = "\0";
breakpad_nlist_64("/usr/lib/dyld", &list, symbolNames);
@@ -79,12 +78,12 @@ void BreakpadNlistTest::CompareToNM() {
fclose(fd);
}
-bool BreakpadNlistTest::IsSymbolMoreThanOnceInDyld(const char *symbolName) {
+bool BreakpadNlistTest::IsSymbolMoreThanOnceInDyld(const char* symbolName) {
// These are the symbols that occur more than once when nm dumps
// the symbol table of /usr/lib/dyld. Our nlist program returns
// the first address because it's doing a search so we need to exclude
// these from causing the test to fail
- const char *multipleSymbols[] = {
+ const char* multipleSymbols[] = {
"__Z41__static_initialization_and_destruction_0ii",
"___tcf_0",
"___tcf_1",
diff --git a/src/client/mac/handler/testcases/breakpad_nlist_test.h b/src/client/mac/handler/testcases/breakpad_nlist_test.h
index e93657cc..ca407ea8 100644
--- a/src/client/mac/handler/testcases/breakpad_nlist_test.h
+++ b/src/client/mac/handler/testcases/breakpad_nlist_test.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2008, Google Inc.
-// All rights reserved
+// Copyright 2008 Google LLC
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
@@ -10,7 +9,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -31,7 +30,7 @@
// minidump_test
//
// Created by Neal Sidhwaney on 4/13/08.
-// Copyright 2008 Google Inc. All rights reserved.
+// Copyright 2008 Google LLC
//
//
@@ -47,7 +46,7 @@ class BreakpadNlistTest : public TestCase {
// /usr/lib/dyld. So we track those so we don't report failures
// in mismatches between what our nlist returns and what nm has
// for the duplicate symbols.
- bool IsSymbolMoreThanOnceInDyld(const char *symbolName);
+ bool IsSymbolMoreThanOnceInDyld(const char* symbolName);
public:
explicit BreakpadNlistTest(TestInvocation* invocation);
diff --git a/src/client/mac/handler/testcases/dwarftests.h b/src/client/mac/handler/testcases/dwarftests.h
index 21ff7a44..0c35374a 100644
--- a/src/client/mac/handler/testcases/dwarftests.h
+++ b/src/client/mac/handler/testcases/dwarftests.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2008, Google Inc.
-// All rights reserved
+// Copyright 2008 Google LLC
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
@@ -10,7 +9,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -31,7 +30,7 @@
// minidump_test
//
// Created by Neal Sidhwaney on 9/24/08.
-// Copyright 2008 Google Inc. All rights reserved.
+// Copyright 2008 Google LLC
//
#import <SenTestingKit/SenTestingKit.h>
diff --git a/src/client/mac/handler/testcases/dwarftests.mm b/src/client/mac/handler/testcases/dwarftests.mm
index 40c69aff..c02a2d23 100644
--- a/src/client/mac/handler/testcases/dwarftests.mm
+++ b/src/client/mac/handler/testcases/dwarftests.mm
@@ -1,5 +1,4 @@
-// Copyright (c) 2008, Google Inc.
-// All rights reserved
+// Copyright 2008 Google LLC
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
@@ -10,7 +9,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -31,7 +30,7 @@
// minidump_test
//
// Created by Neal Sidhwaney on 9/24/08.
-// Copyright 2008 Google Inc. All rights reserved.
+// Copyright 2008 Google LLC
//
#import "dwarftests.h"
diff --git a/src/client/mac/handler/ucontext_compat.h b/src/client/mac/handler/ucontext_compat.h
index 1e4b752e..853b1caa 100644
--- a/src/client/mac/handler/ucontext_compat.h
+++ b/src/client/mac/handler/ucontext_compat.h
@@ -1,5 +1,4 @@
-// Copyright 2013 Google Inc.
-// All rights reserved.
+// Copyright 2013 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/client/mac/sender/crash_report_sender.h b/src/client/mac/sender/crash_report_sender.h
index 6a29d48a..13379cea 100644
--- a/src/client/mac/sender/crash_report_sender.h
+++ b/src/client/mac/sender/crash_report_sender.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2006, Google Inc.
-// All rights reserved.
+// Copyright 2006 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/client/mac/sender/crash_report_sender.m b/src/client/mac/sender/crash_report_sender.m
index 88d26fb0..170fa07f 100644
--- a/src/client/mac/sender/crash_report_sender.m
+++ b/src/client/mac/sender/crash_report_sender.m
@@ -1,5 +1,4 @@
-// Copyright (c) 2006, Google Inc.
-// All rights reserved.
+// Copyright 2006 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/client/mac/sender/uploader.h b/src/client/mac/sender/uploader.h
index 0897dade..4eba7163 100644
--- a/src/client/mac/sender/uploader.h
+++ b/src/client/mac/sender/uploader.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2011, Google Inc.
-// All rights reserved.
+// Copyright 2011 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/client/mac/sender/uploader.mm b/src/client/mac/sender/uploader.mm
index 13b6130a..f2bcd0b1 100644
--- a/src/client/mac/sender/uploader.mm
+++ b/src/client/mac/sender/uploader.mm
@@ -1,5 +1,4 @@
-// Copyright (c) 2011, Google Inc.
-// All rights reserved.
+// Copyright 2011 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/client/mac/testapp/Controller.h b/src/client/mac/testapp/Controller.h
index 7b3be2d6..36f9572a 100644
--- a/src/client/mac/testapp/Controller.h
+++ b/src/client/mac/testapp/Controller.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2006, Google Inc.
-// All rights reserved.
+// Copyright 2006 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/client/mac/testapp/Controller.m b/src/client/mac/testapp/Controller.m
index 87c43024..2de84f3f 100644
--- a/src/client/mac/testapp/Controller.m
+++ b/src/client/mac/testapp/Controller.m
@@ -1,5 +1,4 @@
-// Copyright (c) 2006, Google Inc.
-// All rights reserved.
+// Copyright 2006 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/client/mac/testapp/TestClass.h b/src/client/mac/testapp/TestClass.h
index 0a6d736d..e20b0e87 100644
--- a/src/client/mac/testapp/TestClass.h
+++ b/src/client/mac/testapp/TestClass.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2006, Google Inc.
-// All rights reserved.
+// Copyright 2006 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/client/mac/testapp/TestClass.mm b/src/client/mac/testapp/TestClass.mm
index 6e6a8833..ed0a7eca 100644
--- a/src/client/mac/testapp/TestClass.mm
+++ b/src/client/mac/testapp/TestClass.mm
@@ -1,5 +1,4 @@
-// Copyright (c) 2006, Google Inc.
-// All rights reserved.
+// Copyright 2006 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/client/mac/testapp/main.m b/src/client/mac/testapp/main.m
index 1ed19bf9..af2cc141 100644
--- a/src/client/mac/testapp/main.m
+++ b/src/client/mac/testapp/main.m
@@ -1,5 +1,4 @@
-// Copyright (c) 2006, Google Inc.
-// All rights reserved.
+// Copyright 2006 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -30,5 +29,5 @@
#import <Cocoa/Cocoa.h>
int main(int argc, char *argv[]) {
- return NSApplicationMain(argc, (const char **) argv);
+ return NSApplicationMain(argc, (const char**)argv);
}
diff --git a/src/client/mac/tests/BreakpadFramework_Test.mm b/src/client/mac/tests/BreakpadFramework_Test.mm
index 2ea103c6..7a701330 100644
--- a/src/client/mac/tests/BreakpadFramework_Test.mm
+++ b/src/client/mac/tests/BreakpadFramework_Test.mm
@@ -1,5 +1,4 @@
-// Copyright (c) 2009, Google Inc.
-// All rights reserved.
+// Copyright 2009 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/client/mac/tests/crash_generation_server_test.cc b/src/client/mac/tests/crash_generation_server_test.cc
index 0164f4a2..50825a93 100644
--- a/src/client/mac/tests/crash_generation_server_test.cc
+++ b/src/client/mac/tests/crash_generation_server_test.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2010, Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -147,8 +146,8 @@ TEST_F(CrashGenerationServerTest, testRequestDumpNoDump) {
globfree(&dirContents);
}
-void dumpCallback(void *context, const ClientInfo &client_info,
- const std::string &file_path) {
+void dumpCallback(void* context, const ClientInfo& client_info,
+ const std::string& file_path) {
if (context) {
CrashGenerationServerTest* self =
reinterpret_cast<CrashGenerationServerTest*>(context);
@@ -158,7 +157,7 @@ void dumpCallback(void *context, const ClientInfo &client_info,
}
}
-void *RequestDump(void *context) {
+void* RequestDump(void* context) {
CrashGenerationClient client((const char*)context);
bool result = client.RequestDump();
return (void*)(result ? 0 : 1);
@@ -206,7 +205,7 @@ TEST_F(CrashGenerationServerTest, testRequestDump) {
}
static void Crasher() {
- int *a = (int*)0x42;
+ int* a = (int*)0x42;
fprintf(stdout, "Going to crash...\n");
fprintf(stdout, "A = %d", *a);
diff --git a/src/client/mac/tests/exception_handler_test.cc b/src/client/mac/tests/exception_handler_test.cc
index d5b505a1..eb9aa1bc 100644
--- a/src/client/mac/tests/exception_handler_test.cc
+++ b/src/client/mac/tests/exception_handler_test.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2010, Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -71,7 +70,7 @@ class ExceptionHandlerTest : public Test {
};
static void Crasher() {
- int *a = (int*)0x42;
+ int* a = (int*)0x42;
fprintf(stdout, "Going to crash...\n");
fprintf(stdout, "A = %d", *a);
@@ -86,8 +85,8 @@ static void SoonToCrash(void(*crasher)()) {
crasher();
}
-static bool MDCallback(const char *dump_dir, const char *file_name,
- void *context, bool success) {
+static bool MDCallback(const char* dump_dir, const char* file_name,
+ void* context, bool success) {
string path(dump_dir);
path.append("/");
path.append(file_name);
@@ -179,9 +178,9 @@ TEST_F(ExceptionHandlerTest, InProcessAbort) {
InProcessCrash(true);
}
-static bool DumpNameMDCallback(const char *dump_dir, const char *file_name,
- void *context, bool success) {
- ExceptionHandlerTest *self = reinterpret_cast<ExceptionHandlerTest*>(context);
+static bool DumpNameMDCallback(const char* dump_dir, const char* file_name,
+ void* context, bool success) {
+ ExceptionHandlerTest* self = reinterpret_cast<ExceptionHandlerTest*>(context);
if (dump_dir && file_name) {
self->lastDumpName = dump_dir;
self->lastDumpName += "/";
@@ -652,7 +651,7 @@ TEST_F(ExceptionHandlerTest, InstructionPointerMemoryNullPointer) {
ASSERT_EQ((unsigned int)1, memory_list->region_count());
}
-static void *Junk(void *) {
+static void* Junk(void*) {
sleep(1000000);
return NULL;
}
diff --git a/src/client/mac/tests/minidump_generator_test.cc b/src/client/mac/tests/minidump_generator_test.cc
index b1fa5d02..1a889dfe 100644
--- a/src/client/mac/tests/minidump_generator_test.cc
+++ b/src/client/mac/tests/minidump_generator_test.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2010, Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -79,7 +78,7 @@ class MinidumpGeneratorTest : public Test {
AutoTempDir tempDir;
};
-static void *Junk(void* data) {
+static void* Junk(void* data) {
bool* wait = reinterpret_cast<bool*>(data);
while (!*wait) {
usleep(10000);
diff --git a/src/client/mac/tests/minidump_generator_test_helper.cc b/src/client/mac/tests/minidump_generator_test_helper.cc
index 4e8ce3cf..93cbe1bb 100644
--- a/src/client/mac/tests/minidump_generator_test_helper.cc
+++ b/src/client/mac/tests/minidump_generator_test_helper.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2010, Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/client/mac/tests/spawn_child_process.h b/src/client/mac/tests/spawn_child_process.h
index e52ff6b6..cc804511 100644
--- a/src/client/mac/tests/spawn_child_process.h
+++ b/src/client/mac/tests/spawn_child_process.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2010, Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/client/minidump_file_writer-inl.h b/src/client/minidump_file_writer-inl.h
index 0e12e00b..d95f3554 100644
--- a/src/client/minidump_file_writer-inl.h
+++ b/src/client/minidump_file_writer-inl.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2006, Google Inc.
-// All rights reserved.
+// Copyright 2006 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -69,7 +68,7 @@ inline bool TypedMDRVA<MDType>::AllocateObjectAndArray(size_t count,
}
template<typename MDType>
-inline bool TypedMDRVA<MDType>::CopyIndex(unsigned int index, MDType *item) {
+inline bool TypedMDRVA<MDType>::CopyIndex(unsigned int index, MDType* item) {
assert(allocation_state_ == ARRAY);
return writer_->Copy(
static_cast<MDRVA>(position_ + index * minidump_size<MDType>::size()),
@@ -78,7 +77,7 @@ inline bool TypedMDRVA<MDType>::CopyIndex(unsigned int index, MDType *item) {
template<typename MDType>
inline bool TypedMDRVA<MDType>::CopyIndexAfterObject(unsigned int index,
- const void *src,
+ const void* src,
size_t length) {
assert(allocation_state_ == SINGLE_OBJECT_WITH_ARRAY);
return writer_->Copy(
diff --git a/src/client/minidump_file_writer.cc b/src/client/minidump_file_writer.cc
index a1957f32..d5193e2c 100644
--- a/src/client/minidump_file_writer.cc
+++ b/src/client/minidump_file_writer.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2006, Google Inc.
-// All rights reserved.
+// Copyright 2006 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -101,7 +100,7 @@ MinidumpFileWriter::~MinidumpFileWriter() {
Close();
}
-bool MinidumpFileWriter::Open(const char *path) {
+bool MinidumpFileWriter::Open(const char* path) {
assert(file_ == -1);
#if defined(__linux__) && __linux__
file_ = sys_open(path, O_WRONLY | O_CREAT | O_EXCL, 0600);
@@ -145,9 +144,9 @@ bool MinidumpFileWriter::Close() {
return result;
}
-bool MinidumpFileWriter::CopyStringToMDString(const wchar_t *str,
+bool MinidumpFileWriter::CopyStringToMDString(const wchar_t* str,
unsigned int length,
- TypedMDRVA<MDString> *mdstring) {
+ TypedMDRVA<MDString>* mdstring) {
bool result = true;
if (sizeof(wchar_t) == sizeof(uint16_t)) {
// Shortcut if wchar_t is the same size as MDString's buffer
@@ -178,9 +177,9 @@ bool MinidumpFileWriter::CopyStringToMDString(const wchar_t *str,
return result;
}
-bool MinidumpFileWriter::CopyStringToMDString(const char *str,
+bool MinidumpFileWriter::CopyStringToMDString(const char* str,
unsigned int length,
- TypedMDRVA<MDString> *mdstring) {
+ TypedMDRVA<MDString>* mdstring) {
bool result = true;
uint16_t out[2];
int out_idx = 0;
@@ -205,9 +204,9 @@ bool MinidumpFileWriter::CopyStringToMDString(const char *str,
}
template <typename CharType>
-bool MinidumpFileWriter::WriteStringCore(const CharType *str,
+bool MinidumpFileWriter::WriteStringCore(const CharType* str,
unsigned int length,
- MDLocationDescriptor *location) {
+ MDLocationDescriptor* location) {
assert(str);
assert(location);
// Calculate the mdstring length by either limiting to |length| as passed in
@@ -240,18 +239,18 @@ bool MinidumpFileWriter::WriteStringCore(const CharType *str,
return result;
}
-bool MinidumpFileWriter::WriteString(const wchar_t *str, unsigned int length,
- MDLocationDescriptor *location) {
+bool MinidumpFileWriter::WriteString(const wchar_t* str, unsigned int length,
+ MDLocationDescriptor* location) {
return WriteStringCore(str, length, location);
}
-bool MinidumpFileWriter::WriteString(const char *str, unsigned int length,
- MDLocationDescriptor *location) {
+bool MinidumpFileWriter::WriteString(const char* str, unsigned int length,
+ MDLocationDescriptor* location) {
return WriteStringCore(str, length, location);
}
-bool MinidumpFileWriter::WriteMemory(const void *src, size_t size,
- MDMemoryDescriptor *output) {
+bool MinidumpFileWriter::WriteMemory(const void* src, size_t size,
+ MDMemoryDescriptor* output) {
assert(src);
assert(output);
UntypedMDRVA mem(this);
@@ -307,7 +306,7 @@ MDRVA MinidumpFileWriter::Allocate(size_t size) {
return current_position;
}
-bool MinidumpFileWriter::Copy(MDRVA position, const void *src, ssize_t size) {
+bool MinidumpFileWriter::Copy(MDRVA position, const void* src, ssize_t size) {
assert(src);
assert(size);
assert(file_ != -1);
@@ -340,7 +339,7 @@ bool UntypedMDRVA::Allocate(size_t size) {
return position_ != MinidumpFileWriter::kInvalidMDRVA;
}
-bool UntypedMDRVA::Copy(MDRVA pos, const void *src, size_t size) {
+bool UntypedMDRVA::Copy(MDRVA pos, const void* src, size_t size) {
assert(src);
assert(size);
assert(pos + size <= position_ + size_);
diff --git a/src/client/minidump_file_writer.h b/src/client/minidump_file_writer.h
index ce32b6d0..253a93a9 100644
--- a/src/client/minidump_file_writer.h
+++ b/src/client/minidump_file_writer.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2006, Google Inc.
-// All rights reserved.
+// Copyright 2006 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -77,7 +76,7 @@ public:
// Open |path| as the destination of the minidump data. If |path| already
// exists, then Open() will fail.
// Return true on success, or false on failure.
- bool Open(const char *path);
+ bool Open(const char* path);
// Sets the file descriptor |file| as the destination of the minidump data.
// Can be used as an alternative to Open() when a file descriptor is
@@ -98,20 +97,20 @@ public:
// entire NULL terminated string. Copying will stop at the first NULL.
// |location| the allocated location
// Return true on success, or false on failure
- bool WriteString(const wchar_t *str, unsigned int length,
- MDLocationDescriptor *location);
+ bool WriteString(const wchar_t* str, unsigned int length,
+ MDLocationDescriptor* location);
// Same as above, except with |str| as a UTF-8 string
- bool WriteString(const char *str, unsigned int length,
- MDLocationDescriptor *location);
+ bool WriteString(const char* str, unsigned int length,
+ MDLocationDescriptor* location);
// Write |size| bytes starting at |src| into the current position.
// Return true on success and set |output| to position, or false on failure
- bool WriteMemory(const void *src, size_t size, MDMemoryDescriptor *output);
+ bool WriteMemory(const void* src, size_t size, MDMemoryDescriptor* output);
// Copies |size| bytes from |src| to |position|
// Return true on success, or false on failure
- bool Copy(MDRVA position, const void *src, ssize_t size);
+ bool Copy(MDRVA position, const void* src, ssize_t size);
// Return the current position for writing to the minidump
inline MDRVA position() const { return position_; }
@@ -141,21 +140,21 @@ public:
// variant may need to create a MDString that has more characters than the
// source |str|, whereas the UTF-8 variant may coalesce characters to form
// a single UTF-16 character.
- bool CopyStringToMDString(const wchar_t *str, unsigned int length,
- TypedMDRVA<MDString> *mdstring);
- bool CopyStringToMDString(const char *str, unsigned int length,
- TypedMDRVA<MDString> *mdstring);
+ bool CopyStringToMDString(const wchar_t* str, unsigned int length,
+ TypedMDRVA<MDString>* mdstring);
+ bool CopyStringToMDString(const char* str, unsigned int length,
+ TypedMDRVA<MDString>* mdstring);
// The common templated code for writing a string
template <typename CharType>
- bool WriteStringCore(const CharType *str, unsigned int length,
- MDLocationDescriptor *location);
+ bool WriteStringCore(const CharType* str, unsigned int length,
+ MDLocationDescriptor* location);
};
// Represents an untyped allocated chunk
class UntypedMDRVA {
public:
- explicit UntypedMDRVA(MinidumpFileWriter *writer)
+ explicit UntypedMDRVA(MinidumpFileWriter* writer)
: writer_(writer),
position_(writer->position()),
size_(0) {}
@@ -179,16 +178,16 @@ class UntypedMDRVA {
// Copy |size| bytes starting at |src| into the minidump at |position|
// Return true on success, or false on failure
- bool Copy(MDRVA position, const void *src, size_t size);
+ bool Copy(MDRVA position, const void* src, size_t size);
// Copy |size| bytes from |src| to the current position
- inline bool Copy(const void *src, size_t size) {
+ inline bool Copy(const void* src, size_t size) {
return Copy(position_, src, size);
}
protected:
// Writer we associate with
- MinidumpFileWriter *writer_;
+ MinidumpFileWriter* writer_;
// Position of the start of the data
MDRVA position_;
@@ -206,7 +205,7 @@ template<typename MDType>
class TypedMDRVA : public UntypedMDRVA {
public:
// Constructs an unallocated MDRVA
- explicit TypedMDRVA(MinidumpFileWriter *writer)
+ explicit TypedMDRVA(MinidumpFileWriter* writer)
: UntypedMDRVA(writer),
data_(),
allocation_state_(UNALLOCATED) {}
@@ -220,7 +219,7 @@ class TypedMDRVA : public UntypedMDRVA {
// Address of object data_ of MDType. This is not declared const as the
// typical usage will be to access the underlying |data_| object as to
// alter its contents.
- MDType *get() { return &data_; }
+ MDType* get() { return &data_; }
// Allocates minidump_size<MDType>::size() bytes.
// Must not call more than once.
@@ -245,12 +244,12 @@ class TypedMDRVA : public UntypedMDRVA {
// Copy |item| to |index|
// Must have been allocated using AllocateArray().
// Return true on success, or false on failure
- bool CopyIndex(unsigned int index, MDType *item);
+ bool CopyIndex(unsigned int index, MDType* item);
// Copy |size| bytes starting at |str| to |index|
// Must have been allocated using AllocateObjectAndArray().
// Return true on success, or false on failure
- bool CopyIndexAfterObject(unsigned int index, const void *src, size_t size);
+ bool CopyIndexAfterObject(unsigned int index, const void* src, size_t size);
// Write data_
bool Flush();
diff --git a/src/client/minidump_file_writer_unittest.cc b/src/client/minidump_file_writer_unittest.cc
index 256e3371..bb3a0269 100644
--- a/src/client/minidump_file_writer_unittest.cc
+++ b/src/client/minidump_file_writer_unittest.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2006, Google Inc.
-// All rights reserved.
+// Copyright 2006 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -70,16 +69,16 @@ typedef struct {
ArrayStructure array[0];
} ObjectAndArrayStructure;
-static bool WriteFile(const char *path) {
+static bool WriteFile(const char* path) {
MinidumpFileWriter writer;
if (writer.Open(path)) {
// Test a single structure
google_breakpad::TypedMDRVA<StringStructure> strings(&writer);
ASSERT_TRUE(strings.Allocate());
strings.get()->integer_value = 0xBEEF;
- const char *first = "First String";
+ const char* first = "First String";
ASSERT_TRUE(writer.WriteString(first, 0, &strings.get()->first_string));
- const wchar_t *second = L"Second String";
+ const wchar_t* second = L"Second String";
ASSERT_TRUE(writer.WriteString(second, 0, &strings.get()->second_string));
// Test an array structure
@@ -111,7 +110,7 @@ static bool WriteFile(const char *path) {
return writer.Close();
}
-static bool CompareFile(const char *path) {
+static bool CompareFile(const char* path) {
unsigned long expected[] = {
#if defined(__BIG_ENDIAN__)
0x0000beef, 0x0000001e, 0x00000018, 0x00000020, 0x00000038, 0x00000000,
@@ -146,13 +145,14 @@ static bool CompareFile(const char *path) {
};
size_t expected_byte_count = sizeof(expected);
int fd = open(path, O_RDONLY, 0600);
- void *buffer = malloc(expected_byte_count);
+ void* buffer = malloc(expected_byte_count);
ASSERT_NE(fd, -1);
ASSERT_TRUE(buffer);
ASSERT_EQ(read(fd, buffer, expected_byte_count),
static_cast<ssize_t>(expected_byte_count));
- char *b1, *b2;
+ char* b1;
+ char* b2;
b1 = reinterpret_cast<char*>(buffer);
b2 = reinterpret_cast<char*>(expected);
while (*b1 == *b2) {
@@ -167,13 +167,13 @@ static bool CompareFile(const char *path) {
}
static bool RunTests() {
- const char *path = "/tmp/minidump_file_writer_unittest.dmp";
+ const char* path = "/tmp/minidump_file_writer_unittest.dmp";
ASSERT_TRUE(WriteFile(path));
ASSERT_TRUE(CompareFile(path));
unlink(path);
return true;
}
-extern "C" int main(int argc, const char *argv[]) {
+extern "C" int main(int argc, const char* argv[]) {
return RunTests() ? 0 : 1;
}
diff --git a/src/client/solaris/handler/Makefile b/src/client/solaris/handler/Makefile
index 6da9464e..b22fe561 100644
--- a/src/client/solaris/handler/Makefile
+++ b/src/client/solaris/handler/Makefile
@@ -1,5 +1,4 @@
-# Copyright (c) 2007, Google Inc.
-# All rights reserved.
+# Copyright 2007 Google LLC
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
# copyright notice, this list of conditions and the following disclaimer
# in the documentation and/or other materials provided with the
# distribution.
-# * Neither the name of Google Inc. nor the names of its
+# * Neither the name of Google LLC nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
diff --git a/src/client/solaris/handler/exception_handler.cc b/src/client/solaris/handler/exception_handler.cc
index 7fc8d255..b7b702ac 100644
--- a/src/client/solaris/handler/exception_handler.cc
+++ b/src/client/solaris/handler/exception_handler.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2007, Google Inc.
-// All rights reserved.
+// Copyright 2007 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -54,15 +53,15 @@ static const int kSigTable[] = {
SIGBUS
};
-std::vector<ExceptionHandler*> *ExceptionHandler::handler_stack_ = NULL;
+std::vector<ExceptionHandler*>* ExceptionHandler::handler_stack_ = NULL;
int ExceptionHandler::handler_stack_index_ = 0;
pthread_mutex_t ExceptionHandler::handler_stack_mutex_ =
PTHREAD_MUTEX_INITIALIZER;
-ExceptionHandler::ExceptionHandler(const string &dump_path,
+ExceptionHandler::ExceptionHandler(const string& dump_path,
FilterCallback filter,
MinidumpCallback callback,
- void *callback_context,
+ void* callback_context,
bool install_handler)
: filter_(filter),
callback_(callback),
@@ -79,7 +78,7 @@ ExceptionHandler::ExceptionHandler(const string &dump_path,
pthread_mutex_lock(&handler_stack_mutex_);
if (handler_stack_ == NULL)
- handler_stack_ = new std::vector<ExceptionHandler *>;
+ handler_stack_ = new std::vector<ExceptionHandler*>;
handler_stack_->push_back(this);
pthread_mutex_unlock(&handler_stack_mutex_);
}
@@ -92,7 +91,7 @@ ExceptionHandler::~ExceptionHandler() {
handler_stack_->pop_back();
} else {
print_message1(2, "warning: removing Breakpad handler out of order\n");
- for (std::vector<ExceptionHandler *>::iterator iterator =
+ for (std::vector<ExceptionHandler*>::iterator iterator =
handler_stack_->begin();
iterator != handler_stack_->end();
++iterator) {
@@ -116,9 +115,9 @@ bool ExceptionHandler::WriteMinidump() {
}
// static
-bool ExceptionHandler::WriteMinidump(const string &dump_path,
+bool ExceptionHandler::WriteMinidump(const string& dump_path,
MinidumpCallback callback,
- void *callback_context) {
+ void* callback_context) {
ExceptionHandler handler(dump_path, NULL, callback,
callback_context, false);
return handler.InternalWriteMinidump(0, 0, NULL);
@@ -166,7 +165,7 @@ void ExceptionHandler::TeardownAllHandlers() {
// static
void ExceptionHandler::HandleException(int signo) {
-//void ExceptionHandler::HandleException(int signo, siginfo_t *sip, ucontext_t *sig_ctx) {
+//void ExceptionHandler::HandleException(int signo, siginfo_t* sip, ucontext_t* sig_ctx) {
// The context information about the signal is put on the stack of
// the signal handler frame as value parameter. For some reasons, the
// prototype of the handler doesn't declare this information as parameter, we
@@ -181,14 +180,14 @@ void ExceptionHandler::HandleException(int signo) {
uintptr_t current_ebp = (uintptr_t)_getfp();
pthread_mutex_lock(&handler_stack_mutex_);
- ExceptionHandler *current_handler =
+ ExceptionHandler* current_handler =
handler_stack_->at(handler_stack_->size() - ++handler_stack_index_);
pthread_mutex_unlock(&handler_stack_mutex_);
// Restore original handler.
current_handler->TeardownHandler(signo);
- ucontext_t *sig_ctx = NULL;
+ ucontext_t* sig_ctx = NULL;
if (current_handler->InternalWriteMinidump(signo, current_ebp, &sig_ctx)) {
// if (current_handler->InternalWriteMinidump(signo, &sig_ctx)) {
// Fully handled this exception, safe to exit.
@@ -218,7 +217,7 @@ void ExceptionHandler::HandleException(int signo) {
bool ExceptionHandler::InternalWriteMinidump(int signo,
uintptr_t sighandler_ebp,
- ucontext_t **sig_ctx) {
+ ucontext_t** sig_ctx) {
if (filter_ && !filter_(callback_context_))
return false;
diff --git a/src/client/solaris/handler/exception_handler.h b/src/client/solaris/handler/exception_handler.h
index 4d72485f..04d140f0 100644
--- a/src/client/solaris/handler/exception_handler.h
+++ b/src/client/solaris/handler/exception_handler.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2007, Google Inc.
-// All rights reserved.
+// Copyright 2007 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -79,7 +78,7 @@ class ExceptionHandler {
// attempting to write a minidump. If a FilterCallback returns false,
// Breakpad will immediately report the exception as unhandled without
// writing a minidump, allowing another handler the opportunity to handle it.
- typedef bool (*FilterCallback)(void *context);
+ typedef bool (*FilterCallback)(void* context);
// A callback function to run after the minidump has been written.
// minidump_id is a unique id for the dump, so the minidump
@@ -97,9 +96,9 @@ class ExceptionHandler {
// should normally return the value of |succeeded|, or when they wish to
// not report an exception of handled, false. Callbacks will rarely want to
// return true directly (unless |succeeded| is true).
- typedef bool (*MinidumpCallback)(const char *dump_path,
- const char *minidump_id,
- void *context,
+ typedef bool (*MinidumpCallback)(const char* dump_path,
+ const char* minidump_id,
+ void* context,
bool succeeded);
// Creates a new ExceptionHandler instance to handle writing minidumps.
@@ -110,15 +109,15 @@ class ExceptionHandler {
// If install_handler is true, then a minidump will be written whenever
// an unhandled exception occurs. If it is false, minidumps will only
// be written when WriteMinidump is called.
- ExceptionHandler(const string &dump_path,
+ ExceptionHandler(const string& dump_path,
FilterCallback filter, MinidumpCallback callback,
- void *callback_context,
+ void* callback_context,
bool install_handler);
~ExceptionHandler();
// Get and Set the minidump path.
string dump_path() const { return dump_path_; }
- void set_dump_path(const string &dump_path) {
+ void set_dump_path(const string& dump_path) {
dump_path_ = dump_path;
dump_path_c_ = dump_path_.c_str();
}
@@ -129,9 +128,9 @@ class ExceptionHandler {
// Convenience form of WriteMinidump which does not require an
// ExceptionHandler instance.
- static bool WriteMinidump(const string &dump_path,
+ static bool WriteMinidump(const string& dump_path,
MinidumpCallback callback,
- void *callback_context);
+ void* callback_context);
private:
// Setup crash handler.
@@ -144,7 +143,7 @@ class ExceptionHandler {
void TeardownAllHandlers();
// Runs the main loop for the exception handler thread.
- static void* ExceptionHandlerThreadMain(void *lpParameter);
+ static void* ExceptionHandlerThreadMain(void* lpParameter);
// Signal handler.
static void HandleException(int signo);
@@ -157,20 +156,20 @@ class ExceptionHandler {
// for the second and third parameters if you are not calling
// this from a signal handler.
bool InternalWriteMinidump(int signo, uintptr_t sighandler_ebp,
- ucontext_t **sig_ctx);
+ ucontext_t** sig_ctx);
private:
// The callbacks before and after writing the dump file.
FilterCallback filter_;
MinidumpCallback callback_;
- void *callback_context_;
+ void* callback_context_;
// The directory in which a minidump will be written, set by the dump_path
// argument to the constructor, or set_dump_path.
string dump_path_;
// C style dump path. Keep this when setting dump path, since calling
// c_str() of std::string when crashing may not be safe.
- const char *dump_path_c_;
+ const char* dump_path_c_;
// True if the ExceptionHandler installed an unhandled exception filter
// when created (with an install_handler parameter set to true).
@@ -183,7 +182,7 @@ class ExceptionHandler {
// The global exception handler stack. This is need becuase there may exist
// multiple ExceptionHandler instances in a process. Each will have itself
// registered in this stack.
- static std::vector<ExceptionHandler *> *handler_stack_;
+ static std::vector<ExceptionHandler*>* handler_stack_;
// The index of the handler that should handle the next exception.
static int handler_stack_index_;
static pthread_mutex_t handler_stack_mutex_;
@@ -192,8 +191,8 @@ class ExceptionHandler {
MinidumpGenerator minidump_generator_;
// disallow copy ctor and operator=
- explicit ExceptionHandler(const ExceptionHandler &);
- void operator=(const ExceptionHandler &);
+ explicit ExceptionHandler(const ExceptionHandler&);
+ void operator=(const ExceptionHandler&);
};
} // namespace google_breakpad
diff --git a/src/client/solaris/handler/exception_handler_test.cc b/src/client/solaris/handler/exception_handler_test.cc
index 6bb8e18d..a84f2df1 100644
--- a/src/client/solaris/handler/exception_handler_test.cc
+++ b/src/client/solaris/handler/exception_handler_test.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2007, Google Inc.
-// All rights reserved.
+// Copyright 2007 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -49,7 +48,7 @@ static int foo2(int arg) {
// Stack variable, used for debugging stack dumps.
int c = 0xcccccccc;
fprintf(stderr, "Thread trying to crash: %x\n", getpid());
- c = *reinterpret_cast<int *>(0x5);
+ c = *reinterpret_cast<int*>(0x5);
return c;
}
@@ -60,7 +59,7 @@ static int foo(int arg) {
return b;
}
-static void *thread_crash(void *) {
+static void* thread_crash(void*) {
// Stack variable, used for debugging stack dumps.
int a = 0xaaaaaaaa;
sleep(3);
@@ -69,7 +68,7 @@ static void *thread_crash(void *) {
return NULL;
}
-static void *thread_main(void *) {
+static void* thread_main(void*) {
while (!should_exit)
sleep(1);
return NULL;
@@ -91,9 +90,9 @@ static void CreateThread(int num) {
}
// Callback when minidump written.
-static bool MinidumpCallback(const char *dump_path,
- const char *minidump_id,
- void *context,
+static bool MinidumpCallback(const char* dump_path,
+ const char* minidump_id,
+ void* context,
bool succeeded) {
int index = reinterpret_cast<int>(context);
if (index == 0) {
@@ -104,7 +103,7 @@ static bool MinidumpCallback(const char *dump_path,
return false;
}
-int main(int argc, char *argv[]) {
+int main(int argc, char* argv[]) {
int handler_index = 1;
ExceptionHandler handler_ignore(".", NULL, MinidumpCallback,
(void*)handler_index, true);
diff --git a/src/client/solaris/handler/minidump_generator.cc b/src/client/solaris/handler/minidump_generator.cc
index 7485025f..8f2f6ee2 100644
--- a/src/client/solaris/handler/minidump_generator.cc
+++ b/src/client/solaris/handler/minidump_generator.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2007, Google Inc.
-// All rights reserved.
+// Copyright 2007 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -47,10 +46,11 @@
namespace {
using namespace google_breakpad;
+using namespace google_breakpad::elf::FileID;
// Argument for the writer function.
struct WriterArgument {
- MinidumpFileWriter *minidump_writer;
+ MinidumpFileWriter* minidump_writer;
// Pid of the lwp who called WriteMinidumpToFile
int requester_pid;
@@ -73,15 +73,15 @@ struct WriterArgument {
// User context when crash happens. Can be NULL if this is a requested dump.
// This is actually an out parameter, but it will be filled in at the start
// of the writer LWP.
- ucontext_t *sig_ctx;
+ ucontext_t* sig_ctx;
// Used to get information about the lwps.
- SolarisLwp *lwp_lister;
+ SolarisLwp* lwp_lister;
};
// Holding context information for the callback of finding the crashing lwp.
struct FindCrashLwpContext {
- const SolarisLwp *lwp_lister;
+ const SolarisLwp* lwp_lister;
uintptr_t crashing_stack_bottom;
int crashing_lwpid;
@@ -96,11 +96,11 @@ struct FindCrashLwpContext {
// It will compare the stack bottom of the provided lwp with the stack
// bottom of the crashed lwp, it they are eqaul, this lwp is the one
// who crashed.
-bool IsLwpCrashedCallback(lwpstatus_t *lsp, void *context) {
- FindCrashLwpContext *crashing_context =
- static_cast<FindCrashLwpContext *>(context);
- const SolarisLwp *lwp_lister = crashing_context->lwp_lister;
- const prgregset_t *gregs = &(lsp->pr_reg);
+bool IsLwpCrashedCallback(lwpstatus_t* lsp, void* context) {
+ FindCrashLwpContext* crashing_context =
+ static_cast<FindCrashLwpContext*>(context);
+ const SolarisLwp* lwp_lister = crashing_context->lwp_lister;
+ const prgregset_t* gregs = &(lsp->pr_reg);
#if TARGET_CPU_SPARC
uintptr_t last_ebp = (*gregs)[R_FP];
#elif TARGET_CPU_X86
@@ -121,7 +121,7 @@ bool IsLwpCrashedCallback(lwpstatus_t *lsp, void *context) {
// This is done based on stack bottom comparing.
int FindCrashingLwp(uintptr_t crashing_stack_bottom,
int requester_pid,
- const SolarisLwp *lwp_lister) {
+ const SolarisLwp* lwp_lister) {
FindCrashLwpContext context;
context.lwp_lister = lwp_lister;
context.crashing_stack_bottom = crashing_stack_bottom;
@@ -131,17 +131,17 @@ int FindCrashingLwp(uintptr_t crashing_stack_bottom,
return context.crashing_lwpid;
}
-bool WriteLwpStack(const SolarisLwp *lwp_lister,
+bool WriteLwpStack(const SolarisLwp* lwp_lister,
uintptr_t last_esp,
- UntypedMDRVA *memory,
- MDMemoryDescriptor *loc) {
+ UntypedMDRVA* memory,
+ MDMemoryDescriptor* loc) {
uintptr_t stack_bottom = lwp_lister->GetLwpStackBottom(last_esp);
if (stack_bottom >= last_esp) {
int size = stack_bottom - last_esp;
if (size > 0) {
if (!memory->Allocate(size))
return false;
- memory->Copy(reinterpret_cast<void *>(last_esp), size);
+ memory->Copy(reinterpret_cast<void*>(last_esp), size);
loc->start_of_memory_range = last_esp;
loc->memory = memory->location();
}
@@ -151,7 +151,7 @@ bool WriteLwpStack(const SolarisLwp *lwp_lister,
}
#if TARGET_CPU_SPARC
-bool WriteContext(MDRawContextSPARC *context, ucontext_t *sig_ctx) {
+bool WriteContext(MDRawContextSPARC* context, ucontext_t* sig_ctx) {
assert(sig_ctx != NULL);
int* regs = sig_ctx->uc_mcontext.gregs;
context->context_flags = MD_CONTEXT_SPARC_FULL;
@@ -170,13 +170,13 @@ bool WriteContext(MDRawContextSPARC *context, ucontext_t *sig_ctx) {
for ( int i = 1 ; i < 16; ++i ) {
context->g_r[i] = (uintptr_t)(sig_ctx->uc_mcontext.gregs[i + 3]);
}
- context->g_r[30] = (uintptr_t)(((struct frame *)context->g_r[14])->fr_savfp);
+ context->g_r[30] = (uintptr_t)(((struct frame*)context->g_r[14])->fr_savfp);
return true;
}
-bool WriteContext(MDRawContextSPARC *context, prgregset_t regs,
- prfpregset_t *fp_regs) {
+bool WriteContext(MDRawContextSPARC* context, prgregset_t regs,
+ prfpregset_t* fp_regs) {
if (!context || !regs)
return false;
@@ -195,8 +195,8 @@ bool WriteContext(MDRawContextSPARC *context, prgregset_t regs,
return true;
}
#elif TARGET_CPU_X86
-bool WriteContext(MDRawContextX86 *context, prgregset_t regs,
- prfpregset_t *fp_regs) {
+bool WriteContext(MDRawContextX86* context, prgregset_t regs,
+ prfpregset_t* fp_regs) {
if (!context || !regs)
return false;
@@ -228,10 +228,10 @@ bool WriteContext(MDRawContextX86 *context, prgregset_t regs,
// signal. This makes the current stack not reliable, and our stack walker
// won't figure out the whole call stack for this. So we write the stack at the
// time of the crash into the minidump file, not the current stack.
-bool WriteCrashedLwpStream(MinidumpFileWriter *minidump_writer,
- const WriterArgument *writer_args,
- const lwpstatus_t *lsp,
- MDRawThread *lwp) {
+bool WriteCrashedLwpStream(MinidumpFileWriter* minidump_writer,
+ const WriterArgument* writer_args,
+ const lwpstatus_t* lsp,
+ MDRawThread* lwp) {
assert(writer_args->sig_ctx != NULL);
lwp->thread_id = lsp->pr_lwpid;
@@ -264,16 +264,16 @@ bool WriteCrashedLwpStream(MinidumpFileWriter *minidump_writer,
lwp->thread_context = context.location();
memset(context.get(), 0, sizeof(MDRawContextX86));
return WriteContext(context.get(),
- (int *)&writer_args->sig_ctx->uc_mcontext.gregs,
+ (int*)&writer_args->sig_ctx->uc_mcontext.gregs,
&writer_args->sig_ctx->uc_mcontext.fpregs);
#endif
}
-bool WriteLwpStream(MinidumpFileWriter *minidump_writer,
- const SolarisLwp *lwp_lister,
- const lwpstatus_t *lsp, MDRawThread *lwp) {
+bool WriteLwpStream(MinidumpFileWriter* minidump_writer,
+ const SolarisLwp* lwp_lister,
+ const lwpstatus_t* lsp, MDRawThread* lwp) {
prfpregset_t fp_regs = lsp->pr_fpreg;
- const prgregset_t *gregs = &(lsp->pr_reg);
+ const prgregset_t* gregs = &(lsp->pr_reg);
UntypedMDRVA memory(minidump_writer);
#if TARGET_CPU_SPARC
if (!WriteLwpStack(lwp_lister,
@@ -306,10 +306,10 @@ bool WriteLwpStream(MinidumpFileWriter *minidump_writer,
lwp->thread_context = context.location();
memset(context.get(), 0, sizeof(MDRawContextX86));
#endif /* TARGET_CPU_XXX */
- return WriteContext(context.get(), (int *)gregs, &fp_regs);
+ return WriteContext(context.get(), (int*)gregs, &fp_regs);
}
-bool WriteCPUInformation(MDRawSystemInfo *sys_info) {
+bool WriteCPUInformation(MDRawSystemInfo* sys_info) {
struct utsname uts;
char *major, *minor, *build;
@@ -337,8 +337,8 @@ bool WriteCPUInformation(MDRawSystemInfo *sys_info) {
return true;
}
-bool WriteOSInformation(MinidumpFileWriter *minidump_writer,
- MDRawSystemInfo *sys_info) {
+bool WriteOSInformation(MinidumpFileWriter* minidump_writer,
+ MDRawSystemInfo* sys_info) {
sys_info->platform_id = MD_OS_SOLARIS;
struct utsname uts;
@@ -346,7 +346,7 @@ bool WriteOSInformation(MinidumpFileWriter *minidump_writer,
char os_version[512];
size_t space_left = sizeof(os_version);
memset(os_version, 0, space_left);
- const char *os_info_table[] = {
+ const char* os_info_table[] = {
uts.sysname,
uts.release,
uts.version,
@@ -354,7 +354,7 @@ bool WriteOSInformation(MinidumpFileWriter *minidump_writer,
"OpenSolaris",
NULL
};
- for (const char **cur_os_info = os_info_table;
+ for (const char** cur_os_info = os_info_table;
*cur_os_info != NULL;
++cur_os_info) {
if (cur_os_info != os_info_table && space_left > 1) {
@@ -379,21 +379,21 @@ bool WriteOSInformation(MinidumpFileWriter *minidump_writer,
// Callback context for get writting lwp information.
struct LwpInfoCallbackCtx {
- MinidumpFileWriter *minidump_writer;
- const WriterArgument *writer_args;
- TypedMDRVA<MDRawThreadList> *list;
+ MinidumpFileWriter* minidump_writer;
+ const WriterArgument* writer_args;
+ TypedMDRVA<MDRawThreadList>* list;
int lwp_index;
};
-bool LwpInformationCallback(lwpstatus_t *lsp, void *context) {
+bool LwpInformationCallback(lwpstatus_t* lsp, void* context) {
bool success = true;
- LwpInfoCallbackCtx *callback_context =
- static_cast<LwpInfoCallbackCtx *>(context);
+ LwpInfoCallbackCtx* callback_context =
+ static_cast<LwpInfoCallbackCtx*>(context);
// The current lwp is the one to handle the crash. Ignore it.
if (lsp->pr_lwpid != pthread_self()) {
- LwpInfoCallbackCtx *callback_context =
- static_cast<LwpInfoCallbackCtx *>(context);
+ LwpInfoCallbackCtx* callback_context =
+ static_cast<LwpInfoCallbackCtx*>(context);
MDRawThread lwp;
memset(&lwp, 0, sizeof(MDRawThread));
@@ -417,11 +417,11 @@ bool LwpInformationCallback(lwpstatus_t *lsp, void *context) {
return success;
}
-bool WriteLwpListStream(MinidumpFileWriter *minidump_writer,
- const WriterArgument *writer_args,
- MDRawDirectory *dir) {
+bool WriteLwpListStream(MinidumpFileWriter* minidump_writer,
+ const WriterArgument* writer_args,
+ MDRawDirectory* dir) {
// Get the lwp information.
- const SolarisLwp *lwp_lister = writer_args->lwp_lister;
+ const SolarisLwp* lwp_lister = writer_args->lwp_lister;
int lwp_count = lwp_lister->GetLwpCount();
if (lwp_count < 0)
return false;
@@ -444,14 +444,14 @@ bool WriteLwpListStream(MinidumpFileWriter *minidump_writer,
return written == lwp_count;
}
-bool WriteCVRecord(MinidumpFileWriter *minidump_writer,
- MDRawModule *module,
- const char *module_path,
- char *realname) {
+bool WriteCVRecord(MinidumpFileWriter* minidump_writer,
+ MDRawModule* module,
+ const char* module_path,
+ char* realname) {
TypedMDRVA<MDCVInfoPDB70> cv(minidump_writer);
char path[PATH_MAX];
- const char *module_name = module_path ? module_path : "<Unknown>";
+ const char* module_name = module_path ? module_path : "<Unknown>";
snprintf(path, sizeof(path), "/proc/self/object/%s", module_name);
size_t module_name_length = strlen(realname);
@@ -461,7 +461,7 @@ bool WriteCVRecord(MinidumpFileWriter *minidump_writer,
return false;
module->cv_record = cv.location();
- MDCVInfoPDB70 *cv_ptr = cv.get();
+ MDCVInfoPDB70* cv_ptr = cv.get();
memset(cv_ptr, 0, sizeof(MDCVInfoPDB70));
cv_ptr->cv_signature = MD_CVINFOPDB70_SIGNATURE;
cv_ptr->age = 0;
@@ -489,15 +489,15 @@ bool WriteCVRecord(MinidumpFileWriter *minidump_writer,
}
struct ModuleInfoCallbackCtx {
- MinidumpFileWriter *minidump_writer;
- const WriterArgument *writer_args;
- TypedMDRVA<MDRawModuleList> *list;
+ MinidumpFileWriter* minidump_writer;
+ const WriterArgument* writer_args;
+ TypedMDRVA<MDRawModuleList>* list;
int module_index;
};
-bool ModuleInfoCallback(const ModuleInfo &module_info, void *context) {
- ModuleInfoCallbackCtx *callback_context =
- static_cast<ModuleInfoCallbackCtx *>(context);
+bool ModuleInfoCallback(const ModuleInfo& module_info, void* context) {
+ ModuleInfoCallbackCtx* callback_context =
+ static_cast<ModuleInfoCallbackCtx*>(context);
// Skip those modules without name, or those that are not modules.
if (strlen(module_info.name) == 0)
return true;
@@ -507,7 +507,7 @@ bool ModuleInfoCallback(const ModuleInfo &module_info, void *context) {
MDLocationDescriptor loc;
char path[PATH_MAX];
char buf[PATH_MAX];
- char *realname;
+ char* realname;
int count;
snprintf(path, sizeof (path), "/proc/self/path/%s", module_info.name);
@@ -535,9 +535,9 @@ bool ModuleInfoCallback(const ModuleInfo &module_info, void *context) {
return true;
}
-bool WriteModuleListStream(MinidumpFileWriter *minidump_writer,
- const WriterArgument *writer_args,
- MDRawDirectory *dir) {
+bool WriteModuleListStream(MinidumpFileWriter* minidump_writer,
+ const WriterArgument* writer_args,
+ MDRawDirectory* dir) {
TypedMDRVA<MDRawModuleList> list(minidump_writer);
int module_count = writer_args->lwp_lister->GetModuleCount();
@@ -558,9 +558,9 @@ bool WriteModuleListStream(MinidumpFileWriter *minidump_writer,
return writer_args->lwp_lister->ListModules(&callback) == module_count;
}
-bool WriteSystemInfoStream(MinidumpFileWriter *minidump_writer,
- const WriterArgument *writer_args,
- MDRawDirectory *dir) {
+bool WriteSystemInfoStream(MinidumpFileWriter* minidump_writer,
+ const WriterArgument* writer_args,
+ MDRawDirectory* dir) {
TypedMDRVA<MDRawSystemInfo> sys_info(minidump_writer);
if (!sys_info.Allocate())
@@ -573,9 +573,9 @@ bool WriteSystemInfoStream(MinidumpFileWriter *minidump_writer,
WriteOSInformation(minidump_writer, sys_info.get());
}
-bool WriteExceptionStream(MinidumpFileWriter *minidump_writer,
- const WriterArgument *writer_args,
- MDRawDirectory *dir) {
+bool WriteExceptionStream(MinidumpFileWriter* minidump_writer,
+ const WriterArgument* writer_args,
+ MDRawDirectory* dir) {
// This happenes when this is not a crash, but a requested dump.
if (writer_args->sig_ctx == NULL)
return false;
@@ -620,14 +620,14 @@ bool WriteExceptionStream(MinidumpFileWriter *minidump_writer,
exception.get()->thread_context = context.location();
memset(context.get(), 0, sizeof(MDRawContextX86));
return WriteContext(context.get(),
- (int *)&writer_args->sig_ctx->uc_mcontext.gregs,
+ (int*)&writer_args->sig_ctx->uc_mcontext.gregs,
NULL);
#endif
}
-bool WriteMiscInfoStream(MinidumpFileWriter *minidump_writer,
- const WriterArgument *writer_args,
- MDRawDirectory *dir) {
+bool WriteMiscInfoStream(MinidumpFileWriter* minidump_writer,
+ const WriterArgument* writer_args,
+ MDRawDirectory* dir) {
TypedMDRVA<MDRawMiscInfo> info(minidump_writer);
if (!info.Allocate())
@@ -642,9 +642,9 @@ bool WriteMiscInfoStream(MinidumpFileWriter *minidump_writer,
return true;
}
-bool WriteBreakpadInfoStream(MinidumpFileWriter *minidump_writer,
- const WriterArgument *writer_args,
- MDRawDirectory *dir) {
+bool WriteBreakpadInfoStream(MinidumpFileWriter* minidump_writer,
+ const WriterArgument* writer_args,
+ MDRawDirectory* dir) {
TypedMDRVA<MDRawBreakpadInfo> info(minidump_writer);
if (!info.Allocate())
@@ -662,16 +662,16 @@ bool WriteBreakpadInfoStream(MinidumpFileWriter *minidump_writer,
class AutoLwpResumer {
public:
- AutoLwpResumer(SolarisLwp *lwp) : lwp_(lwp) {}
+ AutoLwpResumer(SolarisLwp* lwp) : lwp_(lwp) {}
~AutoLwpResumer() { lwp_->ControlAllLwps(false); }
private:
- SolarisLwp *lwp_;
+ SolarisLwp* lwp_;
};
// Prototype of writer functions.
-typedef bool (*WriteStreamFN)(MinidumpFileWriter *,
- const WriterArgument *,
- MDRawDirectory *);
+typedef bool (*WriteStreamFN)(MinidumpFileWriter*,
+ const WriterArgument*,
+ MDRawDirectory*);
// Function table to writer a full minidump.
const WriteStreamFN writers[] = {
@@ -684,9 +684,9 @@ const WriteStreamFN writers[] = {
};
// Will call each writer function in the writers table.
-//void* MinidumpGenerator::Write(void *argument) {
-void* Write(void *argument) {
- WriterArgument *writer_args = static_cast<WriterArgument *>(argument);
+//void* MinidumpGenerator::Write(void* argument) {
+void* Write(void* argument) {
+ WriterArgument* writer_args = static_cast<WriterArgument*>(argument);
if (!writer_args->lwp_lister->ControlAllLwps(true))
return NULL;
@@ -712,7 +712,7 @@ void* Write(void *argument) {
writer_args->crashed_lwpid = crashed_lwpid;
}
- MinidumpFileWriter *minidump_writer = writer_args->minidump_writer;
+ MinidumpFileWriter* minidump_writer = writer_args->minidump_writer;
TypedMDRVA<MDRawHeader> header(minidump_writer);
TypedMDRVA<MDRawDirectory> dir(minidump_writer);
if (!header.Allocate())
@@ -750,10 +750,10 @@ MinidumpGenerator::~MinidumpGenerator() {
// Write minidump into file.
// It runs in a different thread from the crashing thread.
-bool MinidumpGenerator::WriteMinidumpToFile(const char *file_pathname,
+bool MinidumpGenerator::WriteMinidumpToFile(const char* file_pathname,
int signo,
uintptr_t sighandler_ebp,
- ucontext_t **sig_ctx) const {
+ ucontext_t** sig_ctx) const {
// The exception handler thread.
pthread_t handler_thread;
@@ -775,7 +775,7 @@ bool MinidumpGenerator::WriteMinidumpToFile(const char *file_pathname,
argument.sighandler_ebp = sighandler_ebp;
argument.sig_ctx = NULL;
- pthread_create(&handler_thread, NULL, Write, (void *)&argument);
+ pthread_create(&handler_thread, NULL, Write, (void*)&argument);
pthread_join(handler_thread, NULL);
return true;
}
diff --git a/src/client/solaris/handler/minidump_generator.h b/src/client/solaris/handler/minidump_generator.h
index 882f9e1d..7d2adbce 100644
--- a/src/client/solaris/handler/minidump_generator.h
+++ b/src/client/solaris/handler/minidump_generator.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2007, Google Inc.
-// All rights reserved.
+// Copyright 2007 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -48,10 +47,10 @@ namespace google_breakpad {
//
class MinidumpGenerator {
// Callback run for writing lwp information in the process.
- friend bool LwpInformationCallback(lwpstatus_t *lsp, void *context);
+ friend bool LwpInformationCallback(lwpstatus_t* lsp, void* context);
// Callback run for writing module information in the process.
- friend bool ModuleInfoCallback(const ModuleInfo &module_info, void *context);
+ friend bool ModuleInfoCallback(const ModuleInfo& module_info, void* context);
public:
MinidumpGenerator();
@@ -59,10 +58,10 @@ class MinidumpGenerator {
~MinidumpGenerator();
// Write minidump.
- bool WriteMinidumpToFile(const char *file_pathname,
+ bool WriteMinidumpToFile(const char* file_pathname,
int signo,
uintptr_t sighandler_ebp,
- ucontext_t **sig_ctx) const;
+ ucontext_t** sig_ctx) const;
};
} // namespace google_breakpad
diff --git a/src/client/solaris/handler/minidump_test.cc b/src/client/solaris/handler/minidump_test.cc
index 33302d86..00f8d9a5 100644
--- a/src/client/solaris/handler/minidump_test.cc
+++ b/src/client/solaris/handler/minidump_test.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2007, Google Inc.
-// All rights reserved.
+// Copyright 2007 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -40,7 +39,7 @@ using google_breakpad::MinidumpGenerator;
static bool doneWritingReport = false;
-static void *Reporter(void *) {
+static void* Reporter(void*) {
char buffer[PATH_MAX];
MinidumpGenerator md;
diff --git a/src/client/solaris/handler/solaris_lwp.cc b/src/client/solaris/handler/solaris_lwp.cc
index 0148997a..d707a5b3 100644
--- a/src/client/solaris/handler/solaris_lwp.cc
+++ b/src/client/solaris/handler/solaris_lwp.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2007, Google Inc.
-// All rights reserved.
+// Copyright 2007 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -69,10 +68,10 @@ struct AddressValidatingContext {
};
// Convert from string to int.
-static bool LocalAtoi(char *s, int *r) {
+static bool LocalAtoi(char* s, int* r) {
assert(s != NULL);
assert(r != NULL);
- char *endptr = NULL;
+ char* endptr = NULL;
int ret = strtol(s, &endptr, 10);
if (endptr == s)
return false;
@@ -82,10 +81,10 @@ static bool LocalAtoi(char *s, int *r) {
// Callback invoked for each mapped module.
// It uses the module's adderss range to validate the address.
-static bool AddressNotInModuleCallback(const ModuleInfo &module_info,
- void *context) {
- AddressValidatingContext *addr =
- reinterpret_cast<AddressValidatingContext *>(context);
+static bool AddressNotInModuleCallback(const ModuleInfo& module_info,
+ void* context) {
+ AddressValidatingContext* addr =
+ reinterpret_cast<AddressValidatingContext*>(context);
if (addr->is_mapped = ((module_info.start_addr > 0) &&
(addr->address >= module_info.start_addr) &&
(addr->address <= module_info.start_addr +
@@ -97,16 +96,16 @@ static bool AddressNotInModuleCallback(const ModuleInfo &module_info,
}
static int IterateLwpAll(int pid,
- CallbackParam<LwpidCallback> *callback_param) {
+ CallbackParam<LwpidCallback>* callback_param) {
char lwp_path[40];
- DIR *dir;
+ DIR* dir;
int count = 0;
snprintf(lwp_path, sizeof (lwp_path), "/proc/%d/lwp", (int)pid);
if ((dir = opendir(lwp_path)) == NULL)
return -1;
- struct dirent *entry = NULL;
+ struct dirent* entry = NULL;
while ((entry = readdir(dir)) != NULL) {
if ((strcmp(entry->d_name, ".") != 0) &&
(strcmp(entry->d_name, "..") != 0)) {
@@ -128,22 +127,22 @@ static int IterateLwpAll(int pid,
}
#if defined(__i386) && !defined(NO_FRAME_POINTER)
-void *GetNextFrame(void **last_ebp) {
- void *sp = *last_ebp;
+void* GetNextFrame(void** last_ebp) {
+ void* sp = *last_ebp;
if ((unsigned long)sp == (unsigned long)last_ebp)
return NULL;
- if ((unsigned long)sp & (sizeof(void *) - 1))
+ if ((unsigned long)sp & (sizeof(void*) - 1))
return NULL;
if ((unsigned long)sp - (unsigned long)last_ebp > 100000)
return NULL;
return sp;
}
#elif defined(__sparc)
-void *GetNextFrame(void *last_ebp) {
- return reinterpret_cast<struct frame *>(last_ebp)->fr_savfp;
+void* GetNextFrame(void* last_ebp) {
+ return reinterpret_cast<struct frame*>(last_ebp)->fr_savfp;
}
#else
-void *GetNextFrame(void **last_ebp) {
+void* GetNextFrame(void** last_ebp) {
return reinterpret_cast<void*>(last_ebp);
}
#endif
@@ -159,12 +158,12 @@ class AutoCloser {
// Control the execution of the lwp.
// Suspend/Resume lwp based on the value of context.
-static bool ControlLwp(int lwpid, void *context) {
+static bool ControlLwp(int lwpid, void* context) {
// The current thread is the one to handle the crash. Ignore it.
if (lwpid != pthread_self()) {
int ctlfd;
char procname[PATH_MAX];
- bool suspend = *(bool *)context;
+ bool suspend = *(bool*)context;
// Open the /proc/$pid/lwp/$lwpid/lwpctl files
snprintf(procname, sizeof (procname), "/proc/self/lwp/%d/lwpctl", lwpid);
@@ -193,7 +192,7 @@ static bool ControlLwp(int lwpid, void *context) {
* prheader_t at the start (/proc/$pid/lstatus or /proc/$pid/lpsinfo).
* Return true on success.
*/
-static bool read_lfile(int pid, const char *lname, prheader_t *lhp) {
+static bool read_lfile(int pid, const char* lname, prheader_t* lhp) {
char lpath[PATH_MAX];
struct stat statb;
int fd;
@@ -242,14 +241,14 @@ int SolarisLwp::GetLwpCount() const {
}
int SolarisLwp::Lwp_iter_all(int pid,
- CallbackParam<LwpCallback> *callback_param) const {
- lwpstatus_t *Lsp;
- lwpstatus_t *sp;
+ CallbackParam<LwpCallback>* callback_param) const {
+ lwpstatus_t* Lsp;
+ lwpstatus_t* sp;
prheader_t lphp[HEADER_MAX];
prheader_t lhp[HEADER_MAX];
- prheader_t *Lphp = lphp;
- prheader_t *Lhp = lhp;
- lwpsinfo_t *Lpsp;
+ prheader_t* Lphp = lphp;
+ prheader_t* Lhp = lhp;
+ lwpsinfo_t* Lpsp;
long nstat;
long ninfo;
int rv = 0;
@@ -264,13 +263,13 @@ int SolarisLwp::Lwp_iter_all(int pid,
return -1;
}
- Lsp = (lwpstatus_t *)(uintptr_t)(Lhp + 1);
- Lpsp = (lwpsinfo_t *)(uintptr_t)(Lphp + 1);
+ Lsp = (lwpstatus_t*)(uintptr_t)(Lhp + 1);
+ Lpsp = (lwpsinfo_t*)(uintptr_t)(Lphp + 1);
for (ninfo = Lphp->pr_nent; ninfo != 0; --ninfo) {
if (Lpsp->pr_sname != 'Z') {
sp = Lsp;
- Lsp = (lwpstatus_t *)((uintptr_t)Lsp + Lhp->pr_entsize);
+ Lsp = (lwpstatus_t*)((uintptr_t)Lsp + Lhp->pr_entsize);
} else {
sp = NULL;
}
@@ -278,7 +277,7 @@ int SolarisLwp::Lwp_iter_all(int pid,
!(callback_param->call_back)(sp, callback_param->context))
break;
++rv;
- Lpsp = (lwpsinfo_t *)((uintptr_t)Lpsp + Lphp->pr_entsize);
+ Lpsp = (lwpsinfo_t*)((uintptr_t)Lpsp + Lphp->pr_entsize);
}
return rv;
@@ -298,12 +297,12 @@ int SolarisLwp::GetModuleCount() const {
}
int SolarisLwp::ListModules(
- CallbackParam<ModuleCallback> *callback_param) const {
- const char *maps_path = "/proc/self/map";
+ CallbackParam<ModuleCallback>* callback_param) const {
+ const char* maps_path = "/proc/self/map";
struct stat status;
int fd = 0, num;
prmap_t map_array[MAP_MAX];
- prmap_t *maps = map_array;
+ prmap_t* maps = map_array;
size_t size;
if ((fd = open(maps_path, O_RDONLY)) == -1) {
@@ -326,12 +325,12 @@ int SolarisLwp::ListModules(
return -1;
}
- if (read(fd, (void *)maps, size) < 0) {
+ if (read(fd, (void*)maps, size) < 0) {
print_message2(2, "failed to read %d\n", fd);
return -1;
}
- prmap_t *_maps;
+ prmap_t* _maps;
int _num;
int module_count = 0;
@@ -345,7 +344,7 @@ int SolarisLwp::ListModules(
*/
for (_num = 0, _maps = maps; _num < num; ++_num, ++_maps) {
ModuleInfo module;
- char *name = _maps->pr_mapname;
+ char* name = _maps->pr_mapname;
memset(&module, 0, sizeof (module));
module.start_addr = _maps->pr_vaddr;
@@ -403,7 +402,7 @@ bool SolarisLwp::IsAddressMapped(uintptr_t address) const {
// The Solaris stack looks like this:
// http://src.opensolaris.org/source/xref/onnv/onnv-gate/usr/src/lib/libproc/common/Pstack.c#81
bool SolarisLwp::FindSigContext(uintptr_t sighandler_ebp,
- ucontext_t **sig_ctx) {
+ ucontext_t** sig_ctx) {
uintptr_t previous_ebp;
uintptr_t sig_ebp;
const int MAX_STACK_DEPTH = 50;
@@ -416,7 +415,7 @@ bool SolarisLwp::FindSigContext(uintptr_t sighandler_ebp,
*sig_ctx = reinterpret_cast<ucontext_t*>(sighandler_ebp + sizeof (struct frame));
uintptr_t sig_esp = (*sig_ctx)->uc_mcontext.gregs[REG_O6];
if (sig_esp < previous_ebp && sig_esp > sighandler_ebp)
- sig_ebp = (uintptr_t)(((struct frame *)sig_esp)->fr_savfp);
+ sig_ebp = (uintptr_t)(((struct frame*)sig_esp)->fr_savfp);
#elif TARGET_CPU_X86
previous_ebp = reinterpret_cast<uintptr_t>(GetNextFrame(
diff --git a/src/client/solaris/handler/solaris_lwp.h b/src/client/solaris/handler/solaris_lwp.h
index 0914cfcd..f27d6b74 100644
--- a/src/client/solaris/handler/solaris_lwp.h
+++ b/src/client/solaris/handler/solaris_lwp.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2007, Google Inc.
-// All rights reserved.
+// Copyright 2007 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -70,17 +69,17 @@ struct ModuleInfo {
// A callback to run when getting a lwp in the process.
// Return true will go on to the next lwp while return false will stop the
// iteration.
-typedef bool (*LwpCallback)(lwpstatus_t* lsp, void *context);
+typedef bool (*LwpCallback)(lwpstatus_t* lsp, void* context);
// A callback to run when a new module is found in the process.
// Return true will go on to the next module while return false will stop the
// iteration.
-typedef bool (*ModuleCallback)(const ModuleInfo &module_info, void *context);
+typedef bool (*ModuleCallback)(const ModuleInfo& module_info, void* context);
// A callback to run when getting a lwpid in the process.
// Return true will go on to the next lwp while return false will stop the
// iteration.
-typedef bool (*LwpidCallback)(int lwpid, void *context);
+typedef bool (*LwpidCallback)(int lwpid, void* context);
// Holding the callback information.
template<class CallbackFunc>
@@ -88,12 +87,12 @@ struct CallbackParam {
// Callback function address.
CallbackFunc call_back;
// Callback context;
- void *context;
+ void* context;
CallbackParam() : call_back(NULL), context(NULL) {
}
- CallbackParam(CallbackFunc func, void *func_context) :
+ CallbackParam(CallbackFunc func, void* func_context) :
call_back(func), context(func_context) {
}
};
@@ -129,7 +128,7 @@ class SolarisLwp {
// Whenever there is a lwp found, the callback will be invoked to process
// the information.
// Return the callback return value or -1 on error.
- int Lwp_iter_all(int pid, CallbackParam<LwpCallback> *callback_param) const;
+ int Lwp_iter_all(int pid, CallbackParam<LwpCallback>* callback_param) const;
// Get the module count of the current process.
int GetModuleCount() const;
@@ -138,13 +137,13 @@ class SolarisLwp {
// Whenever a module is found, the callback will be invoked to process the
// information.
// Return how may modules are found.
- int ListModules(CallbackParam<ModuleCallback> *callback_param) const;
+ int ListModules(CallbackParam<ModuleCallback>* callback_param) const;
// Get the bottom of the stack from esp.
uintptr_t GetLwpStackBottom(uintptr_t current_esp) const;
// Finds a signal context on the stack given the ebp of our signal handler.
- bool FindSigContext(uintptr_t sighandler_ebp, ucontext_t **sig_ctx);
+ bool FindSigContext(uintptr_t sighandler_ebp, ucontext_t** sig_ctx);
private:
// Check if the address is a valid virtual address.
diff --git a/src/client/windows/breakpad_client.gyp b/src/client/windows/breakpad_client.gyp
deleted file mode 100644
index 64797534..00000000
--- a/src/client/windows/breakpad_client.gyp
+++ /dev/null
@@ -1,66 +0,0 @@
-# Copyright 2010 Google Inc. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-# * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-# * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-{
- 'includes': [
- '../../build/common.gypi',
- ],
- 'targets': [
- {
- 'target_name': 'build_all',
- 'type': 'none',
- 'dependencies': [
- './crash_generation/crash_generation.gyp:*',
- './handler/exception_handler.gyp:*',
- './sender/crash_report_sender.gyp:*',
- './unittests/client_tests.gyp:*',
- './unittests/testing.gyp:*',
- './tests/crash_generation_app/crash_generation_app.gyp:*',
- ]
- },
- {
- 'target_name': 'common',
- 'type': 'static_library',
- 'include_dirs': [
- '<(DEPTH)',
- ],
- 'direct_dependent_settings': {
- 'include_dirs': [
- '<(DEPTH)',
- ]
- },
- 'sources': [
- '<(DEPTH)/common/windows/guid_string.cc',
- '<(DEPTH)/common/windows/guid_string.h',
- '<(DEPTH)/common/windows/http_upload.cc',
- '<(DEPTH)/common/windows/http_upload.h',
- '<(DEPTH)/common/windows/string_utils.cc',
- ]
- }
- ]
-}
diff --git a/src/client/windows/common/auto_critical_section.h b/src/client/windows/common/auto_critical_section.h
index 3fd4b9b7..75ed4b9b 100644
--- a/src/client/windows/common/auto_critical_section.h
+++ b/src/client/windows/common/auto_critical_section.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2008, Google Inc.
-// All rights reserved.
+// Copyright 2008 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/client/windows/common/ipc_protocol.h b/src/client/windows/common/ipc_protocol.h
index c7486819..7e0c24e3 100644
--- a/src/client/windows/common/ipc_protocol.h
+++ b/src/client/windows/common/ipc_protocol.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2008, Google Inc.
-// All rights reserved.
+// Copyright 2008 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/client/windows/crash_generation/client_info.cc b/src/client/windows/crash_generation/client_info.cc
index ed312638..f0a4b911 100644
--- a/src/client/windows/crash_generation/client_info.cc
+++ b/src/client/windows/crash_generation/client_info.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2008, Google Inc.
-// All rights reserved.
+// Copyright 2008 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/client/windows/crash_generation/client_info.h b/src/client/windows/crash_generation/client_info.h
index 6a8fba31..1c9cd3c3 100644
--- a/src/client/windows/crash_generation/client_info.h
+++ b/src/client/windows/crash_generation/client_info.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2008, Google Inc.
-// All rights reserved.
+// Copyright 2008 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/client/windows/crash_generation/crash_generation.gyp b/src/client/windows/crash_generation/crash_generation.gyp
deleted file mode 100644
index ba343768..00000000
--- a/src/client/windows/crash_generation/crash_generation.gyp
+++ /dev/null
@@ -1,63 +0,0 @@
-# Copyright 2010 Google Inc. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-# * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-# * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-{
- 'includes': [
- '../../../build/common.gypi',
- ],
- 'targets': [
- {
- 'target_name': 'crash_generation_server',
- 'type': 'static_library',
- 'sources': [
- 'client_info.cc',
- 'crash_generation_server.cc',
- 'minidump_generator.cc',
- 'client_info.h',
- 'crash_generation_client.h',
- 'crash_generation_server.h',
- 'minidump_generator.h',
- ],
- 'dependencies': [
- '../breakpad_client.gyp:common'
- ],
- },
- {
- 'target_name': 'crash_generation_client',
- 'type': 'static_library',
- 'include_dirs': [
- '<(DEPTH)',
- ],
- 'sources': [
- 'crash_generation_client.h',
- 'crash_generation_client.cc',
- 'crash_generation_server.h',
- ],
- },
- ],
-}
diff --git a/src/client/windows/crash_generation/crash_generation_client.cc b/src/client/windows/crash_generation/crash_generation_client.cc
index 3ba5d4e4..d6da09eb 100644
--- a/src/client/windows/crash_generation/crash_generation_client.cc
+++ b/src/client/windows/crash_generation/crash_generation_client.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2008, Google Inc.
-// All rights reserved.
+// Copyright 2008 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/client/windows/crash_generation/crash_generation_client.h b/src/client/windows/crash_generation/crash_generation_client.h
index 457f7319..f912bf5f 100644
--- a/src/client/windows/crash_generation/crash_generation_client.h
+++ b/src/client/windows/crash_generation/crash_generation_client.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2008, Google Inc.
-// All rights reserved.
+// Copyright 2008 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/client/windows/crash_generation/crash_generation_server.cc b/src/client/windows/crash_generation/crash_generation_server.cc
index 0af213ba..bf80ee9c 100644
--- a/src/client/windows/crash_generation/crash_generation_server.cc
+++ b/src/client/windows/crash_generation/crash_generation_server.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2008, Google Inc.
-// All rights reserved.
+// Copyright 2008 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/client/windows/crash_generation/crash_generation_server.h b/src/client/windows/crash_generation/crash_generation_server.h
index 0ea90e51..74275a74 100644
--- a/src/client/windows/crash_generation/crash_generation_server.h
+++ b/src/client/windows/crash_generation/crash_generation_server.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2008, Google Inc.
-// All rights reserved.
+// Copyright 2008 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/client/windows/crash_generation/minidump_generator.cc b/src/client/windows/crash_generation/minidump_generator.cc
index 573c2786..523db27a 100644
--- a/src/client/windows/crash_generation/minidump_generator.cc
+++ b/src/client/windows/crash_generation/minidump_generator.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2008, Google Inc.
-// All rights reserved.
+// Copyright 2008 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -432,7 +431,7 @@ bool MinidumpGenerator::WriteMinidump() {
full_dump_file_,
static_cast<MINIDUMP_TYPE>((dump_type_ & (~MiniDumpNormal))
| MiniDumpWithHandleData),
- exception_pointers_ ? &dump_exception_info : NULL,
+ dump_exception_pointers,
&user_streams,
NULL) != FALSE;
}
@@ -449,7 +448,7 @@ bool MinidumpGenerator::WriteMinidump() {
dump_file_,
static_cast<MINIDUMP_TYPE>((dump_type_ & (~MiniDumpWithFullMemory))
| MiniDumpNormal),
- exception_pointers_ ? &dump_exception_info : NULL,
+ dump_exception_pointers,
&user_streams,
callback_info_) != FALSE;
diff --git a/src/client/windows/crash_generation/minidump_generator.h b/src/client/windows/crash_generation/minidump_generator.h
index a707c0bb..f960c5dc 100644
--- a/src/client/windows/crash_generation/minidump_generator.h
+++ b/src/client/windows/crash_generation/minidump_generator.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2008, Google Inc.
-// All rights reserved.
+// Copyright 2008 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/client/windows/handler/exception_handler.cc b/src/client/windows/handler/exception_handler.cc
index ad45b200..3b3938aa 100644
--- a/src/client/windows/handler/exception_handler.cc
+++ b/src/client/windows/handler/exception_handler.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2006, Google Inc.
-// All rights reserved.
+// Copyright 2006 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -118,7 +117,7 @@ ExceptionHandler::ExceptionHandler(
NULL); // custom_info - not used
}
-ExceptionHandler::ExceptionHandler(const wstring &dump_path,
+ExceptionHandler::ExceptionHandler(const wstring& dump_path,
FilterCallback filter,
MinidumpCallback callback,
void* callback_context,
@@ -383,7 +382,7 @@ bool ExceptionHandler::RequestUpload(DWORD crash_id) {
// static
DWORD ExceptionHandler::ExceptionHandlerThreadMain(void* lpParameter) {
- ExceptionHandler* self = reinterpret_cast<ExceptionHandler *>(lpParameter);
+ ExceptionHandler* self = reinterpret_cast<ExceptionHandler*>(lpParameter);
assert(self);
assert(self->handler_start_semaphore_ != NULL);
assert(self->handler_finish_semaphore_ != NULL);
@@ -765,7 +764,7 @@ bool ExceptionHandler::WriteMinidumpForException(EXCEPTION_POINTERS* exinfo) {
}
// static
-bool ExceptionHandler::WriteMinidump(const wstring &dump_path,
+bool ExceptionHandler::WriteMinidump(const wstring& dump_path,
MinidumpCallback callback,
void* callback_context,
MINIDUMP_TYPE dump_type) {
diff --git a/src/client/windows/handler/exception_handler.gyp b/src/client/windows/handler/exception_handler.gyp
deleted file mode 100644
index c5733277..00000000
--- a/src/client/windows/handler/exception_handler.gyp
+++ /dev/null
@@ -1,47 +0,0 @@
-# Copyright 2010 Google Inc. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-# * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-# * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-{
- 'includes': [
- '../../../build/common.gypi',
- ],
- 'targets': [
- {
- 'target_name': 'exception_handler',
- 'type': 'static_library',
- 'sources': [
- "exception_handler.cc",
- "exception_handler.h",
- ],
- 'dependencies': [
- '../breakpad_client.gyp:common',
- '../crash_generation/crash_generation.gyp:crash_generation_server',
- ]
- },
- ],
-}
diff --git a/src/client/windows/handler/exception_handler.h b/src/client/windows/handler/exception_handler.h
index 11babe51..963572bf 100644
--- a/src/client/windows/handler/exception_handler.h
+++ b/src/client/windows/handler/exception_handler.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2006, Google Inc.
-// All rights reserved.
+// Copyright 2006 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -218,7 +217,7 @@ class ExceptionHandler {
// Get and set the minidump path.
wstring dump_path() const { return dump_path_; }
- void set_dump_path(const wstring &dump_path) {
+ void set_dump_path(const wstring& dump_path) {
dump_path_ = dump_path;
dump_path_c_ = dump_path_.c_str();
UpdateNextID(); // Necessary to put dump_path_ in next_minidump_path_.
@@ -237,7 +236,7 @@ class ExceptionHandler {
// Convenience form of WriteMinidump which does not require an
// ExceptionHandler instance.
- static bool WriteMinidump(const wstring &dump_path,
+ static bool WriteMinidump(const wstring& dump_path,
MinidumpCallback callback, void* callback_context,
MINIDUMP_TYPE dump_type = MiniDumpNormal);
@@ -513,8 +512,8 @@ class ExceptionHandler {
static volatile LONG instance_count_;
// disallow copy ctor and operator=
- explicit ExceptionHandler(const ExceptionHandler &);
- void operator=(const ExceptionHandler &);
+ explicit ExceptionHandler(const ExceptionHandler&);
+ void operator=(const ExceptionHandler&);
};
} // namespace google_breakpad
diff --git a/src/client/windows/sender/crash_report_sender.cc b/src/client/windows/sender/crash_report_sender.cc
index eb2b422a..27a7ec39 100644
--- a/src/client/windows/sender/crash_report_sender.cc
+++ b/src/client/windows/sender/crash_report_sender.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2006, Google Inc.
-// All rights reserved.
+// Copyright 2006 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -45,12 +44,12 @@ namespace google_breakpad {
static const char kCheckpointSignature[] = "GBP1\n";
-CrashReportSender::CrashReportSender(const wstring &checkpoint_file)
+CrashReportSender::CrashReportSender(const wstring& checkpoint_file)
: checkpoint_file_(checkpoint_file),
max_reports_per_day_(-1),
last_sent_date_(-1),
reports_sent_(0) {
- FILE *fd;
+ FILE* fd;
if (OpenCheckpointFile(L"r", &fd) == 0) {
ReadCheckpoint(fd);
fclose(fd);
@@ -58,8 +57,8 @@ CrashReportSender::CrashReportSender(const wstring &checkpoint_file)
}
ReportResult CrashReportSender::SendCrashReport(
- const wstring &url, const map<wstring, wstring> &parameters,
- const map<wstring, wstring> &files, wstring *report_code) {
+ const wstring& url, const map<wstring, wstring>& parameters,
+ const map<wstring, wstring>& files, wstring* report_code) {
int today = GetCurrentDate();
if (today == last_sent_date_ &&
max_reports_per_day_ != -1 &&
@@ -82,7 +81,7 @@ ReportResult CrashReportSender::SendCrashReport(
}
}
-void CrashReportSender::ReadCheckpoint(FILE *fd) {
+void CrashReportSender::ReadCheckpoint(FILE* fd) {
char buf[128];
if (!fgets(buf, sizeof(buf), fd) ||
strcmp(buf, kCheckpointSignature) != 0) {
@@ -108,7 +107,7 @@ void CrashReportSender::ReportSent(int today) {
++reports_sent_;
// Update the checkpoint file
- FILE *fd;
+ FILE* fd;
if (OpenCheckpointFile(L"w", &fd) == 0) {
fputs(kCheckpointSignature, fd);
fprintf(fd, "%d\n", last_sent_date_);
@@ -124,7 +123,7 @@ int CrashReportSender::GetCurrentDate() const {
system_time.wDay;
}
-int CrashReportSender::OpenCheckpointFile(const wchar_t *mode, FILE **fd) {
+int CrashReportSender::OpenCheckpointFile(const wchar_t* mode, FILE** fd) {
if (checkpoint_file_.empty()) {
return ENOENT;
}
diff --git a/src/client/windows/sender/crash_report_sender.gyp b/src/client/windows/sender/crash_report_sender.gyp
deleted file mode 100644
index dc8583a0..00000000
--- a/src/client/windows/sender/crash_report_sender.gyp
+++ /dev/null
@@ -1,46 +0,0 @@
-# Copyright 2010 Google Inc. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-# * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-# * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-{
- 'includes': [
- '../../../build/common.gypi',
- ],
- 'targets': [
- {
- 'target_name': 'crash_report_sender',
- 'type': 'static_library',
- 'sources': [
- 'crash_report_sender.cc',
- 'crash_report_sender.h',
- ],
- 'dependencies': [
- '../breakpad_client.gyp:common'
- ],
- },
- ],
-}
diff --git a/src/client/windows/sender/crash_report_sender.h b/src/client/windows/sender/crash_report_sender.h
index 7786cc69..758adbb4 100644
--- a/src/client/windows/sender/crash_report_sender.h
+++ b/src/client/windows/sender/crash_report_sender.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2006, Google Inc.
-// All rights reserved.
+// Copyright 2006 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -65,7 +64,7 @@ class CrashReportSender {
// If checkpoint_file is non-empty, breakpad will persist crash report
// state to this file. A checkpoint file is required for
// set_max_reports_per_day() to function properly.
- explicit CrashReportSender(const wstring &checkpoint_file);
+ explicit CrashReportSender(const wstring& checkpoint_file);
~CrashReportSender() {}
// Sets the maximum number of crash reports that will be sent in a 24-hour
@@ -87,14 +86,14 @@ class CrashReportSender {
// the return value is RESULT_SUCCEEDED), a code uniquely identifying the
// report will be returned in report_code.
// (Otherwise, report_code will be unchanged.)
- ReportResult SendCrashReport(const wstring &url,
- const map<wstring, wstring> &parameters,
- const map<wstring, wstring> &files,
- wstring *report_code);
+ ReportResult SendCrashReport(const wstring& url,
+ const map<wstring, wstring>& parameters,
+ const map<wstring, wstring>& files,
+ wstring* report_code);
private:
// Reads persistent state from a checkpoint file.
- void ReadCheckpoint(FILE *fd);
+ void ReadCheckpoint(FILE* fd);
// Called when a new report has been sent, to update the checkpoint state.
void ReportSent(int today);
@@ -104,7 +103,7 @@ class CrashReportSender {
// Opens the checkpoint file with the specified mode.
// Returns zero on success, or an error code on failure.
- int OpenCheckpointFile(const wchar_t *mode, FILE **fd);
+ int OpenCheckpointFile(const wchar_t* mode, FILE** fd);
wstring checkpoint_file_;
int max_reports_per_day_;
@@ -114,8 +113,8 @@ class CrashReportSender {
int reports_sent_;
// Disallow copy constructor and operator=
- explicit CrashReportSender(const CrashReportSender &);
- void operator=(const CrashReportSender &);
+ explicit CrashReportSender(const CrashReportSender&);
+ void operator=(const CrashReportSender&);
};
} // namespace google_breakpad
diff --git a/src/client/windows/tests/crash_generation_app/abstract_class.cc b/src/client/windows/tests/crash_generation_app/abstract_class.cc
index 32f78f2b..28b8ee14 100644
--- a/src/client/windows/tests/crash_generation_app/abstract_class.cc
+++ b/src/client/windows/tests/crash_generation_app/abstract_class.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2008, Google Inc.
-// All rights reserved.
+// Copyright 2008 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/client/windows/tests/crash_generation_app/abstract_class.h b/src/client/windows/tests/crash_generation_app/abstract_class.h
index e3f2a4f3..c996a216 100644
--- a/src/client/windows/tests/crash_generation_app/abstract_class.h
+++ b/src/client/windows/tests/crash_generation_app/abstract_class.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2008, Google Inc.
-// All rights reserved.
+// Copyright 2008 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/client/windows/tests/crash_generation_app/crash_generation_app.cc b/src/client/windows/tests/crash_generation_app/crash_generation_app.cc
index 0d837e52..883afcc6 100644
--- a/src/client/windows/tests/crash_generation_app/crash_generation_app.cc
+++ b/src/client/windows/tests/crash_generation_app/crash_generation_app.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2008, Google Inc.
-// All rights reserved.
+// Copyright 2008 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/client/windows/tests/crash_generation_app/crash_generation_app.gyp b/src/client/windows/tests/crash_generation_app/crash_generation_app.gyp
deleted file mode 100644
index 3ce307da..00000000
--- a/src/client/windows/tests/crash_generation_app/crash_generation_app.gyp
+++ /dev/null
@@ -1,63 +0,0 @@
-# Copyright 2010 Google Inc. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-# * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-# * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-{
- 'includes': [
- '../../../../build/common.gypi',
- ],
- 'targets': [
- {
- 'target_name': 'crash_generation_app',
- 'type': 'executable',
- 'sources': [
- 'abstract_class.cc',
- 'abstract_class.h',
- 'crash_generation_app.cc',
- 'crash_generation_app.h',
- 'crash_generation_app.ico',
- 'crash_generation_app.rc',
- 'resource.h',
- 'small.ico',
- ],
- 'libraries': [
- 'user32.lib',
- ],
- 'dependencies': [
- '../../breakpad_client.gyp:common',
- '../../crash_generation/crash_generation.gyp:crash_generation_server',
- '../../crash_generation/crash_generation.gyp:crash_generation_client',
- '../../handler/exception_handler.gyp:exception_handler',
- ],
- 'msvs_settings': {
- 'VCLinkerTool': {
- 'SubSystem': '2', # Windows Subsystem as opposed to a console app
- },
- },
- }
- ]
-}
diff --git a/src/client/windows/tests/crash_generation_app/crash_generation_app.h b/src/client/windows/tests/crash_generation_app/crash_generation_app.h
index 4d3bb6eb..1d1deea4 100644
--- a/src/client/windows/tests/crash_generation_app/crash_generation_app.h
+++ b/src/client/windows/tests/crash_generation_app/crash_generation_app.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2008, Google Inc.
-// All rights reserved.
+// Copyright 2008 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/client/windows/tests/crash_generation_app/resource.h b/src/client/windows/tests/crash_generation_app/resource.h
index 8c7f6570..e9120826 100644
--- a/src/client/windows/tests/crash_generation_app/resource.h
+++ b/src/client/windows/tests/crash_generation_app/resource.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2008, Google Inc.
-// All rights reserved.
+// Copyright 2008 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/client/windows/unittests/client_tests.gyp b/src/client/windows/unittests/client_tests.gyp
deleted file mode 100644
index 768f8fd8..00000000
--- a/src/client/windows/unittests/client_tests.gyp
+++ /dev/null
@@ -1,81 +0,0 @@
-# Copyright 2010 Google Inc. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-# * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-# * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-{
- 'includes': [
- '../../../build/common.gypi',
- ],
- 'targets': [
- {
- 'target_name': 'client_tests',
- 'type': 'executable',
- 'sources': [
- 'exception_handler_test.h',
- 'exception_handler_test.cc',
- 'exception_handler_death_test.cc',
- 'exception_handler_nesting_test.cc',
- 'minidump_test.cc',
- 'dump_analysis.cc',
- 'dump_analysis.h',
- 'crash_generation_server_test.cc'
- ],
- 'dependencies': [
- 'testing.gyp:gtest',
- 'testing.gyp:gmock',
- '../breakpad_client.gyp:common',
- '../crash_generation/crash_generation.gyp:crash_generation_server',
- '../crash_generation/crash_generation.gyp:crash_generation_client',
- '../handler/exception_handler.gyp:exception_handler',
- 'processor_bits',
- ]
- },
- {
- 'target_name': 'processor_bits',
- 'type': 'static_library',
- 'include_dirs': [
- '<(DEPTH)',
- ],
- 'direct_dependent_settings': {
- 'include_dirs': [
- '<(DEPTH)',
- ]
- },
- 'sources': [
- '<(DEPTH)/common/string_conversion.cc',
- '<(DEPTH)/processor/basic_code_modules.cc',
- '<(DEPTH)/processor/convert_old_arm64_context.cc',
- '<(DEPTH)/processor/dump_context.cc',
- '<(DEPTH)/processor/dump_object.cc',
- '<(DEPTH)/processor/logging.cc',
- '<(DEPTH)/processor/minidump.cc',
- '<(DEPTH)/processor/pathname_stripper.cc',
- '<(DEPTH)/processor/proc_maps_linux.cc',
- ]
- }
- ],
-}
diff --git a/src/client/windows/unittests/crash_generation_server_test.cc b/src/client/windows/unittests/crash_generation_server_test.cc
index 09f2dd20..cd624f07 100644
--- a/src/client/windows/unittests/crash_generation_server_test.cc
+++ b/src/client/windows/unittests/crash_generation_server_test.cc
@@ -1,5 +1,4 @@
-// Copyright 2010, Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/client/windows/unittests/dump_analysis.cc b/src/client/windows/unittests/dump_analysis.cc
index 53d4ddbd..24a33769 100644
--- a/src/client/windows/unittests/dump_analysis.cc
+++ b/src/client/windows/unittests/dump_analysis.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2010, Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -127,8 +126,8 @@ size_t DumpAnalysis::GetStreamImpl(ULONG stream_number, void** stream) const {
return ret ? memory_list_size : 0;
}
-bool DumpAnalysis::HasMemoryImpl(const void *addr_in, size_t structuresize,
- void **structure) const {
+bool DumpAnalysis::HasMemoryImpl(const void* addr_in, size_t structuresize,
+ void** structure) const {
uintptr_t address = reinterpret_cast<uintptr_t>(addr_in);
MINIDUMP_MEMORY_LIST* memory_list = NULL;
size_t memory_list_size = GetStream(MemoryListStream, &memory_list);
diff --git a/src/client/windows/unittests/dump_analysis.h b/src/client/windows/unittests/dump_analysis.h
index 6cef48d8..f8acc268 100644
--- a/src/client/windows/unittests/dump_analysis.h
+++ b/src/client/windows/unittests/dump_analysis.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2010, Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/client/windows/unittests/exception_handler_death_test.cc b/src/client/windows/unittests/exception_handler_death_test.cc
index 5ef9e64d..a7679dd6 100644
--- a/src/client/windows/unittests/exception_handler_death_test.cc
+++ b/src/client/windows/unittests/exception_handler_death_test.cc
@@ -1,5 +1,4 @@
-// Copyright 2009, Google Inc.
-// All rights reserved.
+// Copyright 2009 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -52,7 +51,7 @@ const char kSuccessIndicator[] = "success";
const char kFailureIndicator[] = "failure";
// Utility function to test for a path's existence.
-BOOL DoesPathExist(const TCHAR *path_name);
+BOOL DoesPathExist(const TCHAR* path_name);
enum OutOfProcGuarantee {
OUT_OF_PROC_GUARANTEED,
@@ -92,7 +91,7 @@ void ExceptionHandlerDeathTest::SetUp() {
CreateDirectory(temp_path_, NULL);
}
-BOOL DoesPathExist(const TCHAR *path_name) {
+BOOL DoesPathExist(const TCHAR* path_name) {
DWORD flags = GetFileAttributes(path_name);
if (flags == INVALID_FILE_ATTRIBUTES) {
return FALSE;
@@ -135,15 +134,15 @@ TEST_F(ExceptionHandlerDeathTest, InProcTest) {
// Disable GTest SEH handler
testing::DisableExceptionHandlerInScope disable_exception_handler;
- int *i = NULL;
+ int* i = NULL;
ASSERT_DEATH((*i)++, kSuccessIndicator);
}
static bool gDumpCallbackCalled = false;
-void clientDumpCallback(void *dump_context,
- const google_breakpad::ClientInfo *client_info,
- const std::wstring *dump_path) {
+void clientDumpCallback(void* dump_context,
+ const google_breakpad::ClientInfo* client_info,
+ const std::wstring* dump_path) {
gDumpCallbackCalled = true;
}
@@ -152,7 +151,7 @@ void ExceptionHandlerDeathTest::DoCrashAccessViolation(
scoped_ptr<google_breakpad::ExceptionHandler> exc;
if (out_of_proc_guarantee == OUT_OF_PROC_GUARANTEED) {
- google_breakpad::CrashGenerationClient *client =
+ google_breakpad::CrashGenerationClient* client =
new google_breakpad::CrashGenerationClient(kPipeName,
MiniDumpNormal,
NULL); // custom_info
@@ -184,7 +183,7 @@ void ExceptionHandlerDeathTest::DoCrashAccessViolation(
// if it's not true we'll still get an error rather than the crash
// being expected.
ASSERT_TRUE(exc->IsOutOfProcess());
- int *i = NULL;
+ int* i = NULL;
printf("%d\n", (*i)++);
}
@@ -283,7 +282,7 @@ TEST_F(ExceptionHandlerDeathTest, PureVirtualCallTest) {
EXPECT_EXIT(DoCrashPureVirtualCall(), ::testing::ExitedWithCode(0), "");
}
-wstring find_minidump_in_directory(const wstring &directory) {
+wstring find_minidump_in_directory(const wstring& directory) {
wstring search_path = directory + L"\\*";
WIN32_FIND_DATA find_data;
HANDLE find_handle = FindFirstFileW(search_path.c_str(), &find_data);
diff --git a/src/client/windows/unittests/exception_handler_nesting_test.cc b/src/client/windows/unittests/exception_handler_nesting_test.cc
index 3ae1d7cd..81ae7dc7 100644
--- a/src/client/windows/unittests/exception_handler_nesting_test.cc
+++ b/src/client/windows/unittests/exception_handler_nesting_test.cc
@@ -1,5 +1,4 @@
-// Copyright 2012, Google Inc.
-// All rights reserved.
+// Copyright 2012 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -49,7 +48,7 @@ const char kFilterReturnsFalse[] = "filter_returns_false";
const char kCallbackReturnsTrue[] = "callback_returns_true";
const char kCallbackReturnsFalse[] = "callback_returns_false";
-bool DoesPathExist(const wchar_t *path_name) {
+bool DoesPathExist(const wchar_t* path_name) {
DWORD flags = GetFileAttributes(path_name);
if (flags == INVALID_FILE_ATTRIBUTES) {
return false;
@@ -128,12 +127,12 @@ bool MinidumpWrittenCallback(const wchar_t* dump_path,
}
-void DoCrash(const char *message) {
+void DoCrash(const char* message) {
if (message) {
fprintf(stderr, "%s", message);
fflush(stderr);
}
- int *i = NULL;
+ int* i = NULL;
(*i)++;
ASSERT_TRUE(false);
diff --git a/src/client/windows/unittests/exception_handler_test.cc b/src/client/windows/unittests/exception_handler_test.cc
index a4ce12a8..237af29d 100644
--- a/src/client/windows/unittests/exception_handler_test.cc
+++ b/src/client/windows/unittests/exception_handler_test.cc
@@ -1,5 +1,4 @@
-// Copyright 2009, Google Inc.
-// All rights reserved.
+// Copyright 2009 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -87,13 +86,13 @@ class ExceptionHandlerTest : public ::testing::Test {
void DoCrashPureVirtualCall();
// Utility function to test for a path's existence.
- static BOOL DoesPathExist(const TCHAR *path_name);
+ static BOOL DoesPathExist(const TCHAR* path_name);
// Client callback.
static void ClientDumpCallback(
- void *dump_context,
- const google_breakpad::ClientInfo *client_info,
- const std::wstring *dump_path);
+ void* dump_context,
+ const google_breakpad::ClientInfo* client_info,
+ const std::wstring* dump_path);
static bool DumpCallback(const wchar_t* dump_path,
const wchar_t* minidump_id,
@@ -141,7 +140,7 @@ void ExceptionHandlerTest::TearDown() {
}
}
-BOOL ExceptionHandlerTest::DoesPathExist(const TCHAR *path_name) {
+BOOL ExceptionHandlerTest::DoesPathExist(const TCHAR* path_name) {
DWORD flags = GetFileAttributes(path_name);
if (flags == INVALID_FILE_ATTRIBUTES) {
return FALSE;
@@ -151,9 +150,9 @@ BOOL ExceptionHandlerTest::DoesPathExist(const TCHAR *path_name) {
// static
void ExceptionHandlerTest::ClientDumpCallback(
- void *dump_context,
- const google_breakpad::ClientInfo *client_info,
- const wstring *dump_path) {
+ void* dump_context,
+ const google_breakpad::ClientInfo* client_info,
+ const wstring* dump_path) {
dump_file = *dump_path;
// Create the full dump file name from the dump path.
full_dump_file = dump_file.substr(0, dump_file.length() - 4) + L"-full.dmp";
@@ -174,7 +173,7 @@ bool ExceptionHandlerTest::DumpCallback(const wchar_t* dump_path,
}
void ExceptionHandlerTest::DoCrashInvalidParameter() {
- google_breakpad::ExceptionHandler *exc =
+ google_breakpad::ExceptionHandler* exc =
new google_breakpad::ExceptionHandler(
temp_path_, NULL, NULL, NULL,
google_breakpad::ExceptionHandler::HANDLER_INVALID_PARAMETER,
@@ -206,7 +205,7 @@ struct PureVirtualCall : public PureVirtualCallBase {
};
void ExceptionHandlerTest::DoCrashPureVirtualCall() {
- google_breakpad::ExceptionHandler *exc =
+ google_breakpad::ExceptionHandler* exc =
new google_breakpad::ExceptionHandler(
temp_path_, NULL, NULL, NULL,
google_breakpad::ExceptionHandler::HANDLER_PURECALL,
diff --git a/src/client/windows/unittests/exception_handler_test.h b/src/client/windows/unittests/exception_handler_test.h
index ef973e53..9d4e44e4 100644
--- a/src/client/windows/unittests/exception_handler_test.h
+++ b/src/client/windows/unittests/exception_handler_test.h
@@ -1,5 +1,4 @@
-// Copyright 2012, Google Inc.
-// All rights reserved.
+// Copyright 2012 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/client/windows/unittests/minidump_test.cc b/src/client/windows/unittests/minidump_test.cc
index 82641125..7bfc8d77 100644
--- a/src/client/windows/unittests/minidump_test.cc
+++ b/src/client/windows/unittests/minidump_test.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2010, Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/client/windows/unittests/testing.gyp b/src/client/windows/unittests/testing.gyp
deleted file mode 100644
index 0f9f944c..00000000
--- a/src/client/windows/unittests/testing.gyp
+++ /dev/null
@@ -1,90 +0,0 @@
-# Copyright 2010 Google Inc. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-# * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-# * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-{
- 'includes': [
- '../../../build/common.gypi',
- ],
- 'target_defaults': {
- },
- 'targets': [
- {
- 'target_name': 'gtest',
- 'type': 'static_library',
- 'include_dirs': [
- '<(DEPTH)/testing/include',
- '<(DEPTH)/testing/googletest/include',
- '<(DEPTH)/testing/googletest',
- '<(DEPTH)/testing',
- ],
- 'sources': [
- '<(DEPTH)/testing/googletest/src/gtest-all.cc',
- ],
- 'direct_dependent_settings': {
- 'include_dirs': [
- '<(DEPTH)/testing/include',
- '<(DEPTH)/testing/gtest/include',
- ],
- # Visual C++ implements variadic templates strangely, and
- # VC++2012 broke Google Test by lowering this value. See
- # http://stackoverflow.com/questions/12558327/google-test-in-visual-studio-2012
- 'defines': ['_VARIADIC_MAX=10', '_SILENCE_TR1_NAMESPACE_DEPRECATION_WARNING'],
- },
- 'defines': ['_VARIADIC_MAX=10', '_SILENCE_TR1_NAMESPACE_DEPRECATION_WARNING'],
- },
- {
- 'target_name': 'gmock',
- 'type': 'static_library',
- 'include_dirs': [
- '<(DEPTH)/testing/include',
- '<(DEPTH)/testing/googletest/include',
- '<(DEPTH)/testing/googletest',
- '<(DEPTH)/testing/googlemock/include',
- '<(DEPTH)/testing/googlemock',
- '<(DEPTH)/testing',
- ],
- 'sources': [
- '<(DEPTH)/testing/googlemock/src/gmock-all.cc',
- '<(DEPTH)/testing/googletest/src/gtest_main.cc',
- ],
- 'direct_dependent_settings': {
- 'include_dirs': [
- '<(DEPTH)/testing/include',
- '<(DEPTH)/testing/googletest/include',
- '<(DEPTH)/testing/googletest',
- '<(DEPTH)/testing/googlemock/include',
- '<(DEPTH)/testing/googlemock',
- '<(DEPTH)/testing',
- ],
- 'defines': ['_VARIADIC_MAX=10', '_SILENCE_TR1_NAMESPACE_DEPRECATION_WARNING'],
- },
- 'defines': ['_VARIADIC_MAX=10', '_SILENCE_TR1_NAMESPACE_DEPRECATION_WARNING'],
- },
-
- ],
-}
diff --git a/src/common/android/include/elf.h b/src/common/android/include/elf.h
index e6f0c672..80e4c835 100644
--- a/src/common/android/include/elf.h
+++ b/src/common/android/include/elf.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2012, Google Inc.
-// All rights reserved.
+// Copyright 2012 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/common/android/include/link.h b/src/common/android/include/link.h
index 4324629d..02d2db26 100644
--- a/src/common/android/include/link.h
+++ b/src/common/android/include/link.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2012, Google Inc.
-// All rights reserved.
+// Copyright 2012 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/common/android/include/stab.h b/src/common/android/include/stab.h
index cd929021..28882445 100644
--- a/src/common/android/include/stab.h
+++ b/src/common/android/include/stab.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2012, Google Inc.
-// All rights reserved.
+// Copyright 2012 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/common/android/include/sys/procfs.h b/src/common/android/include/sys/procfs.h
index 18512436..f7ff9774 100644
--- a/src/common/android/include/sys/procfs.h
+++ b/src/common/android/include/sys/procfs.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2012, Google Inc.
-// All rights reserved.
+// Copyright 2012 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/common/android/include/sys/user.h b/src/common/android/include/sys/user.h
index 9c27ef02..021ec90d 100644
--- a/src/common/android/include/sys/user.h
+++ b/src/common/android/include/sys/user.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2012, Google Inc.
-// All rights reserved.
+// Copyright 2012 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/common/android/testing/include/wchar.h b/src/common/android/testing/include/wchar.h
index 85373fd2..aa17c731 100644
--- a/src/common/android/testing/include/wchar.h
+++ b/src/common/android/testing/include/wchar.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2012, Google Inc.
-// All rights reserved.
+// Copyright 2012 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/common/android/testing/mkdtemp.h b/src/common/android/testing/mkdtemp.h
index b86e2cd7..f05cf653 100644
--- a/src/common/android/testing/mkdtemp.h
+++ b/src/common/android/testing/mkdtemp.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2012, Google Inc.
-// All rights reserved.
+// Copyright 2012 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/common/android/testing/pthread_fixes.h b/src/common/android/testing/pthread_fixes.h
index 20c12084..04bf6369 100644
--- a/src/common/android/testing/pthread_fixes.h
+++ b/src/common/android/testing/pthread_fixes.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2012, Google Inc.
-// All rights reserved.
+// Copyright 2012 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -80,7 +79,7 @@ int pthread_barrier_wait(pthread_barrier_t* barrier) {
return 0;
}
-int pthread_barrier_destroy(pthread_barrier_t *barrier) {
+int pthread_barrier_destroy(pthread_barrier_t* barrier) {
barrier->count = 0;
pthread_cond_destroy(&barrier->cond);
pthread_mutex_destroy(&barrier->mutex);
diff --git a/src/common/basictypes.h b/src/common/basictypes.h
index 9426c1f6..6458a893 100644
--- a/src/common/basictypes.h
+++ b/src/common/basictypes.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2011 Google Inc.
-// All rights reserved.
+// Copyright 2011 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/common/byte_cursor.h b/src/common/byte_cursor.h
index accd54e0..fd0e45ff 100644
--- a/src/common/byte_cursor.h
+++ b/src/common/byte_cursor.h
@@ -1,7 +1,6 @@
// -*- mode: c++ -*-
-// Copyright (c) 2010, Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -13,7 +12,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -52,16 +51,16 @@ namespace google_breakpad {
// A buffer holding a series of bytes.
struct ByteBuffer {
ByteBuffer() : start(0), end(0) { }
- ByteBuffer(const uint8_t *set_start, size_t set_size)
+ ByteBuffer(const uint8_t* set_start, size_t set_size)
: start(set_start), end(set_start + set_size) { }
~ByteBuffer() { };
// Equality operators. Useful in unit tests, and when we're using
// ByteBuffers to refer to regions of a larger buffer.
- bool operator==(const ByteBuffer &that) const {
+ bool operator==(const ByteBuffer& that) const {
return start == that.start && end == that.end;
}
- bool operator!=(const ByteBuffer &that) const {
+ bool operator!=(const ByteBuffer& that) const {
return start != that.start || end != that.end;
}
@@ -71,7 +70,8 @@ struct ByteBuffer {
return end - start;
}
- const uint8_t *start, *end;
+ const uint8_t* start;
+ const uint8_t* end;
};
// A cursor pointing into a ByteBuffer that can parse numbers of various
@@ -82,8 +82,8 @@ class ByteCursor {
public:
// Create a cursor reading bytes from the start of BUFFER. By default, the
// cursor reads multi-byte values in little-endian form.
- ByteCursor(const ByteBuffer *buffer, bool big_endian = false)
- : buffer_(buffer), here_(buffer->start),
+ ByteCursor(const ByteBuffer* buffer, bool big_endian = false)
+ : buffer_(buffer), here_(buffer->start),
big_endian_(big_endian), complete_(true) { }
// Accessor and setter for this cursor's endianness flag.
@@ -92,8 +92,8 @@ class ByteCursor {
// Accessor and setter for this cursor's current position. The setter
// returns a reference to this cursor.
- const uint8_t *here() const { return here_; }
- ByteCursor &set_here(const uint8_t *here) {
+ const uint8_t* here() const { return here_; }
+ ByteCursor& set_here(const uint8_t* here) {
assert(buffer_->start <= here && here <= buffer_->end);
here_ = here;
return *this;
@@ -116,7 +116,7 @@ class ByteCursor {
// this cursor's complete_ flag, and store a dummy value in *RESULT.
// Return a reference to this cursor.
template<typename T>
- ByteCursor &Read(size_t size, bool is_signed, T *result) {
+ ByteCursor& Read(size_t size, bool is_signed, T* result) {
if (CheckAvailable(size)) {
T v = 0;
if (big_endian_) {
@@ -145,7 +145,7 @@ class ByteCursor {
// read off the end of our buffer, clear this cursor's complete_ flag.
// Return a reference to this cursor.
template<typename T>
- ByteCursor &operator>>(T &result) {
+ ByteCursor& operator>>(T& result) {
bool T_is_signed = (T)-1 < 0;
return Read(sizeof(T), T_is_signed, &result);
}
@@ -154,7 +154,7 @@ class ByteCursor {
// cursor to the end of them. If we read off the end of our buffer,
// clear this cursor's complete_ flag, and set *POINTER to NULL.
// Return a reference to this cursor.
- ByteCursor &Read(uint8_t *buffer, size_t size) {
+ ByteCursor& Read(uint8_t* buffer, size_t size) {
if (CheckAvailable(size)) {
memcpy(buffer, here_, size);
here_ += size;
@@ -166,11 +166,11 @@ class ByteCursor {
// byte buffer does not contain a terminating zero, clear this cursor's
// complete_ flag, and set STR to the empty string. Return a reference to
// this cursor.
- ByteCursor &CString(string *str) {
- const uint8_t *end
- = static_cast<const uint8_t *>(memchr(here_, '\0', Available()));
+ ByteCursor& CString(string* str) {
+ const uint8_t* end
+ = static_cast<const uint8_t*>(memchr(here_, '\0', Available()));
if (end) {
- str->assign(reinterpret_cast<const char *>(here_), end - here_);
+ str->assign(reinterpret_cast<const char*>(here_), end - here_);
here_ = end + 1;
} else {
str->clear();
@@ -193,14 +193,14 @@ class ByteCursor {
//
// - Otherwise, set *STR to a copy of those LIMIT bytes, and advance the
// cursor by LIMIT bytes.
- ByteCursor &CString(string *str, size_t limit) {
+ ByteCursor& CString(string* str, size_t limit) {
if (CheckAvailable(limit)) {
- const uint8_t *end
- = static_cast<const uint8_t *>(memchr(here_, '\0', limit));
+ const uint8_t* end
+ = static_cast<const uint8_t*>(memchr(here_, '\0', limit));
if (end)
- str->assign(reinterpret_cast<const char *>(here_), end - here_);
+ str->assign(reinterpret_cast<const char*>(here_), end - here_);
else
- str->assign(reinterpret_cast<const char *>(here_), limit);
+ str->assign(reinterpret_cast<const char*>(here_), limit);
here_ += limit;
} else {
str->clear();
@@ -213,7 +213,7 @@ class ByteCursor {
// cursor. If we read off the end of our buffer, clear this cursor's
// complete_ flag, and set *POINTER to NULL. Return a reference to this
// cursor.
- ByteCursor &PointTo(const uint8_t **pointer, size_t size = 0) {
+ ByteCursor& PointTo(const uint8_t** pointer, size_t size = 0) {
if (CheckAvailable(size)) {
*pointer = here_;
here_ += size;
@@ -226,7 +226,7 @@ class ByteCursor {
// Skip SIZE bytes at the cursor. If doing so would advance us off
// the end of our buffer, clear this cursor's complete_ flag, and
// set *POINTER to NULL. Return a reference to this cursor.
- ByteCursor &Skip(size_t size) {
+ ByteCursor& Skip(size_t size) {
if (CheckAvailable(size))
here_ += size;
return *this;
@@ -247,10 +247,10 @@ class ByteCursor {
}
// The buffer we're reading bytes from.
- const ByteBuffer *buffer_;
+ const ByteBuffer* buffer_;
// The next byte within buffer_ that we'll read.
- const uint8_t *here_;
+ const uint8_t* here_;
// True if we should read numbers in big-endian form; false if we
// should read in little-endian form.
diff --git a/src/common/byte_cursor_unittest.cc b/src/common/byte_cursor_unittest.cc
index 06bfd89d..00648f76 100644
--- a/src/common/byte_cursor_unittest.cc
+++ b/src/common/byte_cursor_unittest.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2010 Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -593,7 +592,7 @@ TEST(Extractor, Signed4) {
int32_t a;
// For some reason, G++ 4.4.1 complains:
// warning: array subscript is above array bounds
- // in ByteCursor::Read(size_t, bool, T *) as it inlines this call, but
+ // in ByteCursor::Read(size_t, bool, T*) as it inlines this call, but
// I'm not able to see how such a reference would occur.
EXPECT_TRUE(cursor >> a);
EXPECT_EQ(-380377902, a);
@@ -627,7 +626,7 @@ TEST(Extractor, Unsigned4) {
uint32_t a;
// For some reason, G++ 4.4.1 complains:
// warning: array subscript is above array bounds
- // in ByteCursor::Read(size_t, bool, T *) as it inlines this call, but
+ // in ByteCursor::Read(size_t, bool, T*) as it inlines this call, but
// I'm not able to see how such a reference would occur.
EXPECT_TRUE(cursor >> a);
EXPECT_EQ(0xe953e4d2, a);
@@ -718,10 +717,10 @@ TEST(Strings, PointTo) {
ByteBuffer buffer(data, sizeof(data));
ByteCursor cursor(&buffer);
- const uint8_t *received1;
- const uint8_t *received2;
- const uint8_t *received3;
- const uint8_t *received4;
+ const uint8_t* received1;
+ const uint8_t* received2;
+ const uint8_t* received3;
+ const uint8_t* received4;
EXPECT_FALSE(cursor
.PointTo(&received1, 3)
.PointTo(&received2, 3)
diff --git a/src/common/common.gyp b/src/common/common.gyp
deleted file mode 100644
index c1dbb0fe..00000000
--- a/src/common/common.gyp
+++ /dev/null
@@ -1,260 +0,0 @@
-# Copyright 2014 Google Inc. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-# * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-# * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-{
- 'target_defaults': {
- 'target_conditions': [
- ['OS=="mac"', {
- 'defines': ['HAVE_MACH_O_NLIST_H'],
- }],
- ['OS=="linux"', {
- # Assume glibc.
- 'defines': ['HAVE_A_OUT_H', 'HAVE_GETCONTEXT'],
- 'sources!': [
- 'linux/breakpad_getcontext.S',
- 'linux/breakpad_getcontext.h',
- 'linux/breakpad_getcontext_unittest.cc',
- ],
- }],
- ['OS!="android"', {'sources/': [['exclude', '(^|/)android/']]}],
- ['OS!="linux"', {'sources/': [['exclude', '(^|/)linux/']]}],
- ['OS!="mac"', {'sources/': [['exclude', '(^|/)mac/']]}],
- ['OS!="solaris"', {'sources/': [['exclude', '(^|/)solaris/']]}],
- ['OS!="win"', {'sources/': [['exclude', '(^|/)windows/']]}],
- ],
- },
- 'targets': [
- {
- 'target_name': 'common',
- 'type': 'static_library',
- 'sources': [
- 'android/include/elf.h',
- 'android/include/link.h',
- 'android/include/stab.h',
- 'android/include/sys/procfs.h',
- 'android/include/sys/user.h',
- 'android/testing/include/wchar.h',
- 'android/testing/mkdtemp.h',
- 'android/testing/pthread_fixes.h',
- 'android/ucontext_constants.h',
- 'basictypes.h',
- 'byte_cursor.h',
- 'convert_UTF.cc',
- 'convert_UTF.h',
- 'dwarf/bytereader-inl.h',
- 'dwarf/bytereader.cc',
- 'dwarf/bytereader.h',
- 'dwarf/cfi_assembler.cc',
- 'dwarf/cfi_assembler.h',
- 'dwarf/dwarf2diehandler.cc',
- 'dwarf/dwarf2diehandler.h',
- 'dwarf/dwarf2enums.h',
- 'dwarf/dwarf2reader.cc',
- 'dwarf/dwarf2reader.h',
- 'dwarf/dwarf2reader_test_common.h',
- 'dwarf/elf_reader.cc',
- 'dwarf/elf_reader.h',
- 'dwarf/functioninfo.cc',
- 'dwarf/functioninfo.h',
- 'dwarf/line_state_machine.h',
- 'dwarf/types.h',
- 'dwarf_cfi_to_module.cc',
- 'dwarf_cfi_to_module.h',
- 'dwarf_cu_to_module.cc',
- 'dwarf_cu_to_module.h',
- 'dwarf_line_to_module.cc',
- 'dwarf_line_to_module.h',
- 'language.cc',
- 'language.h',
- 'linux/breakpad_getcontext.S',
- 'linux/breakpad_getcontext.h',
- 'linux/crc32.cc',
- 'linux/crc32.h',
- 'linux/dump_symbols.cc',
- 'linux/dump_symbols.h',
- 'linux/eintr_wrapper.h',
- 'linux/elf_core_dump.cc',
- 'linux/elf_core_dump.h',
- 'linux/elf_gnu_compat.h',
- 'linux/elf_symbols_to_module.cc',
- 'linux/elf_symbols_to_module.h',
- 'linux/elfutils-inl.h',
- 'linux/elfutils.cc',
- 'linux/elfutils.h',
- 'linux/file_id.cc',
- 'linux/file_id.h',
- 'linux/google_crashdump_uploader.cc',
- 'linux/google_crashdump_uploader.h',
- 'linux/guid_creator.cc',
- 'linux/guid_creator.h',
- 'linux/http_upload.cc',
- 'linux/http_upload.h',
- 'linux/ignore_ret.h',
- 'linux/libcurl_wrapper.cc',
- 'linux/libcurl_wrapper.h',
- 'linux/linux_libc_support.cc',
- 'linux/linux_libc_support.h',
- 'linux/memory_mapped_file.cc',
- 'linux/memory_mapped_file.h',
- 'linux/safe_readlink.cc',
- 'linux/safe_readlink.h',
- 'linux/symbol_collector_client.cc',
- 'linux/symbol_collector_client.h',
- 'linux/synth_elf.cc',
- 'linux/synth_elf.h',
- 'long_string_dictionary.cc',
- 'long_string_dictionary.h',
- 'mac/arch_utilities.cc',
- 'mac/arch_utilities.h',
- 'mac/bootstrap_compat.cc',
- 'mac/bootstrap_compat.h',
- 'mac/byteswap.h',
- 'mac/dump_syms.h',
- 'mac/dump_syms.cc',
- 'mac/file_id.cc',
- 'mac/file_id.h',
- 'mac/GTMDefines.h',
- 'mac/GTMLogger.h',
- 'mac/GTMLogger.m',
- 'mac/HTTPMultipartUpload.h',
- 'mac/HTTPMultipartUpload.m',
- 'mac/MachIPC.h',
- 'mac/MachIPC.mm',
- 'mac/macho_id.cc',
- 'mac/macho_id.h',
- 'mac/macho_reader.cc',
- 'mac/macho_reader.h',
- 'mac/macho_utilities.cc',
- 'mac/macho_utilities.h',
- 'mac/macho_walker.cc',
- 'mac/macho_walker.h',
- 'mac/scoped_task_suspend-inl.h',
- 'mac/string_utilities.cc',
- 'mac/string_utilities.h',
- 'mac/super_fat_arch.h',
- 'md5.cc',
- 'md5.h',
- 'memory_allocator.h',
- 'memory_range.h',
- 'module.cc',
- 'module.h',
- 'scoped_ptr.h',
- 'simple_string_dictionary.cc',
- 'simple_string_dictionary.h',
- 'solaris/dump_symbols.cc',
- 'solaris/dump_symbols.h',
- 'solaris/file_id.cc',
- 'solaris/file_id.h',
- 'solaris/guid_creator.cc',
- 'solaris/guid_creator.h',
- 'solaris/message_output.h',
- 'stabs_reader.cc',
- 'stabs_reader.h',
- 'stabs_to_module.cc',
- 'stabs_to_module.h',
- 'string_conversion.cc',
- 'string_conversion.h',
- 'symbol_data.h',
- 'test_assembler.cc',
- 'test_assembler.h',
- 'unordered.h',
- 'using_std_string.h',
- 'windows/common_windows.gyp',
- 'windows/dia_util.cc',
- 'windows/dia_util.h',
- 'windows/guid_string.cc',
- 'windows/guid_string.h',
- 'windows/http_upload.cc',
- 'windows/http_upload.h',
- 'windows/omap.cc',
- 'windows/omap.h',
- 'windows/omap_internal.h',
- 'windows/pdb_source_line_writer.cc',
- 'windows/pdb_source_line_writer.h',
- 'windows/string_utils-inl.h',
- 'windows/string_utils.cc',
- ],
- 'include_dirs': [
- '..',
- ],
- },
- {
- 'target_name': 'common_unittests',
- 'type': 'executable',
- 'sources': [
- 'byte_cursor_unittest.cc',
- 'dwarf/bytereader_unittest.cc',
- 'dwarf/dwarf2diehandler_unittest.cc',
- 'dwarf/dwarf2reader_cfi_unittest.cc',
- 'dwarf/dwarf2reader_die_unittest.cc',
- 'dwarf_cfi_to_module_unittest.cc',
- 'dwarf_cu_to_module_unittest.cc',
- 'dwarf_line_to_module_unittest.cc',
- 'linux/breakpad_getcontext_unittest.cc',
- 'linux/dump_symbols_unittest.cc',
- 'linux/elf_core_dump_unittest.cc',
- 'linux/elf_symbols_to_module_unittest.cc',
- 'linux/file_id_unittest.cc',
- 'linux/google_crashdump_uploader_test.cc',
- 'linux/linux_libc_support_unittest.cc',
- 'linux/memory_mapped_file_unittest.cc',
- 'linux/safe_readlink_unittest.cc',
- 'linux/synth_elf_unittest.cc',
- 'linux/tests/auto_testfile.h',
- 'linux/tests/crash_generator.cc',
- 'linux/tests/crash_generator.h',
- 'long_string_dictionary_unittest.cc',
- 'mac/macho_reader_unittest.cc',
- 'memory_allocator_unittest.cc',
- 'memory_range_unittest.cc',
- 'module_unittest.cc',
- 'simple_string_dictionary_unittest.cc',
- 'stabs_reader_unittest.cc',
- 'stabs_to_module_unittest.cc',
- 'string_conversion_unittest.cc',
- 'test_assembler_unittest.cc',
- 'tests/auto_tempdir.h',
- 'tests/file_utils.cc',
- 'tests/file_utils.h',
- 'windows/omap_unittest.cc',
- ],
- 'include_dirs': [
- '..',
- ],
- 'dependencies': [
- 'common',
- '../build/testing.gyp:gmock_main',
- '../build/testing.gyp:gmock',
- '../build/testing.gyp:gtest',
- ],
- 'libraries': [
- '-ldl',
- ],
- },
- ],
-}
diff --git a/src/common/dwarf/bytereader-inl.h b/src/common/dwarf/bytereader-inl.h
index f4c068a2..21026484 100644
--- a/src/common/dwarf/bytereader-inl.h
+++ b/src/common/dwarf/bytereader-inl.h
@@ -1,4 +1,4 @@
-// Copyright 2006 Google Inc. All Rights Reserved.
+// Copyright 2006 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -10,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -34,13 +34,13 @@
#include <assert.h>
#include <stdint.h>
-namespace dwarf2reader {
+namespace google_breakpad {
-inline uint8_t ByteReader::ReadOneByte(const uint8_t *buffer) const {
+inline uint8_t ByteReader::ReadOneByte(const uint8_t* buffer) const {
return buffer[0];
}
-inline uint16_t ByteReader::ReadTwoBytes(const uint8_t *buffer) const {
+inline uint16_t ByteReader::ReadTwoBytes(const uint8_t* buffer) const {
const uint16_t buffer0 = buffer[0];
const uint16_t buffer1 = buffer[1];
if (endian_ == ENDIANNESS_LITTLE) {
@@ -50,7 +50,18 @@ inline uint16_t ByteReader::ReadTwoBytes(const uint8_t *buffer) const {
}
}
-inline uint64_t ByteReader::ReadFourBytes(const uint8_t *buffer) const {
+inline uint64_t ByteReader::ReadThreeBytes(const uint8_t* buffer) const {
+ const uint32_t buffer0 = buffer[0];
+ const uint32_t buffer1 = buffer[1];
+ const uint32_t buffer2 = buffer[2];
+ if (endian_ == ENDIANNESS_LITTLE) {
+ return buffer0 | buffer1 << 8 | buffer2 << 16;
+ } else {
+ return buffer2 | buffer1 << 8 | buffer0 << 16;
+ }
+}
+
+inline uint64_t ByteReader::ReadFourBytes(const uint8_t* buffer) const {
const uint32_t buffer0 = buffer[0];
const uint32_t buffer1 = buffer[1];
const uint32_t buffer2 = buffer[2];
@@ -62,7 +73,7 @@ inline uint64_t ByteReader::ReadFourBytes(const uint8_t *buffer) const {
}
}
-inline uint64_t ByteReader::ReadEightBytes(const uint8_t *buffer) const {
+inline uint64_t ByteReader::ReadEightBytes(const uint8_t* buffer) const {
const uint64_t buffer0 = buffer[0];
const uint64_t buffer1 = buffer[1];
const uint64_t buffer2 = buffer[2];
@@ -84,7 +95,7 @@ inline uint64_t ByteReader::ReadEightBytes(const uint8_t *buffer) const {
// information, plus one bit saying whether the number continues or
// not.
-inline uint64_t ByteReader::ReadUnsignedLEB128(const uint8_t *buffer,
+inline uint64_t ByteReader::ReadUnsignedLEB128(const uint8_t* buffer,
size_t* len) const {
uint64_t result = 0;
size_t num_read = 0;
@@ -109,7 +120,7 @@ inline uint64_t ByteReader::ReadUnsignedLEB128(const uint8_t *buffer,
// Read a signed LEB128 number. These are like regular LEB128
// numbers, except the last byte may have a sign bit set.
-inline int64_t ByteReader::ReadSignedLEB128(const uint8_t *buffer,
+inline int64_t ByteReader::ReadSignedLEB128(const uint8_t* buffer,
size_t* len) const {
int64_t result = 0;
unsigned int shift = 0;
@@ -129,18 +140,18 @@ inline int64_t ByteReader::ReadSignedLEB128(const uint8_t *buffer,
return result;
}
-inline uint64_t ByteReader::ReadOffset(const uint8_t *buffer) const {
+inline uint64_t ByteReader::ReadOffset(const uint8_t* buffer) const {
assert(this->offset_reader_);
return (this->*offset_reader_)(buffer);
}
-inline uint64_t ByteReader::ReadAddress(const uint8_t *buffer) const {
+inline uint64_t ByteReader::ReadAddress(const uint8_t* buffer) const {
assert(this->address_reader_);
return (this->*address_reader_)(buffer);
}
inline void ByteReader::SetCFIDataBase(uint64_t section_base,
- const uint8_t *buffer_base) {
+ const uint8_t* buffer_base) {
section_base_ = section_base;
buffer_base_ = buffer_base;
have_section_base_ = true;
@@ -165,6 +176,6 @@ inline void ByteReader::ClearFunctionBase() {
have_function_base_ = false;
}
-} // namespace dwarf2reader
+} // namespace google_breakpad
#endif // UTIL_DEBUGINFO_BYTEREADER_INL_H__
diff --git a/src/common/dwarf/bytereader.cc b/src/common/dwarf/bytereader.cc
index 0b27dd58..46bed6d0 100644
--- a/src/common/dwarf/bytereader.cc
+++ b/src/common/dwarf/bytereader.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2010 Google Inc. All Rights Reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -10,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -33,7 +33,7 @@
#include "common/dwarf/bytereader-inl.h"
#include "common/dwarf/bytereader.h"
-namespace dwarf2reader {
+namespace google_breakpad {
ByteReader::ByteReader(enum Endianness endian)
:offset_reader_(NULL), address_reader_(NULL), endian_(endian),
@@ -63,7 +63,7 @@ void ByteReader::SetAddressSize(uint8_t size) {
}
}
-uint64_t ByteReader::ReadInitialLength(const uint8_t *start, size_t* len) {
+uint64_t ByteReader::ReadInitialLength(const uint8_t* start, size_t* len) {
const uint64_t initial_length = ReadFourBytes(start);
start += 4;
@@ -101,9 +101,9 @@ bool ByteReader::UsableEncoding(DwarfPointerEncoding encoding) const {
}
}
-uint64_t ByteReader::ReadEncodedPointer(const uint8_t *buffer,
+uint64_t ByteReader::ReadEncodedPointer(const uint8_t* buffer,
DwarfPointerEncoding encoding,
- size_t *len) const {
+ size_t* len) const {
// UsableEncoding doesn't approve of DW_EH_PE_omit, so we shouldn't
// see it here.
assert(encoding != DW_EH_PE_omit);
@@ -130,7 +130,7 @@ uint64_t ByteReader::ReadEncodedPointer(const uint8_t *buffer,
// Round up to the next boundary.
uint64_t aligned = (offset + AddressSize() - 1) & -AddressSize();
// Convert back to a pointer.
- const uint8_t *aligned_buffer = buffer_base_ + (aligned - skew);
+ const uint8_t* aligned_buffer = buffer_base_ + (aligned - skew);
// Finally, store the length and actually fetch the pointer.
*len = aligned_buffer - buffer + AddressSize();
return ReadAddress(aligned_buffer);
@@ -247,4 +247,4 @@ Endianness ByteReader::GetEndianness() const {
return endian_;
}
-} // namespace dwarf2reader
+} // namespace google_breakpad
diff --git a/src/common/dwarf/bytereader.h b/src/common/dwarf/bytereader.h
index 2b37a12d..761eaf68 100644
--- a/src/common/dwarf/bytereader.h
+++ b/src/common/dwarf/bytereader.h
@@ -1,6 +1,6 @@
// -*- mode: C++ -*-
-// Copyright (c) 2010 Google Inc. All Rights Reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -12,7 +12,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -38,7 +38,7 @@
#include "common/dwarf/types.h"
#include "common/dwarf/dwarf2enums.h"
-namespace dwarf2reader {
+namespace google_breakpad {
// We can't use the obvious name of LITTLE_ENDIAN and BIG_ENDIAN
// because it conflicts with a macro
@@ -62,22 +62,27 @@ class ByteReader {
// Read a single byte from BUFFER and return it as an unsigned 8 bit
// number.
- uint8_t ReadOneByte(const uint8_t *buffer) const;
+ uint8_t ReadOneByte(const uint8_t* buffer) const;
// Read two bytes from BUFFER and return them as an unsigned 16 bit
// number, using this ByteReader's endianness.
- uint16_t ReadTwoBytes(const uint8_t *buffer) const;
+ uint16_t ReadTwoBytes(const uint8_t* buffer) const;
+
+ // Read three bytes from BUFFER and return them as an unsigned 64 bit
+ // number, using this ByteReader's endianness. DWARF 5 uses this encoding
+ // for various index-related DW_FORMs.
+ uint64_t ReadThreeBytes(const uint8_t* buffer) const;
// Read four bytes from BUFFER and return them as an unsigned 32 bit
// number, using this ByteReader's endianness. This function returns
// a uint64_t so that it is compatible with ReadAddress and
// ReadOffset. The number it returns will never be outside the range
// of an unsigned 32 bit integer.
- uint64_t ReadFourBytes(const uint8_t *buffer) const;
+ uint64_t ReadFourBytes(const uint8_t* buffer) const;
// Read eight bytes from BUFFER and return them as an unsigned 64
// bit number, using this ByteReader's endianness.
- uint64_t ReadEightBytes(const uint8_t *buffer) const;
+ uint64_t ReadEightBytes(const uint8_t* buffer) const;
// Read an unsigned LEB128 (Little Endian Base 128) number from
// BUFFER and return it as an unsigned 64 bit integer. Set LEN to
@@ -96,7 +101,7 @@ class ByteReader {
// In other words, we break VALUE into groups of seven bits, put
// them in little-endian order, and then write them as eight-bit
// bytes with the high bit on all but the last.
- uint64_t ReadUnsignedLEB128(const uint8_t *buffer, size_t *len) const;
+ uint64_t ReadUnsignedLEB128(const uint8_t* buffer, size_t* len) const;
// Read a signed LEB128 number from BUFFER and return it as an
// signed 64 bit integer. Set LEN to the number of bytes read.
@@ -115,7 +120,7 @@ class ByteReader {
// In other words, we break VALUE into groups of seven bits, put
// them in little-endian order, and then write them as eight-bit
// bytes with the high bit on all but the last.
- int64_t ReadSignedLEB128(const uint8_t *buffer, size_t *len) const;
+ int64_t ReadSignedLEB128(const uint8_t* buffer, size_t* len) const;
// Indicate that addresses on this architecture are SIZE bytes long. SIZE
// must be either 4 or 8. (DWARF allows addresses to be any number of
@@ -138,7 +143,7 @@ class ByteReader {
// Read an address from BUFFER and return it as an unsigned 64 bit
// integer, respecting this ByteReader's endianness and address size. You
// must call SetAddressSize before calling this function.
- uint64_t ReadAddress(const uint8_t *buffer) const;
+ uint64_t ReadAddress(const uint8_t* buffer) const;
// DWARF actually defines two slightly different formats: 32-bit DWARF
// and 64-bit DWARF. This is *not* related to the size of registers or
@@ -175,14 +180,14 @@ class ByteReader {
// - The 32-bit value 0xffffffff, followed by a 64-bit byte count,
// indicating that the data whose length is being measured uses
// the 64-bit DWARF format.
- uint64_t ReadInitialLength(const uint8_t *start, size_t *len);
+ uint64_t ReadInitialLength(const uint8_t* start, size_t* len);
// Read an offset from BUFFER and return it as an unsigned 64 bit
// integer, respecting the ByteReader's endianness. In 32-bit DWARF, the
// offset is 4 bytes long; in 64-bit DWARF, the offset is eight bytes
// long. You must call ReadInitialLength or SetOffsetSize before calling
// this function; see the comments above for details.
- uint64_t ReadOffset(const uint8_t *buffer) const;
+ uint64_t ReadOffset(const uint8_t* buffer) const;
// Return the current offset size, in bytes.
// A return value of 4 indicates that we are reading 32-bit DWARF.
@@ -237,7 +242,7 @@ class ByteReader {
// is BUFFER_BASE. This allows us to find the address that a given
// byte in our buffer would have when loaded into the program the
// data describes. We need this to resolve DW_EH_PE_pcrel pointers.
- void SetCFIDataBase(uint64_t section_base, const uint8_t *buffer_base);
+ void SetCFIDataBase(uint64_t section_base, const uint8_t* buffer_base);
// Indicate that the base address of the program's ".text" section
// is TEXT_BASE. We need this to resolve DW_EH_PE_textrel pointers.
@@ -276,15 +281,15 @@ class ByteReader {
// base address this reader hasn't been given, so you should check
// with ValidEncoding and UsableEncoding first if you would rather
// die in a more helpful way.
- uint64_t ReadEncodedPointer(const uint8_t *buffer,
+ uint64_t ReadEncodedPointer(const uint8_t* buffer,
DwarfPointerEncoding encoding,
- size_t *len) const;
+ size_t* len) const;
Endianness GetEndianness() const;
private:
// Function pointer type for our address and offset readers.
- typedef uint64_t (ByteReader::*AddressReader)(const uint8_t *) const;
+ typedef uint64_t (ByteReader::*AddressReader)(const uint8_t*) const;
// Read an offset from BUFFER and return it as an unsigned 64 bit
// integer. DWARF2/3 define offsets as either 4 or 8 bytes,
@@ -307,9 +312,9 @@ class ByteReader {
bool have_section_base_, have_text_base_, have_data_base_;
bool have_function_base_;
uint64_t section_base_, text_base_, data_base_, function_base_;
- const uint8_t *buffer_base_;
+ const uint8_t* buffer_base_;
};
-} // namespace dwarf2reader
+} // namespace google_breakpad
#endif // COMMON_DWARF_BYTEREADER_H__
diff --git a/src/common/dwarf/bytereader_unittest.cc b/src/common/dwarf/bytereader_unittest.cc
index e66062d1..c23c737b 100644
--- a/src/common/dwarf/bytereader_unittest.cc
+++ b/src/common/dwarf/bytereader_unittest.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2010, Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -29,7 +28,7 @@
// Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com>
-// bytereader_unittest.cc: Unit tests for dwarf2reader::ByteReader
+// bytereader_unittest.cc: Unit tests for google_breakpad::ByteReader
#include <stdint.h>
@@ -41,10 +40,10 @@
#include "common/dwarf/cfi_assembler.h"
#include "common/using_std_string.h"
-using dwarf2reader::ByteReader;
-using dwarf2reader::DwarfPointerEncoding;
-using dwarf2reader::ENDIANNESS_BIG;
-using dwarf2reader::ENDIANNESS_LITTLE;
+using google_breakpad::ByteReader;
+using google_breakpad::DwarfPointerEncoding;
+using google_breakpad::ENDIANNESS_BIG;
+using google_breakpad::ENDIANNESS_LITTLE;
using google_breakpad::CFISection;
using google_breakpad::test_assembler::Label;
using google_breakpad::test_assembler::kBigEndian;
@@ -73,7 +72,7 @@ TEST_F(Reader, SimpleConstructor) {
.LEB128(-0x4f337badf4483f83LL)
.D32(0xfec319c9);
ASSERT_TRUE(section.GetContents(&contents));
- const uint8_t *data = reinterpret_cast<const uint8_t *>(contents.data());
+ const uint8_t* data = reinterpret_cast<const uint8_t*>(contents.data());
EXPECT_EQ(0xc0U, reader.ReadOneByte(data));
EXPECT_EQ(0xcf0dU, reader.ReadTwoBytes(data + 1));
EXPECT_EQ(0x96fdd219U, reader.ReadFourBytes(data + 3));
@@ -91,279 +90,279 @@ TEST_F(Reader, SimpleConstructor) {
TEST_F(Reader, ValidEncodings) {
ByteReader reader(ENDIANNESS_LITTLE);
EXPECT_TRUE(reader.ValidEncoding(
- DwarfPointerEncoding(dwarf2reader::DW_EH_PE_absptr)));
+ DwarfPointerEncoding(google_breakpad::DW_EH_PE_absptr)));
EXPECT_TRUE(reader.ValidEncoding(
- DwarfPointerEncoding(dwarf2reader::DW_EH_PE_omit)));
+ DwarfPointerEncoding(google_breakpad::DW_EH_PE_omit)));
EXPECT_TRUE(reader.ValidEncoding(
- DwarfPointerEncoding(dwarf2reader::DW_EH_PE_aligned)));
+ DwarfPointerEncoding(google_breakpad::DW_EH_PE_aligned)));
EXPECT_TRUE(reader.ValidEncoding(
- DwarfPointerEncoding(dwarf2reader::DW_EH_PE_uleb128)));
+ DwarfPointerEncoding(google_breakpad::DW_EH_PE_uleb128)));
EXPECT_TRUE(reader.ValidEncoding(
- DwarfPointerEncoding(dwarf2reader::DW_EH_PE_udata2)));
+ DwarfPointerEncoding(google_breakpad::DW_EH_PE_udata2)));
EXPECT_TRUE(reader.ValidEncoding(
- DwarfPointerEncoding(dwarf2reader::DW_EH_PE_udata4)));
+ DwarfPointerEncoding(google_breakpad::DW_EH_PE_udata4)));
EXPECT_TRUE(reader.ValidEncoding(
- DwarfPointerEncoding(dwarf2reader::DW_EH_PE_udata8)));
+ DwarfPointerEncoding(google_breakpad::DW_EH_PE_udata8)));
EXPECT_TRUE(reader.ValidEncoding(
- DwarfPointerEncoding(dwarf2reader::DW_EH_PE_sleb128)));
+ DwarfPointerEncoding(google_breakpad::DW_EH_PE_sleb128)));
EXPECT_TRUE(reader.ValidEncoding(
- DwarfPointerEncoding(dwarf2reader::DW_EH_PE_sdata2)));
+ DwarfPointerEncoding(google_breakpad::DW_EH_PE_sdata2)));
EXPECT_TRUE(reader.ValidEncoding(
- DwarfPointerEncoding(dwarf2reader::DW_EH_PE_sdata4)));
+ DwarfPointerEncoding(google_breakpad::DW_EH_PE_sdata4)));
EXPECT_TRUE(reader.ValidEncoding(
- DwarfPointerEncoding(dwarf2reader::DW_EH_PE_sdata8)));
+ DwarfPointerEncoding(google_breakpad::DW_EH_PE_sdata8)));
EXPECT_TRUE(reader.ValidEncoding(
- DwarfPointerEncoding(dwarf2reader::DW_EH_PE_absptr |
- dwarf2reader::DW_EH_PE_pcrel)));
+ DwarfPointerEncoding(google_breakpad::DW_EH_PE_absptr |
+ google_breakpad::DW_EH_PE_pcrel)));
EXPECT_TRUE(reader.ValidEncoding(
- DwarfPointerEncoding(dwarf2reader::DW_EH_PE_uleb128 |
- dwarf2reader::DW_EH_PE_pcrel)));
+ DwarfPointerEncoding(google_breakpad::DW_EH_PE_uleb128 |
+ google_breakpad::DW_EH_PE_pcrel)));
EXPECT_TRUE(reader.ValidEncoding(
- DwarfPointerEncoding(dwarf2reader::DW_EH_PE_udata2 |
- dwarf2reader::DW_EH_PE_pcrel)));
+ DwarfPointerEncoding(google_breakpad::DW_EH_PE_udata2 |
+ google_breakpad::DW_EH_PE_pcrel)));
EXPECT_TRUE(reader.ValidEncoding(
- DwarfPointerEncoding(dwarf2reader::DW_EH_PE_udata4 |
- dwarf2reader::DW_EH_PE_pcrel)));
+ DwarfPointerEncoding(google_breakpad::DW_EH_PE_udata4 |
+ google_breakpad::DW_EH_PE_pcrel)));
EXPECT_TRUE(reader.ValidEncoding(
- DwarfPointerEncoding(dwarf2reader::DW_EH_PE_udata8 |
- dwarf2reader::DW_EH_PE_pcrel)));
+ DwarfPointerEncoding(google_breakpad::DW_EH_PE_udata8 |
+ google_breakpad::DW_EH_PE_pcrel)));
EXPECT_TRUE(reader.ValidEncoding(
- DwarfPointerEncoding(dwarf2reader::DW_EH_PE_sleb128 |
- dwarf2reader::DW_EH_PE_pcrel)));
+ DwarfPointerEncoding(google_breakpad::DW_EH_PE_sleb128 |
+ google_breakpad::DW_EH_PE_pcrel)));
EXPECT_TRUE(reader.ValidEncoding(
- DwarfPointerEncoding(dwarf2reader::DW_EH_PE_sdata2 |
- dwarf2reader::DW_EH_PE_pcrel)));
+ DwarfPointerEncoding(google_breakpad::DW_EH_PE_sdata2 |
+ google_breakpad::DW_EH_PE_pcrel)));
EXPECT_TRUE(reader.ValidEncoding(
- DwarfPointerEncoding(dwarf2reader::DW_EH_PE_sdata4 |
- dwarf2reader::DW_EH_PE_pcrel)));
+ DwarfPointerEncoding(google_breakpad::DW_EH_PE_sdata4 |
+ google_breakpad::DW_EH_PE_pcrel)));
EXPECT_TRUE(reader.ValidEncoding(
- DwarfPointerEncoding(dwarf2reader::DW_EH_PE_sdata8 |
- dwarf2reader::DW_EH_PE_pcrel)));
+ DwarfPointerEncoding(google_breakpad::DW_EH_PE_sdata8 |
+ google_breakpad::DW_EH_PE_pcrel)));
EXPECT_TRUE(reader.ValidEncoding(
- DwarfPointerEncoding(dwarf2reader::DW_EH_PE_absptr |
- dwarf2reader::DW_EH_PE_textrel)));
+ DwarfPointerEncoding(google_breakpad::DW_EH_PE_absptr |
+ google_breakpad::DW_EH_PE_textrel)));
EXPECT_TRUE(reader.ValidEncoding(
- DwarfPointerEncoding(dwarf2reader::DW_EH_PE_uleb128 |
- dwarf2reader::DW_EH_PE_textrel)));
+ DwarfPointerEncoding(google_breakpad::DW_EH_PE_uleb128 |
+ google_breakpad::DW_EH_PE_textrel)));
EXPECT_TRUE(reader.ValidEncoding(
- DwarfPointerEncoding(dwarf2reader::DW_EH_PE_udata2 |
- dwarf2reader::DW_EH_PE_textrel)));
+ DwarfPointerEncoding(google_breakpad::DW_EH_PE_udata2 |
+ google_breakpad::DW_EH_PE_textrel)));
EXPECT_TRUE(reader.ValidEncoding(
- DwarfPointerEncoding(dwarf2reader::DW_EH_PE_udata4 |
- dwarf2reader::DW_EH_PE_textrel)));
+ DwarfPointerEncoding(google_breakpad::DW_EH_PE_udata4 |
+ google_breakpad::DW_EH_PE_textrel)));
EXPECT_TRUE(reader.ValidEncoding(
- DwarfPointerEncoding(dwarf2reader::DW_EH_PE_udata8 |
- dwarf2reader::DW_EH_PE_textrel)));
+ DwarfPointerEncoding(google_breakpad::DW_EH_PE_udata8 |
+ google_breakpad::DW_EH_PE_textrel)));
EXPECT_TRUE(reader.ValidEncoding(
- DwarfPointerEncoding(dwarf2reader::DW_EH_PE_sleb128 |
- dwarf2reader::DW_EH_PE_textrel)));
+ DwarfPointerEncoding(google_breakpad::DW_EH_PE_sleb128 |
+ google_breakpad::DW_EH_PE_textrel)));
EXPECT_TRUE(reader.ValidEncoding(
- DwarfPointerEncoding(dwarf2reader::DW_EH_PE_sdata2 |
- dwarf2reader::DW_EH_PE_textrel)));
+ DwarfPointerEncoding(google_breakpad::DW_EH_PE_sdata2 |
+ google_breakpad::DW_EH_PE_textrel)));
EXPECT_TRUE(reader.ValidEncoding(
- DwarfPointerEncoding(dwarf2reader::DW_EH_PE_sdata4 |
- dwarf2reader::DW_EH_PE_textrel)));
+ DwarfPointerEncoding(google_breakpad::DW_EH_PE_sdata4 |
+ google_breakpad::DW_EH_PE_textrel)));
EXPECT_TRUE(reader.ValidEncoding(
- DwarfPointerEncoding(dwarf2reader::DW_EH_PE_sdata8 |
- dwarf2reader::DW_EH_PE_textrel)));
+ DwarfPointerEncoding(google_breakpad::DW_EH_PE_sdata8 |
+ google_breakpad::DW_EH_PE_textrel)));
EXPECT_TRUE(reader.ValidEncoding(
- DwarfPointerEncoding(dwarf2reader::DW_EH_PE_absptr |
- dwarf2reader::DW_EH_PE_datarel)));
+ DwarfPointerEncoding(google_breakpad::DW_EH_PE_absptr |
+ google_breakpad::DW_EH_PE_datarel)));
EXPECT_TRUE(reader.ValidEncoding(
- DwarfPointerEncoding(dwarf2reader::DW_EH_PE_uleb128 |
- dwarf2reader::DW_EH_PE_datarel)));
+ DwarfPointerEncoding(google_breakpad::DW_EH_PE_uleb128 |
+ google_breakpad::DW_EH_PE_datarel)));
EXPECT_TRUE(reader.ValidEncoding(
- DwarfPointerEncoding(dwarf2reader::DW_EH_PE_udata2 |
- dwarf2reader::DW_EH_PE_datarel)));
+ DwarfPointerEncoding(google_breakpad::DW_EH_PE_udata2 |
+ google_breakpad::DW_EH_PE_datarel)));
EXPECT_TRUE(reader.ValidEncoding(
- DwarfPointerEncoding(dwarf2reader::DW_EH_PE_udata4 |
- dwarf2reader::DW_EH_PE_datarel)));
+ DwarfPointerEncoding(google_breakpad::DW_EH_PE_udata4 |
+ google_breakpad::DW_EH_PE_datarel)));
EXPECT_TRUE(reader.ValidEncoding(
- DwarfPointerEncoding(dwarf2reader::DW_EH_PE_udata8 |
- dwarf2reader::DW_EH_PE_datarel)));
+ DwarfPointerEncoding(google_breakpad::DW_EH_PE_udata8 |
+ google_breakpad::DW_EH_PE_datarel)));
EXPECT_TRUE(reader.ValidEncoding(
- DwarfPointerEncoding(dwarf2reader::DW_EH_PE_sleb128 |
- dwarf2reader::DW_EH_PE_datarel)));
+ DwarfPointerEncoding(google_breakpad::DW_EH_PE_sleb128 |
+ google_breakpad::DW_EH_PE_datarel)));
EXPECT_TRUE(reader.ValidEncoding(
- DwarfPointerEncoding(dwarf2reader::DW_EH_PE_sdata2 |
- dwarf2reader::DW_EH_PE_datarel)));
+ DwarfPointerEncoding(google_breakpad::DW_EH_PE_sdata2 |
+ google_breakpad::DW_EH_PE_datarel)));
EXPECT_TRUE(reader.ValidEncoding(
- DwarfPointerEncoding(dwarf2reader::DW_EH_PE_sdata4 |
- dwarf2reader::DW_EH_PE_datarel)));
+ DwarfPointerEncoding(google_breakpad::DW_EH_PE_sdata4 |
+ google_breakpad::DW_EH_PE_datarel)));
EXPECT_TRUE(reader.ValidEncoding(
- DwarfPointerEncoding(dwarf2reader::DW_EH_PE_sdata8 |
- dwarf2reader::DW_EH_PE_datarel)));
+ DwarfPointerEncoding(google_breakpad::DW_EH_PE_sdata8 |
+ google_breakpad::DW_EH_PE_datarel)));
EXPECT_TRUE(reader.ValidEncoding(
- DwarfPointerEncoding(dwarf2reader::DW_EH_PE_absptr |
- dwarf2reader::DW_EH_PE_funcrel)));
+ DwarfPointerEncoding(google_breakpad::DW_EH_PE_absptr |
+ google_breakpad::DW_EH_PE_funcrel)));
EXPECT_TRUE(reader.ValidEncoding(
- DwarfPointerEncoding(dwarf2reader::DW_EH_PE_uleb128 |
- dwarf2reader::DW_EH_PE_funcrel)));
+ DwarfPointerEncoding(google_breakpad::DW_EH_PE_uleb128 |
+ google_breakpad::DW_EH_PE_funcrel)));
EXPECT_TRUE(reader.ValidEncoding(
- DwarfPointerEncoding(dwarf2reader::DW_EH_PE_udata2 |
- dwarf2reader::DW_EH_PE_funcrel)));
+ DwarfPointerEncoding(google_breakpad::DW_EH_PE_udata2 |
+ google_breakpad::DW_EH_PE_funcrel)));
EXPECT_TRUE(reader.ValidEncoding(
- DwarfPointerEncoding(dwarf2reader::DW_EH_PE_udata4 |
- dwarf2reader::DW_EH_PE_funcrel)));
+ DwarfPointerEncoding(google_breakpad::DW_EH_PE_udata4 |
+ google_breakpad::DW_EH_PE_funcrel)));
EXPECT_TRUE(reader.ValidEncoding(
- DwarfPointerEncoding(dwarf2reader::DW_EH_PE_udata8 |
- dwarf2reader::DW_EH_PE_funcrel)));
+ DwarfPointerEncoding(google_breakpad::DW_EH_PE_udata8 |
+ google_breakpad::DW_EH_PE_funcrel)));
EXPECT_TRUE(reader.ValidEncoding(
- DwarfPointerEncoding(dwarf2reader::DW_EH_PE_sleb128 |
- dwarf2reader::DW_EH_PE_funcrel)));
+ DwarfPointerEncoding(google_breakpad::DW_EH_PE_sleb128 |
+ google_breakpad::DW_EH_PE_funcrel)));
EXPECT_TRUE(reader.ValidEncoding(
- DwarfPointerEncoding(dwarf2reader::DW_EH_PE_sdata2 |
- dwarf2reader::DW_EH_PE_funcrel)));
+ DwarfPointerEncoding(google_breakpad::DW_EH_PE_sdata2 |
+ google_breakpad::DW_EH_PE_funcrel)));
EXPECT_TRUE(reader.ValidEncoding(
- DwarfPointerEncoding(dwarf2reader::DW_EH_PE_sdata4 |
- dwarf2reader::DW_EH_PE_funcrel)));
+ DwarfPointerEncoding(google_breakpad::DW_EH_PE_sdata4 |
+ google_breakpad::DW_EH_PE_funcrel)));
EXPECT_TRUE(reader.ValidEncoding(
- DwarfPointerEncoding(dwarf2reader::DW_EH_PE_sdata8 |
- dwarf2reader::DW_EH_PE_funcrel)));
+ DwarfPointerEncoding(google_breakpad::DW_EH_PE_sdata8 |
+ google_breakpad::DW_EH_PE_funcrel)));
EXPECT_TRUE(reader.ValidEncoding(
- DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect |
- dwarf2reader::DW_EH_PE_absptr |
- dwarf2reader::DW_EH_PE_pcrel)));
+ DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect |
+ google_breakpad::DW_EH_PE_absptr |
+ google_breakpad::DW_EH_PE_pcrel)));
EXPECT_TRUE(reader.ValidEncoding(
- DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect |
- dwarf2reader::DW_EH_PE_uleb128 |
- dwarf2reader::DW_EH_PE_pcrel)));
+ DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect |
+ google_breakpad::DW_EH_PE_uleb128 |
+ google_breakpad::DW_EH_PE_pcrel)));
EXPECT_TRUE(reader.ValidEncoding(
- DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect |
- dwarf2reader::DW_EH_PE_udata2 |
- dwarf2reader::DW_EH_PE_pcrel)));
+ DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect |
+ google_breakpad::DW_EH_PE_udata2 |
+ google_breakpad::DW_EH_PE_pcrel)));
EXPECT_TRUE(reader.ValidEncoding(
- DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect |
- dwarf2reader::DW_EH_PE_udata4 |
- dwarf2reader::DW_EH_PE_pcrel)));
+ DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect |
+ google_breakpad::DW_EH_PE_udata4 |
+ google_breakpad::DW_EH_PE_pcrel)));
EXPECT_TRUE(reader.ValidEncoding(
- DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect |
- dwarf2reader::DW_EH_PE_udata8 |
- dwarf2reader::DW_EH_PE_pcrel)));
+ DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect |
+ google_breakpad::DW_EH_PE_udata8 |
+ google_breakpad::DW_EH_PE_pcrel)));
EXPECT_TRUE(reader.ValidEncoding(
- DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect |
- dwarf2reader::DW_EH_PE_sleb128 |
- dwarf2reader::DW_EH_PE_pcrel)));
+ DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect |
+ google_breakpad::DW_EH_PE_sleb128 |
+ google_breakpad::DW_EH_PE_pcrel)));
EXPECT_TRUE(reader.ValidEncoding(
- DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect |
- dwarf2reader::DW_EH_PE_sdata2 |
- dwarf2reader::DW_EH_PE_pcrel)));
+ DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect |
+ google_breakpad::DW_EH_PE_sdata2 |
+ google_breakpad::DW_EH_PE_pcrel)));
EXPECT_TRUE(reader.ValidEncoding(
- DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect |
- dwarf2reader::DW_EH_PE_sdata4 |
- dwarf2reader::DW_EH_PE_pcrel)));
+ DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect |
+ google_breakpad::DW_EH_PE_sdata4 |
+ google_breakpad::DW_EH_PE_pcrel)));
EXPECT_TRUE(reader.ValidEncoding(
- DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect |
- dwarf2reader::DW_EH_PE_sdata8 |
- dwarf2reader::DW_EH_PE_pcrel)));
+ DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect |
+ google_breakpad::DW_EH_PE_sdata8 |
+ google_breakpad::DW_EH_PE_pcrel)));
EXPECT_TRUE(reader.ValidEncoding(
- DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect |
- dwarf2reader::DW_EH_PE_absptr |
- dwarf2reader::DW_EH_PE_textrel)));
+ DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect |
+ google_breakpad::DW_EH_PE_absptr |
+ google_breakpad::DW_EH_PE_textrel)));
EXPECT_TRUE(reader.ValidEncoding(
- DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect |
- dwarf2reader::DW_EH_PE_uleb128 |
- dwarf2reader::DW_EH_PE_textrel)));
+ DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect |
+ google_breakpad::DW_EH_PE_uleb128 |
+ google_breakpad::DW_EH_PE_textrel)));
EXPECT_TRUE(reader.ValidEncoding(
- DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect |
- dwarf2reader::DW_EH_PE_udata2 |
- dwarf2reader::DW_EH_PE_textrel)));
+ DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect |
+ google_breakpad::DW_EH_PE_udata2 |
+ google_breakpad::DW_EH_PE_textrel)));
EXPECT_TRUE(reader.ValidEncoding(
- DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect |
- dwarf2reader::DW_EH_PE_udata4 |
- dwarf2reader::DW_EH_PE_textrel)));
+ DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect |
+ google_breakpad::DW_EH_PE_udata4 |
+ google_breakpad::DW_EH_PE_textrel)));
EXPECT_TRUE(reader.ValidEncoding(
- DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect |
- dwarf2reader::DW_EH_PE_udata8 |
- dwarf2reader::DW_EH_PE_textrel)));
+ DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect |
+ google_breakpad::DW_EH_PE_udata8 |
+ google_breakpad::DW_EH_PE_textrel)));
EXPECT_TRUE(reader.ValidEncoding(
- DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect |
- dwarf2reader::DW_EH_PE_sleb128 |
- dwarf2reader::DW_EH_PE_textrel)));
+ DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect |
+ google_breakpad::DW_EH_PE_sleb128 |
+ google_breakpad::DW_EH_PE_textrel)));
EXPECT_TRUE(reader.ValidEncoding(
- DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect |
- dwarf2reader::DW_EH_PE_sdata2 |
- dwarf2reader::DW_EH_PE_textrel)));
+ DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect |
+ google_breakpad::DW_EH_PE_sdata2 |
+ google_breakpad::DW_EH_PE_textrel)));
EXPECT_TRUE(reader.ValidEncoding(
- DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect |
- dwarf2reader::DW_EH_PE_sdata4 |
- dwarf2reader::DW_EH_PE_textrel)));
+ DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect |
+ google_breakpad::DW_EH_PE_sdata4 |
+ google_breakpad::DW_EH_PE_textrel)));
EXPECT_TRUE(reader.ValidEncoding(
- DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect |
- dwarf2reader::DW_EH_PE_sdata8 |
- dwarf2reader::DW_EH_PE_textrel)));
+ DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect |
+ google_breakpad::DW_EH_PE_sdata8 |
+ google_breakpad::DW_EH_PE_textrel)));
EXPECT_TRUE(reader.ValidEncoding(
- DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect |
- dwarf2reader::DW_EH_PE_absptr |
- dwarf2reader::DW_EH_PE_datarel)));
+ DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect |
+ google_breakpad::DW_EH_PE_absptr |
+ google_breakpad::DW_EH_PE_datarel)));
EXPECT_TRUE(reader.ValidEncoding(
- DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect |
- dwarf2reader::DW_EH_PE_uleb128 |
- dwarf2reader::DW_EH_PE_datarel)));
+ DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect |
+ google_breakpad::DW_EH_PE_uleb128 |
+ google_breakpad::DW_EH_PE_datarel)));
EXPECT_TRUE(reader.ValidEncoding(
- DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect |
- dwarf2reader::DW_EH_PE_udata2 |
- dwarf2reader::DW_EH_PE_datarel)));
+ DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect |
+ google_breakpad::DW_EH_PE_udata2 |
+ google_breakpad::DW_EH_PE_datarel)));
EXPECT_TRUE(reader.ValidEncoding(
- DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect |
- dwarf2reader::DW_EH_PE_udata4 |
- dwarf2reader::DW_EH_PE_datarel)));
+ DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect |
+ google_breakpad::DW_EH_PE_udata4 |
+ google_breakpad::DW_EH_PE_datarel)));
EXPECT_TRUE(reader.ValidEncoding(
- DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect |
- dwarf2reader::DW_EH_PE_udata8 |
- dwarf2reader::DW_EH_PE_datarel)));
+ DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect |
+ google_breakpad::DW_EH_PE_udata8 |
+ google_breakpad::DW_EH_PE_datarel)));
EXPECT_TRUE(reader.ValidEncoding(
- DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect |
- dwarf2reader::DW_EH_PE_sleb128 |
- dwarf2reader::DW_EH_PE_datarel)));
+ DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect |
+ google_breakpad::DW_EH_PE_sleb128 |
+ google_breakpad::DW_EH_PE_datarel)));
EXPECT_TRUE(reader.ValidEncoding(
- DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect |
- dwarf2reader::DW_EH_PE_sdata2 |
- dwarf2reader::DW_EH_PE_datarel)));
+ DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect |
+ google_breakpad::DW_EH_PE_sdata2 |
+ google_breakpad::DW_EH_PE_datarel)));
EXPECT_TRUE(reader.ValidEncoding(
- DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect |
- dwarf2reader::DW_EH_PE_sdata4 |
- dwarf2reader::DW_EH_PE_datarel)));
+ DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect |
+ google_breakpad::DW_EH_PE_sdata4 |
+ google_breakpad::DW_EH_PE_datarel)));
EXPECT_TRUE(reader.ValidEncoding(
- DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect |
- dwarf2reader::DW_EH_PE_sdata8 |
- dwarf2reader::DW_EH_PE_datarel)));
+ DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect |
+ google_breakpad::DW_EH_PE_sdata8 |
+ google_breakpad::DW_EH_PE_datarel)));
EXPECT_TRUE(reader.ValidEncoding(
- DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect |
- dwarf2reader::DW_EH_PE_absptr |
- dwarf2reader::DW_EH_PE_funcrel)));
+ DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect |
+ google_breakpad::DW_EH_PE_absptr |
+ google_breakpad::DW_EH_PE_funcrel)));
EXPECT_TRUE(reader.ValidEncoding(
- DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect |
- dwarf2reader::DW_EH_PE_uleb128 |
- dwarf2reader::DW_EH_PE_funcrel)));
+ DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect |
+ google_breakpad::DW_EH_PE_uleb128 |
+ google_breakpad::DW_EH_PE_funcrel)));
EXPECT_TRUE(reader.ValidEncoding(
- DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect |
- dwarf2reader::DW_EH_PE_udata2 |
- dwarf2reader::DW_EH_PE_funcrel)));
+ DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect |
+ google_breakpad::DW_EH_PE_udata2 |
+ google_breakpad::DW_EH_PE_funcrel)));
EXPECT_TRUE(reader.ValidEncoding(
- DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect |
- dwarf2reader::DW_EH_PE_udata4 |
- dwarf2reader::DW_EH_PE_funcrel)));
+ DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect |
+ google_breakpad::DW_EH_PE_udata4 |
+ google_breakpad::DW_EH_PE_funcrel)));
EXPECT_TRUE(reader.ValidEncoding(
- DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect |
- dwarf2reader::DW_EH_PE_udata8 |
- dwarf2reader::DW_EH_PE_funcrel)));
+ DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect |
+ google_breakpad::DW_EH_PE_udata8 |
+ google_breakpad::DW_EH_PE_funcrel)));
EXPECT_TRUE(reader.ValidEncoding(
- DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect |
- dwarf2reader::DW_EH_PE_sleb128 |
- dwarf2reader::DW_EH_PE_funcrel)));
+ DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect |
+ google_breakpad::DW_EH_PE_sleb128 |
+ google_breakpad::DW_EH_PE_funcrel)));
EXPECT_TRUE(reader.ValidEncoding(
- DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect |
- dwarf2reader::DW_EH_PE_sdata2 |
- dwarf2reader::DW_EH_PE_funcrel)));
+ DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect |
+ google_breakpad::DW_EH_PE_sdata2 |
+ google_breakpad::DW_EH_PE_funcrel)));
EXPECT_TRUE(reader.ValidEncoding(
- DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect |
- dwarf2reader::DW_EH_PE_sdata4 |
- dwarf2reader::DW_EH_PE_funcrel)));
+ DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect |
+ google_breakpad::DW_EH_PE_sdata4 |
+ google_breakpad::DW_EH_PE_funcrel)));
EXPECT_TRUE(reader.ValidEncoding(
- DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect |
- dwarf2reader::DW_EH_PE_sdata8 |
- dwarf2reader::DW_EH_PE_funcrel)));
+ DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect |
+ google_breakpad::DW_EH_PE_sdata8 |
+ google_breakpad::DW_EH_PE_funcrel)));
EXPECT_FALSE(reader.ValidEncoding(DwarfPointerEncoding(0x05)));
EXPECT_FALSE(reader.ValidEncoding(DwarfPointerEncoding(0x07)));
@@ -380,7 +379,7 @@ TEST_F(ReaderDeathTest, DW_EH_PE_omit) {
static const uint8_t data[] = { 42 };
ByteReader reader(ENDIANNESS_BIG);
reader.SetAddressSize(4);
- EXPECT_DEATH(reader.ReadEncodedPointer(data, dwarf2reader::DW_EH_PE_omit,
+ EXPECT_DEATH(reader.ReadEncodedPointer(data, google_breakpad::DW_EH_PE_omit,
&pointer_size),
"encoding != DW_EH_PE_omit");
}
@@ -390,7 +389,7 @@ TEST_F(Reader, DW_EH_PE_absptr4) {
ByteReader reader(ENDIANNESS_LITTLE);
reader.SetAddressSize(4);
EXPECT_EQ(0x40ea5727U,
- reader.ReadEncodedPointer(data, dwarf2reader::DW_EH_PE_absptr,
+ reader.ReadEncodedPointer(data, google_breakpad::DW_EH_PE_absptr,
&pointer_size));
EXPECT_EQ(4U, pointer_size);
}
@@ -402,7 +401,7 @@ TEST_F(Reader, DW_EH_PE_absptr8) {
ByteReader reader(ENDIANNESS_LITTLE);
reader.SetAddressSize(8);
EXPECT_EQ(0x010598c240ea5727ULL,
- reader.ReadEncodedPointer(data + 1, dwarf2reader::DW_EH_PE_absptr,
+ reader.ReadEncodedPointer(data + 1, google_breakpad::DW_EH_PE_absptr,
&pointer_size));
EXPECT_EQ(8U, pointer_size);
}
@@ -412,7 +411,7 @@ TEST_F(Reader, DW_EH_PE_uleb128) {
ByteReader reader(ENDIANNESS_LITTLE);
reader.SetAddressSize(4);
EXPECT_EQ(0x130201U,
- reader.ReadEncodedPointer(data, dwarf2reader::DW_EH_PE_uleb128,
+ reader.ReadEncodedPointer(data, google_breakpad::DW_EH_PE_uleb128,
&pointer_size));
EXPECT_EQ(3U, pointer_size);
}
@@ -422,7 +421,7 @@ TEST_F(Reader, DW_EH_PE_udata2) {
ByteReader reader(ENDIANNESS_BIG);
reader.SetAddressSize(4);
EXPECT_EQ(0xf48dU,
- reader.ReadEncodedPointer(data, dwarf2reader::DW_EH_PE_udata2,
+ reader.ReadEncodedPointer(data, google_breakpad::DW_EH_PE_udata2,
&pointer_size));
EXPECT_EQ(2U, pointer_size);
}
@@ -432,7 +431,7 @@ TEST_F(Reader, DW_EH_PE_udata4) {
ByteReader reader(ENDIANNESS_BIG);
reader.SetAddressSize(8);
EXPECT_EQ(0xa5628f8b,
- reader.ReadEncodedPointer(data + 2, dwarf2reader::DW_EH_PE_udata4,
+ reader.ReadEncodedPointer(data + 2, google_breakpad::DW_EH_PE_udata4,
&pointer_size));
EXPECT_EQ(4U, pointer_size);
}
@@ -444,7 +443,7 @@ TEST_F(Reader, DW_EH_PE_udata8Addr8) {
ByteReader reader(ENDIANNESS_LITTLE);
reader.SetAddressSize(8);
EXPECT_EQ(0x8fed199f69047304ULL,
- reader.ReadEncodedPointer(data + 1, dwarf2reader::DW_EH_PE_udata8,
+ reader.ReadEncodedPointer(data + 1, google_breakpad::DW_EH_PE_udata8,
&pointer_size));
EXPECT_EQ(8U, pointer_size);
}
@@ -456,7 +455,7 @@ TEST_F(Reader, DW_EH_PE_udata8Addr4) {
ByteReader reader(ENDIANNESS_LITTLE);
reader.SetAddressSize(4);
EXPECT_EQ(0x69047304ULL,
- reader.ReadEncodedPointer(data + 1, dwarf2reader::DW_EH_PE_udata8,
+ reader.ReadEncodedPointer(data + 1, google_breakpad::DW_EH_PE_udata8,
&pointer_size));
EXPECT_EQ(8U, pointer_size);
}
@@ -466,7 +465,7 @@ TEST_F(Reader, DW_EH_PE_sleb128) {
ByteReader reader(ENDIANNESS_BIG);
reader.SetAddressSize(4);
EXPECT_EQ(-0x030201U & 0xffffffff,
- reader.ReadEncodedPointer(data + 1, dwarf2reader::DW_EH_PE_sleb128,
+ reader.ReadEncodedPointer(data + 1, google_breakpad::DW_EH_PE_sleb128,
&pointer_size));
EXPECT_EQ(3U, pointer_size);
}
@@ -476,7 +475,7 @@ TEST_F(Reader, DW_EH_PE_sdata2) {
ByteReader reader(ENDIANNESS_LITTLE);
reader.SetAddressSize(8);
EXPECT_EQ(0xffffffffffffbfb9ULL,
- reader.ReadEncodedPointer(data, dwarf2reader::DW_EH_PE_sdata2,
+ reader.ReadEncodedPointer(data, google_breakpad::DW_EH_PE_sdata2,
&pointer_size));
EXPECT_EQ(2U, pointer_size);
}
@@ -486,7 +485,7 @@ TEST_F(Reader, DW_EH_PE_sdata4) {
ByteReader reader(ENDIANNESS_LITTLE);
reader.SetAddressSize(8);
EXPECT_EQ(0xffffffffadc2b8f2ULL,
- reader.ReadEncodedPointer(data + 2, dwarf2reader::DW_EH_PE_sdata4,
+ reader.ReadEncodedPointer(data + 2, google_breakpad::DW_EH_PE_sdata4,
&pointer_size));
EXPECT_EQ(4U, pointer_size);
}
@@ -498,7 +497,7 @@ TEST_F(Reader, DW_EH_PE_sdata8) {
ByteReader reader(ENDIANNESS_LITTLE);
reader.SetAddressSize(8);
EXPECT_EQ(0x87269b0ce0795766ULL,
- reader.ReadEncodedPointer(data + 1, dwarf2reader::DW_EH_PE_sdata8,
+ reader.ReadEncodedPointer(data + 1, google_breakpad::DW_EH_PE_sdata8,
&pointer_size));
EXPECT_EQ(8U, pointer_size);
}
@@ -510,8 +509,8 @@ TEST_F(Reader, DW_EH_PE_pcrel) {
ByteReader reader(ENDIANNESS_BIG);
reader.SetAddressSize(4);
DwarfPointerEncoding encoding =
- DwarfPointerEncoding(dwarf2reader::DW_EH_PE_pcrel
- | dwarf2reader::DW_EH_PE_absptr);
+ DwarfPointerEncoding(google_breakpad::DW_EH_PE_pcrel
+ | google_breakpad::DW_EH_PE_absptr);
reader.SetCFIDataBase(0x89951377, data);
EXPECT_EQ(0x89951377 + 3 + 0x14c8c402,
reader.ReadEncodedPointer(data + 3, encoding, &pointer_size));
@@ -526,8 +525,8 @@ TEST_F(Reader, DW_EH_PE_textrel) {
reader.SetAddressSize(4);
reader.SetTextBase(0xb91beaf0);
DwarfPointerEncoding encoding =
- DwarfPointerEncoding(dwarf2reader::DW_EH_PE_textrel
- | dwarf2reader::DW_EH_PE_sdata2);
+ DwarfPointerEncoding(google_breakpad::DW_EH_PE_textrel
+ | google_breakpad::DW_EH_PE_sdata2);
EXPECT_EQ((0xb91beaf0 + 0xffffc917) & 0xffffffff,
reader.ReadEncodedPointer(data + 3, encoding, &pointer_size));
EXPECT_EQ(2U, pointer_size);
@@ -541,8 +540,8 @@ TEST_F(Reader, DW_EH_PE_datarel) {
reader.SetAddressSize(8);
reader.SetDataBase(0xbef308bd25ce74f0ULL);
DwarfPointerEncoding encoding =
- DwarfPointerEncoding(dwarf2reader::DW_EH_PE_datarel
- | dwarf2reader::DW_EH_PE_sleb128);
+ DwarfPointerEncoding(google_breakpad::DW_EH_PE_datarel
+ | google_breakpad::DW_EH_PE_sleb128);
EXPECT_EQ(0xbef308bd25ce74f0ULL + 0xfffffffffffa013bULL,
reader.ReadEncodedPointer(data + 2, encoding, &pointer_size));
EXPECT_EQ(3U, pointer_size);
@@ -556,8 +555,8 @@ TEST_F(Reader, DW_EH_PE_funcrel) {
reader.SetAddressSize(4);
reader.SetFunctionBase(0x823c3520);
DwarfPointerEncoding encoding =
- DwarfPointerEncoding(dwarf2reader::DW_EH_PE_funcrel
- | dwarf2reader::DW_EH_PE_udata2);
+ DwarfPointerEncoding(google_breakpad::DW_EH_PE_funcrel
+ | google_breakpad::DW_EH_PE_udata2);
EXPECT_EQ(0x823c3520 + 0xd148,
reader.ReadEncodedPointer(data + 5, encoding, &pointer_size));
EXPECT_EQ(2U, pointer_size);
@@ -567,48 +566,48 @@ TEST(UsableBase, CFI) {
static const uint8_t data[] = { 0x42 };
ByteReader reader(ENDIANNESS_BIG);
reader.SetCFIDataBase(0xb31cbd20, data);
- EXPECT_TRUE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_absptr));
- EXPECT_TRUE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_pcrel));
- EXPECT_FALSE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_textrel));
- EXPECT_FALSE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_datarel));
- EXPECT_FALSE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_funcrel));
- EXPECT_FALSE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_omit));
+ EXPECT_TRUE(reader.UsableEncoding(google_breakpad::DW_EH_PE_absptr));
+ EXPECT_TRUE(reader.UsableEncoding(google_breakpad::DW_EH_PE_pcrel));
+ EXPECT_FALSE(reader.UsableEncoding(google_breakpad::DW_EH_PE_textrel));
+ EXPECT_FALSE(reader.UsableEncoding(google_breakpad::DW_EH_PE_datarel));
+ EXPECT_FALSE(reader.UsableEncoding(google_breakpad::DW_EH_PE_funcrel));
+ EXPECT_FALSE(reader.UsableEncoding(google_breakpad::DW_EH_PE_omit));
EXPECT_FALSE(reader.UsableEncoding(DwarfPointerEncoding(0x60)));
}
TEST(UsableBase, Text) {
ByteReader reader(ENDIANNESS_BIG);
reader.SetTextBase(0xa899ccb9);
- EXPECT_TRUE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_absptr));
- EXPECT_FALSE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_pcrel));
- EXPECT_TRUE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_textrel));
- EXPECT_FALSE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_datarel));
- EXPECT_FALSE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_funcrel));
- EXPECT_FALSE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_omit));
+ EXPECT_TRUE(reader.UsableEncoding(google_breakpad::DW_EH_PE_absptr));
+ EXPECT_FALSE(reader.UsableEncoding(google_breakpad::DW_EH_PE_pcrel));
+ EXPECT_TRUE(reader.UsableEncoding(google_breakpad::DW_EH_PE_textrel));
+ EXPECT_FALSE(reader.UsableEncoding(google_breakpad::DW_EH_PE_datarel));
+ EXPECT_FALSE(reader.UsableEncoding(google_breakpad::DW_EH_PE_funcrel));
+ EXPECT_FALSE(reader.UsableEncoding(google_breakpad::DW_EH_PE_omit));
EXPECT_FALSE(reader.UsableEncoding(DwarfPointerEncoding(0x60)));
}
TEST(UsableBase, Data) {
ByteReader reader(ENDIANNESS_BIG);
reader.SetDataBase(0xf7b10bcd);
- EXPECT_TRUE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_absptr));
- EXPECT_FALSE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_pcrel));
- EXPECT_FALSE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_textrel));
- EXPECT_TRUE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_datarel));
- EXPECT_FALSE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_funcrel));
- EXPECT_FALSE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_omit));
+ EXPECT_TRUE(reader.UsableEncoding(google_breakpad::DW_EH_PE_absptr));
+ EXPECT_FALSE(reader.UsableEncoding(google_breakpad::DW_EH_PE_pcrel));
+ EXPECT_FALSE(reader.UsableEncoding(google_breakpad::DW_EH_PE_textrel));
+ EXPECT_TRUE(reader.UsableEncoding(google_breakpad::DW_EH_PE_datarel));
+ EXPECT_FALSE(reader.UsableEncoding(google_breakpad::DW_EH_PE_funcrel));
+ EXPECT_FALSE(reader.UsableEncoding(google_breakpad::DW_EH_PE_omit));
EXPECT_FALSE(reader.UsableEncoding(DwarfPointerEncoding(0x60)));
}
TEST(UsableBase, Function) {
ByteReader reader(ENDIANNESS_BIG);
reader.SetFunctionBase(0xc2c0ed81);
- EXPECT_TRUE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_absptr));
- EXPECT_FALSE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_pcrel));
- EXPECT_FALSE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_textrel));
- EXPECT_FALSE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_datarel));
- EXPECT_TRUE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_funcrel));
- EXPECT_FALSE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_omit));
+ EXPECT_TRUE(reader.UsableEncoding(google_breakpad::DW_EH_PE_absptr));
+ EXPECT_FALSE(reader.UsableEncoding(google_breakpad::DW_EH_PE_pcrel));
+ EXPECT_FALSE(reader.UsableEncoding(google_breakpad::DW_EH_PE_textrel));
+ EXPECT_FALSE(reader.UsableEncoding(google_breakpad::DW_EH_PE_datarel));
+ EXPECT_TRUE(reader.UsableEncoding(google_breakpad::DW_EH_PE_funcrel));
+ EXPECT_FALSE(reader.UsableEncoding(google_breakpad::DW_EH_PE_omit));
EXPECT_FALSE(reader.UsableEncoding(DwarfPointerEncoding(0x60)));
}
@@ -616,12 +615,12 @@ TEST(UsableBase, ClearFunction) {
ByteReader reader(ENDIANNESS_BIG);
reader.SetFunctionBase(0xc2c0ed81);
reader.ClearFunctionBase();
- EXPECT_TRUE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_absptr));
- EXPECT_FALSE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_pcrel));
- EXPECT_FALSE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_textrel));
- EXPECT_FALSE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_datarel));
- EXPECT_FALSE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_funcrel));
- EXPECT_FALSE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_omit));
+ EXPECT_TRUE(reader.UsableEncoding(google_breakpad::DW_EH_PE_absptr));
+ EXPECT_FALSE(reader.UsableEncoding(google_breakpad::DW_EH_PE_pcrel));
+ EXPECT_FALSE(reader.UsableEncoding(google_breakpad::DW_EH_PE_textrel));
+ EXPECT_FALSE(reader.UsableEncoding(google_breakpad::DW_EH_PE_datarel));
+ EXPECT_FALSE(reader.UsableEncoding(google_breakpad::DW_EH_PE_funcrel));
+ EXPECT_FALSE(reader.UsableEncoding(google_breakpad::DW_EH_PE_omit));
EXPECT_FALSE(reader.UsableEncoding(DwarfPointerEncoding(0x60)));
}
@@ -641,7 +640,7 @@ class Aligned: public AlignedFixture, public Test { };
TEST_F(Aligned, DW_EH_PE_aligned0) {
reader.SetCFIDataBase(0xb440305c, data);
EXPECT_EQ(0xfe6e93d8U,
- reader.ReadEncodedPointer(data, dwarf2reader::DW_EH_PE_aligned,
+ reader.ReadEncodedPointer(data, google_breakpad::DW_EH_PE_aligned,
&pointer_size));
EXPECT_EQ(4U, pointer_size);
}
@@ -649,7 +648,7 @@ TEST_F(Aligned, DW_EH_PE_aligned0) {
TEST_F(Aligned, DW_EH_PE_aligned1) {
reader.SetCFIDataBase(0xb440305d, data);
EXPECT_EQ(0xd834d51cU,
- reader.ReadEncodedPointer(data, dwarf2reader::DW_EH_PE_aligned,
+ reader.ReadEncodedPointer(data, google_breakpad::DW_EH_PE_aligned,
&pointer_size));
EXPECT_EQ(7U, pointer_size);
}
@@ -657,7 +656,7 @@ TEST_F(Aligned, DW_EH_PE_aligned1) {
TEST_F(Aligned, DW_EH_PE_aligned2) {
reader.SetCFIDataBase(0xb440305e, data);
EXPECT_EQ(0x93d834d5U,
- reader.ReadEncodedPointer(data, dwarf2reader::DW_EH_PE_aligned,
+ reader.ReadEncodedPointer(data, google_breakpad::DW_EH_PE_aligned,
&pointer_size));
EXPECT_EQ(6U, pointer_size);
}
@@ -665,7 +664,7 @@ TEST_F(Aligned, DW_EH_PE_aligned2) {
TEST_F(Aligned, DW_EH_PE_aligned3) {
reader.SetCFIDataBase(0xb440305f, data);
EXPECT_EQ(0x6e93d834U,
- reader.ReadEncodedPointer(data, dwarf2reader::DW_EH_PE_aligned,
+ reader.ReadEncodedPointer(data, google_breakpad::DW_EH_PE_aligned,
&pointer_size));
EXPECT_EQ(5U, pointer_size);
}
@@ -674,7 +673,7 @@ TEST_F(Aligned, DW_EH_PE_aligned11) {
reader.SetCFIDataBase(0xb4403061, data);
EXPECT_EQ(0xd834d51cU,
reader.ReadEncodedPointer(data + 1,
- dwarf2reader::DW_EH_PE_aligned,
+ google_breakpad::DW_EH_PE_aligned,
&pointer_size));
EXPECT_EQ(6U, pointer_size);
}
@@ -683,7 +682,7 @@ TEST_F(Aligned, DW_EH_PE_aligned30) {
reader.SetCFIDataBase(0xb4403063, data);
EXPECT_EQ(0x6e93d834U,
reader.ReadEncodedPointer(data + 1,
- dwarf2reader::DW_EH_PE_aligned,
+ google_breakpad::DW_EH_PE_aligned,
&pointer_size));
EXPECT_EQ(4U, pointer_size);
}
@@ -692,7 +691,7 @@ TEST_F(Aligned, DW_EH_PE_aligned23) {
reader.SetCFIDataBase(0xb4403062, data);
EXPECT_EQ(0x1cd3ac2bU,
reader.ReadEncodedPointer(data + 3,
- dwarf2reader::DW_EH_PE_aligned,
+ google_breakpad::DW_EH_PE_aligned,
&pointer_size));
EXPECT_EQ(7U, pointer_size);
}
@@ -701,7 +700,7 @@ TEST_F(Aligned, DW_EH_PE_aligned03) {
reader.SetCFIDataBase(0xb4403064, data);
EXPECT_EQ(0x34d51cd3U,
reader.ReadEncodedPointer(data + 3,
- dwarf2reader::DW_EH_PE_aligned,
+ google_breakpad::DW_EH_PE_aligned,
&pointer_size));
EXPECT_EQ(5U, pointer_size);
}
diff --git a/src/common/dwarf/cfi_assembler.cc b/src/common/dwarf/cfi_assembler.cc
index 2dc22085..9ed979b4 100644
--- a/src/common/dwarf/cfi_assembler.cc
+++ b/src/common/dwarf/cfi_assembler.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2010, Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -38,14 +37,12 @@
#include <stdlib.h>
namespace google_breakpad {
-
-using dwarf2reader::DwarfPointerEncoding;
-CFISection &CFISection::CIEHeader(uint64_t code_alignment_factor,
+CFISection& CFISection::CIEHeader(uint64_t code_alignment_factor,
int data_alignment_factor,
unsigned return_address_register,
uint8_t version,
- const string &augmentation,
+ const string& augmentation,
bool dwarf64,
uint8_t address_size,
uint8_t segment_size) {
@@ -78,7 +75,7 @@ CFISection &CFISection::CIEHeader(uint64_t code_alignment_factor,
return *this;
}
-CFISection &CFISection::FDEHeader(Label cie_pointer,
+CFISection& CFISection::FDEHeader(Label cie_pointer,
uint64_t initial_location,
uint64_t address_range,
bool dwarf64) {
@@ -113,9 +110,9 @@ CFISection &CFISection::FDEHeader(Label cie_pointer,
return *this;
}
-CFISection &CFISection::FinishEntry() {
+CFISection& CFISection::FinishEntry() {
assert(entry_length_);
- Align(address_size_, dwarf2reader::DW_CFA_nop);
+ Align(address_size_, DW_CFA_nop);
entry_length_->length = Here() - entry_length_->start;
delete entry_length_;
entry_length_ = NULL;
@@ -123,28 +120,28 @@ CFISection &CFISection::FinishEntry() {
return *this;
}
-CFISection &CFISection::EncodedPointer(uint64_t address,
+CFISection& CFISection::EncodedPointer(uint64_t address,
DwarfPointerEncoding encoding,
- const EncodedPointerBases &bases) {
+ const EncodedPointerBases& bases) {
// Omitted data is extremely easy to emit.
- if (encoding == dwarf2reader::DW_EH_PE_omit)
+ if (encoding == DW_EH_PE_omit)
return *this;
- // If (encoding & dwarf2reader::DW_EH_PE_indirect) != 0, then we assume
+ // If (encoding & DW_EH_PE_indirect) != 0, then we assume
// that ADDRESS is the address at which the pointer is stored --- in
// other words, that bit has no effect on how we write the pointer.
- encoding = DwarfPointerEncoding(encoding & ~dwarf2reader::DW_EH_PE_indirect);
+ encoding = DwarfPointerEncoding(encoding & ~DW_EH_PE_indirect);
// Find the base address to which this pointer is relative. The upper
// nybble of the encoding specifies this.
uint64_t base;
switch (encoding & 0xf0) {
- case dwarf2reader::DW_EH_PE_absptr: base = 0; break;
- case dwarf2reader::DW_EH_PE_pcrel: base = bases.cfi + Size(); break;
- case dwarf2reader::DW_EH_PE_textrel: base = bases.text; break;
- case dwarf2reader::DW_EH_PE_datarel: base = bases.data; break;
- case dwarf2reader::DW_EH_PE_funcrel: base = fde_start_address_; break;
- case dwarf2reader::DW_EH_PE_aligned: base = 0; break;
+ case DW_EH_PE_absptr: base = 0; break;
+ case DW_EH_PE_pcrel: base = bases.cfi + Size(); break;
+ case DW_EH_PE_textrel: base = bases.text; break;
+ case DW_EH_PE_datarel: base = bases.data; break;
+ case DW_EH_PE_funcrel: base = fde_start_address_; break;
+ case DW_EH_PE_aligned: base = 0; break;
default: abort();
};
@@ -153,7 +150,7 @@ CFISection &CFISection::EncodedPointer(uint64_t address,
address -= base;
// Align the pointer, if required.
- if ((encoding & 0xf0) == dwarf2reader::DW_EH_PE_aligned)
+ if ((encoding & 0xf0) == DW_EH_PE_aligned)
Align(AddressSize());
// Append ADDRESS to this section in the appropriate form. For the
@@ -161,30 +158,30 @@ CFISection &CFISection::EncodedPointer(uint64_t address,
// unsigned encodings, because ADDRESS has already been extended to 64
// bits before it was passed to us.
switch (encoding & 0x0f) {
- case dwarf2reader::DW_EH_PE_absptr:
+ case DW_EH_PE_absptr:
Address(address);
break;
- case dwarf2reader::DW_EH_PE_uleb128:
+ case DW_EH_PE_uleb128:
ULEB128(address);
break;
- case dwarf2reader::DW_EH_PE_sleb128:
+ case DW_EH_PE_sleb128:
LEB128(address);
break;
- case dwarf2reader::DW_EH_PE_udata2:
- case dwarf2reader::DW_EH_PE_sdata2:
+ case DW_EH_PE_udata2:
+ case DW_EH_PE_sdata2:
D16(address);
break;
- case dwarf2reader::DW_EH_PE_udata4:
- case dwarf2reader::DW_EH_PE_sdata4:
+ case DW_EH_PE_udata4:
+ case DW_EH_PE_sdata4:
D32(address);
break;
- case dwarf2reader::DW_EH_PE_udata8:
- case dwarf2reader::DW_EH_PE_sdata8:
+ case DW_EH_PE_udata8:
+ case DW_EH_PE_sdata8:
D64(address);
break;
diff --git a/src/common/dwarf/cfi_assembler.h b/src/common/dwarf/cfi_assembler.h
index bd7354d1..a33d5d84 100644
--- a/src/common/dwarf/cfi_assembler.h
+++ b/src/common/dwarf/cfi_assembler.h
@@ -1,7 +1,6 @@
// -*- mode: C++ -*-
-// Copyright (c) 2010, Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -13,7 +12,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -46,8 +45,6 @@
namespace google_breakpad {
-using dwarf2reader::DwarfPointerEncoding;
-using google_breakpad::test_assembler::Endianness;
using google_breakpad::test_assembler::Label;
using google_breakpad::test_assembler::Section;
@@ -95,10 +92,10 @@ class CFISection: public Section {
// true, use the .eh_frame format, as described by the Linux
// Standards Base Core Specification, instead of the DWARF CFI
// format.
- CFISection(Endianness endianness, size_t address_size,
+ CFISection(google_breakpad::test_assembler::Endianness endianness, size_t address_size,
bool eh_frame = false)
: Section(endianness), address_size_(address_size), eh_frame_(eh_frame),
- pointer_encoding_(dwarf2reader::DW_EH_PE_absptr),
+ pointer_encoding_(DW_EH_PE_absptr),
encoded_pointer_bases_(), entry_length_(NULL), in_fde_(false) {
// The 'start', 'Here', and 'Mark' members of a CFISection all refer
// to section offsets.
@@ -120,7 +117,7 @@ class CFISection: public Section {
// Use the addresses in BASES as the base addresses for encoded
// pointers in subsequent calls to FDEHeader or EncodedPointer.
// This function makes a copy of BASES.
- void SetEncodedPointerBases(const EncodedPointerBases &bases) {
+ void SetEncodedPointerBases(const EncodedPointerBases& bases) {
encoded_pointer_bases_ = bases;
}
@@ -133,11 +130,11 @@ class CFISection: public Section {
// Before calling this function, you will typically want to use Mark
// or Here to make a label to pass to FDEHeader that refers to this
// CIE's position in the section.
- CFISection &CIEHeader(uint64_t code_alignment_factor,
+ CFISection& CIEHeader(uint64_t code_alignment_factor,
int data_alignment_factor,
unsigned return_address_register,
uint8_t version = 3,
- const string &augmentation = "",
+ const string& augmentation = "",
bool dwarf64 = false,
uint8_t address_size = 8,
uint8_t segment_size = 0);
@@ -152,7 +149,7 @@ class CFISection: public Section {
// 0xffffff00 bytes. (The "initial length" is always a 32-bit
// value.) Nor does it support .debug_frame sections longer than
// 0xffffff00 bytes.
- CFISection &FDEHeader(Label cie_pointer,
+ CFISection& FDEHeader(Label cie_pointer,
uint64_t initial_location,
uint64_t address_range,
bool dwarf64 = false);
@@ -161,11 +158,11 @@ class CFISection: public Section {
// started, after padding with DW_CFA_nops for alignment. This
// defines the label representing the entry's length, cited in the
// entry's header. Return a reference to this section.
- CFISection &FinishEntry();
+ CFISection& FinishEntry();
// Append the contents of BLOCK as a DW_FORM_block value: an
// unsigned LEB128 length, followed by that many bytes of data.
- CFISection &Block(const string &block) {
+ CFISection& Block(const string& block) {
ULEB128(block.size());
Append(block);
return *this;
@@ -173,11 +170,11 @@ class CFISection: public Section {
// Append ADDRESS to this section, in the appropriate size and
// endianness. Return a reference to this section.
- CFISection &Address(uint64_t address) {
+ CFISection& Address(uint64_t address) {
Section::Append(endianness(), address_size_, address);
return *this;
}
- CFISection &Address(Label address) {
+ CFISection& Address(Label address) {
Section::Append(endianness(), address_size_, address);
return *this;
}
@@ -191,26 +188,26 @@ class CFISection: public Section {
//
// (C++ doesn't let me use default arguments here, because I want to
// refer to members of *this in the default argument expression.)
- CFISection &EncodedPointer(uint64_t address) {
+ CFISection& EncodedPointer(uint64_t address) {
return EncodedPointer(address, pointer_encoding_, encoded_pointer_bases_);
}
- CFISection &EncodedPointer(uint64_t address, DwarfPointerEncoding encoding) {
+ CFISection& EncodedPointer(uint64_t address, DwarfPointerEncoding encoding) {
return EncodedPointer(address, encoding, encoded_pointer_bases_);
}
- CFISection &EncodedPointer(uint64_t address, DwarfPointerEncoding encoding,
- const EncodedPointerBases &bases);
+ CFISection& EncodedPointer(uint64_t address, DwarfPointerEncoding encoding,
+ const EncodedPointerBases& bases);
// Restate some member functions, to keep chaining working nicely.
- CFISection &Mark(Label *label) { Section::Mark(label); return *this; }
- CFISection &D8(uint8_t v) { Section::D8(v); return *this; }
- CFISection &D16(uint16_t v) { Section::D16(v); return *this; }
- CFISection &D16(Label v) { Section::D16(v); return *this; }
- CFISection &D32(uint32_t v) { Section::D32(v); return *this; }
- CFISection &D32(const Label &v) { Section::D32(v); return *this; }
- CFISection &D64(uint64_t v) { Section::D64(v); return *this; }
- CFISection &D64(const Label &v) { Section::D64(v); return *this; }
- CFISection &LEB128(long long v) { Section::LEB128(v); return *this; }
- CFISection &ULEB128(uint64_t v) { Section::ULEB128(v); return *this; }
+ CFISection& Mark(Label* label) { Section::Mark(label); return *this; }
+ CFISection& D8(uint8_t v) { Section::D8(v); return *this; }
+ CFISection& D16(uint16_t v) { Section::D16(v); return *this; }
+ CFISection& D16(Label v) { Section::D16(v); return *this; }
+ CFISection& D32(uint32_t v) { Section::D32(v); return *this; }
+ CFISection& D32(const Label& v) { Section::D32(v); return *this; }
+ CFISection& D64(uint64_t v) { Section::D64(v); return *this; }
+ CFISection& D64(const Label& v) { Section::D64(v); return *this; }
+ CFISection& LEB128(long long v) { Section::LEB128(v); return *this; }
+ CFISection& ULEB128(uint64_t v) { Section::ULEB128(v); return *this; }
private:
// A length value that we've appended to the section, but is not yet
diff --git a/src/common/dwarf/dwarf2diehandler.cc b/src/common/dwarf/dwarf2diehandler.cc
index 63845018..ea3ac71c 100644
--- a/src/common/dwarf/dwarf2diehandler.cc
+++ b/src/common/dwarf/dwarf2diehandler.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2010 Google Inc. All Rights Reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -10,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -39,11 +39,11 @@
#include "common/dwarf/dwarf2diehandler.h"
#include "common/using_std_string.h"
-namespace dwarf2reader {
+namespace google_breakpad {
DIEDispatcher::~DIEDispatcher() {
while (!die_handlers_.empty()) {
- HandlerStack &entry = die_handlers_.top();
+ HandlerStack& entry = die_handlers_.top();
if (entry.handler_ != root_handler_)
delete entry.handler_;
die_handlers_.pop();
@@ -60,7 +60,7 @@ bool DIEDispatcher::StartCompilationUnit(uint64_t offset, uint8_t address_size,
bool DIEDispatcher::StartDIE(uint64_t offset, enum DwarfTag tag) {
// The stack entry for the parent of this DIE, if there is one.
- HandlerStack *parent = die_handlers_.empty() ? NULL : &die_handlers_.top();
+ HandlerStack* parent = die_handlers_.empty() ? NULL : &die_handlers_.top();
// Does this call indicate that we're done receiving the parent's
// attributes' values? If so, call its EndAttributes member function.
@@ -78,7 +78,7 @@ bool DIEDispatcher::StartDIE(uint64_t offset, enum DwarfTag tag) {
}
// Find a handler for this DIE.
- DIEHandler *handler;
+ DIEHandler* handler;
if (parent) {
if (parent->handler_)
// Ask the parent to find a handler.
@@ -115,7 +115,7 @@ bool DIEDispatcher::StartDIE(uint64_t offset, enum DwarfTag tag) {
void DIEDispatcher::EndDIE(uint64_t offset) {
assert(!die_handlers_.empty());
- HandlerStack *entry = &die_handlers_.top();
+ HandlerStack* entry = &die_handlers_.top();
if (entry->handler_) {
// This entry had better be the handler for this DIE.
assert(entry->offset_ == offset);
@@ -139,7 +139,7 @@ void DIEDispatcher::ProcessAttributeUnsigned(uint64_t offset,
enum DwarfAttribute attr,
enum DwarfForm form,
uint64_t data) {
- HandlerStack &current = die_handlers_.top();
+ HandlerStack& current = die_handlers_.top();
// This had better be an attribute of the DIE we were meant to handle.
assert(offset == current.offset_);
current.handler_->ProcessAttributeUnsigned(attr, form, data);
@@ -149,7 +149,7 @@ void DIEDispatcher::ProcessAttributeSigned(uint64_t offset,
enum DwarfAttribute attr,
enum DwarfForm form,
int64_t data) {
- HandlerStack &current = die_handlers_.top();
+ HandlerStack& current = die_handlers_.top();
// This had better be an attribute of the DIE we were meant to handle.
assert(offset == current.offset_);
current.handler_->ProcessAttributeSigned(attr, form, data);
@@ -159,7 +159,7 @@ void DIEDispatcher::ProcessAttributeReference(uint64_t offset,
enum DwarfAttribute attr,
enum DwarfForm form,
uint64_t data) {
- HandlerStack &current = die_handlers_.top();
+ HandlerStack& current = die_handlers_.top();
// This had better be an attribute of the DIE we were meant to handle.
assert(offset == current.offset_);
current.handler_->ProcessAttributeReference(attr, form, data);
@@ -168,9 +168,9 @@ void DIEDispatcher::ProcessAttributeReference(uint64_t offset,
void DIEDispatcher::ProcessAttributeBuffer(uint64_t offset,
enum DwarfAttribute attr,
enum DwarfForm form,
- const uint8_t *data,
+ const uint8_t* data,
uint64_t len) {
- HandlerStack &current = die_handlers_.top();
+ HandlerStack& current = die_handlers_.top();
// This had better be an attribute of the DIE we were meant to handle.
assert(offset == current.offset_);
current.handler_->ProcessAttributeBuffer(attr, form, data, len);
@@ -180,7 +180,7 @@ void DIEDispatcher::ProcessAttributeString(uint64_t offset,
enum DwarfAttribute attr,
enum DwarfForm form,
const string& data) {
- HandlerStack &current = die_handlers_.top();
+ HandlerStack& current = die_handlers_.top();
// This had better be an attribute of the DIE we were meant to handle.
assert(offset == current.offset_);
current.handler_->ProcessAttributeString(attr, form, data);
@@ -190,10 +190,10 @@ void DIEDispatcher::ProcessAttributeSignature(uint64_t offset,
enum DwarfAttribute attr,
enum DwarfForm form,
uint64_t signature) {
- HandlerStack &current = die_handlers_.top();
+ HandlerStack& current = die_handlers_.top();
// This had better be an attribute of the DIE we were meant to handle.
assert(offset == current.offset_);
current.handler_->ProcessAttributeSignature(attr, form, signature);
}
-} // namespace dwarf2reader
+} // namespace google_breakpad
diff --git a/src/common/dwarf/dwarf2diehandler.h b/src/common/dwarf/dwarf2diehandler.h
index 871ba436..02c22853 100644
--- a/src/common/dwarf/dwarf2diehandler.h
+++ b/src/common/dwarf/dwarf2diehandler.h
@@ -1,6 +1,6 @@
// -*- mode: c++ -*-
-// Copyright (c) 2010 Google Inc. All Rights Reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -12,7 +12,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -166,7 +166,7 @@
#include "common/dwarf/dwarf2reader.h"
#include "common/using_std_string.h"
-namespace dwarf2reader {
+namespace google_breakpad {
// A base class for handlers for specific DIE types. The series of
// calls made on a DIE handler is as follows:
@@ -208,7 +208,7 @@ class DIEHandler {
uint64_t data) { }
virtual void ProcessAttributeBuffer(enum DwarfAttribute attr,
enum DwarfForm form,
- const uint8_t *data,
+ const uint8_t* data,
uint64_t len) { }
virtual void ProcessAttributeString(enum DwarfAttribute attr,
enum DwarfForm form,
@@ -244,7 +244,7 @@ class DIEHandler {
// it is.
//
// The default definition skips all children.
- virtual DIEHandler *FindChildHandler(uint64_t offset, enum DwarfTag tag) {
+ virtual DIEHandler* FindChildHandler(uint64_t offset, enum DwarfTag tag) {
return NULL;
}
@@ -258,10 +258,13 @@ class DIEHandler {
// A subclass of DIEHandler, with additional kludges for handling the
// compilation unit's root die.
-class RootDIEHandler: public DIEHandler {
+class RootDIEHandler : public DIEHandler {
public:
- RootDIEHandler() { }
- virtual ~RootDIEHandler() { }
+ bool handle_inline;
+
+ explicit RootDIEHandler(bool handle_inline = false)
+ : handle_inline(handle_inline) {}
+ virtual ~RootDIEHandler() {}
// We pass the values reported via Dwarf2Handler::StartCompilationUnit
// to this member function, and skip the entire compilation unit if it
@@ -288,7 +291,7 @@ class DIEDispatcher: public Dwarf2Handler {
// Create a Dwarf2Handler which uses ROOT_HANDLER as the handler for
// the compilation unit's root die, as described for the DIEHandler
// class.
- DIEDispatcher(RootDIEHandler *root_handler) : root_handler_(root_handler) { }
+ DIEDispatcher(RootDIEHandler* root_handler) : root_handler_(root_handler) { }
// Destroying a DIEDispatcher destroys all active handler objects
// except the root handler.
~DIEDispatcher();
@@ -311,12 +314,12 @@ class DIEDispatcher: public Dwarf2Handler {
void ProcessAttributeBuffer(uint64_t offset,
enum DwarfAttribute attr,
enum DwarfForm form,
- const uint8_t *data,
+ const uint8_t* data,
uint64_t len);
void ProcessAttributeString(uint64_t offset,
enum DwarfAttribute attr,
enum DwarfForm form,
- const string &data);
+ const string& data);
void ProcessAttributeSignature(uint64_t offset,
enum DwarfAttribute attr,
enum DwarfForm form,
@@ -335,7 +338,7 @@ class DIEDispatcher: public Dwarf2Handler {
// The handler object interested in this DIE's attributes and
// children. If NULL, we're not interested in either.
- DIEHandler *handler_;
+ DIEHandler* handler_;
// Have we reported the end of this DIE's attributes to the handler?
bool reported_attributes_end_;
@@ -358,8 +361,8 @@ class DIEDispatcher: public Dwarf2Handler {
// The root handler. We don't push it on die_handlers_ until we
// actually get the StartDIE call for the root.
- RootDIEHandler *root_handler_;
+ RootDIEHandler* root_handler_;
};
-} // namespace dwarf2reader
+} // namespace google_breakpad
#endif // COMMON_DWARF_DWARF2DIEHANDLER_H__
diff --git a/src/common/dwarf/dwarf2diehandler_unittest.cc b/src/common/dwarf/dwarf2diehandler_unittest.cc
index 01b70489..67c9489d 100644
--- a/src/common/dwarf/dwarf2diehandler_unittest.cc
+++ b/src/common/dwarf/dwarf2diehandler_unittest.cc
@@ -1,6 +1,6 @@
// -*- mode: c++ -*-
-// Copyright (c) 2010 Google Inc. All Rights Reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -12,7 +12,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -53,12 +53,12 @@ using ::testing::Return;
using ::testing::Sequence;
using ::testing::StrEq;
-using dwarf2reader::DIEDispatcher;
-using dwarf2reader::DIEHandler;
-using dwarf2reader::DwarfAttribute;
-using dwarf2reader::DwarfForm;
-using dwarf2reader::DwarfTag;
-using dwarf2reader::RootDIEHandler;
+using google_breakpad::DIEDispatcher;
+using google_breakpad::DIEHandler;
+using google_breakpad::DwarfAttribute;
+using google_breakpad::DwarfForm;
+using google_breakpad::DwarfTag;
+using google_breakpad::RootDIEHandler;
class MockDIEHandler: public DIEHandler {
public:
@@ -69,9 +69,9 @@ class MockDIEHandler: public DIEHandler {
MOCK_METHOD3(ProcessAttributeReference,
void(DwarfAttribute, DwarfForm, uint64_t));
MOCK_METHOD4(ProcessAttributeBuffer,
- void(DwarfAttribute, DwarfForm, const uint8_t *, uint64_t));
+ void(DwarfAttribute, DwarfForm, const uint8_t*, uint64_t));
MOCK_METHOD3(ProcessAttributeString,
- void(DwarfAttribute, DwarfForm, const string &));
+ void(DwarfAttribute, DwarfForm, const string&));
MOCK_METHOD3(ProcessAttributeSignature,
void(DwarfAttribute, DwarfForm, uint64_t));
MOCK_METHOD0(EndAttributes, bool());
@@ -88,9 +88,9 @@ class MockRootDIEHandler: public RootDIEHandler {
MOCK_METHOD3(ProcessAttributeReference,
void(DwarfAttribute, DwarfForm, uint64_t));
MOCK_METHOD4(ProcessAttributeBuffer,
- void(DwarfAttribute, DwarfForm, const uint8_t *, uint64_t));
+ void(DwarfAttribute, DwarfForm, const uint8_t*, uint64_t));
MOCK_METHOD3(ProcessAttributeString,
- void(DwarfAttribute, DwarfForm, const string &));
+ void(DwarfAttribute, DwarfForm, const string&));
MOCK_METHOD3(ProcessAttributeSignature,
void(DwarfAttribute, DwarfForm, uint64_t));
MOCK_METHOD0(EndAttributes, bool());
@@ -339,7 +339,7 @@ TEST(Dwarf2DIEHandler, FindAndSkipChildren) {
EXPECT_CALL(mock_root_handler,
FindChildHandler(0x97412be24875de9dLL,
(DwarfTag) 0x505a068b))
- .WillOnce(Return((DIEHandler *) NULL));
+ .WillOnce(Return((DIEHandler*) NULL));
// Third child DIE.
EXPECT_CALL(mock_root_handler,
diff --git a/src/common/dwarf/dwarf2enums.h b/src/common/dwarf/dwarf2enums.h
index 4316a89c..777d9bfc 100644
--- a/src/common/dwarf/dwarf2enums.h
+++ b/src/common/dwarf/dwarf2enums.h
@@ -1,6 +1,6 @@
// -*- mode: c++ -*-
-// Copyright (c) 2010 Google Inc. All Rights Reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -12,7 +12,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -31,7 +31,7 @@
#ifndef COMMON_DWARF_DWARF2ENUMS_H__
#define COMMON_DWARF_DWARF2ENUMS_H__
-namespace dwarf2reader {
+namespace google_breakpad {
// These enums do not follow the google3 style only because they are
// known universally (specs, other implementations) by the names in
@@ -95,6 +95,10 @@ enum DwarfTag {
DW_TAG_unspecified_type = 0x3b,
DW_TAG_partial_unit = 0x3c,
DW_TAG_imported_unit = 0x3d,
+ // DWARF 4.
+ DW_TAG_type_unit = 0x41,
+ // DWARF 5.
+ DW_TAG_skeleton_unit = 0x4a,
// SGI/MIPS Extensions.
DW_TAG_MIPS_loop = 0x4081,
// HP extensions. See:
@@ -115,6 +119,16 @@ enum DwarfTag {
DW_TAG_PGI_interface_block = 0xA020
};
+enum DwarfUnitHeader {
+ DW_UT_compile = 0x01,
+ DW_UT_type = 0x02,
+ DW_UT_partial = 0x03,
+ DW_UT_skeleton = 0x04,
+ DW_UT_split_compile = 0x05,
+ DW_UT_split_type = 0x06,
+ DW_UT_lo_user = 0x80,
+ DW_UT_hi_user = 0xFF
+};
enum DwarfHasChild {
DW_children_no = 0,
@@ -149,7 +163,33 @@ enum DwarfForm {
DW_FORM_sec_offset = 0x17,
DW_FORM_exprloc = 0x18,
DW_FORM_flag_present = 0x19,
+
+ // Added in DWARF 5:
+ DW_FORM_strx = 0x1a,
+ DW_FORM_addrx = 0x1b,
+ DW_FORM_ref_sup4 = 0x1c,
+ DW_FORM_strp_sup = 0x1d,
+ DW_FORM_data16 = 0x1e,
+ DW_FORM_line_strp = 0x1f,
+
+ // DWARF 4, but value out of order.
DW_FORM_ref_sig8 = 0x20,
+
+ // Added in DWARF 5:
+ DW_FORM_implicit_const = 0x21,
+ DW_FORM_loclistx = 0x22,
+ DW_FORM_rnglistx = 0x23,
+ DW_FORM_ref_sup8 = 0x24,
+ DW_FORM_strx1 = 0x25,
+ DW_FORM_strx2 = 0x26,
+ DW_FORM_strx3 = 0x27,
+ DW_FORM_strx4 = 0x28,
+
+ DW_FORM_addrx1 = 0x29,
+ DW_FORM_addrx2 = 0x2a,
+ DW_FORM_addrx3 = 0x2b,
+ DW_FORM_addrx4 = 0x2c,
+
// Extensions for Fission. See http://gcc.gnu.org/wiki/DebugFission.
DW_FORM_GNU_addr_index = 0x1f01,
DW_FORM_GNU_str_index = 0x1f02
@@ -234,6 +274,11 @@ enum DwarfAttribute {
DW_AT_call_line = 0x59,
// DWARF 4
DW_AT_linkage_name = 0x6e,
+ // DWARF 5
+ DW_AT_str_offsets_base = 0x72,
+ DW_AT_addr_base = 0x73,
+ DW_AT_rnglists_base = 0x74,
+ DW_AT_dwo_name = 0x76,
// SGI/MIPS extensions.
DW_AT_MIPS_fde = 0x2001,
DW_AT_MIPS_loop_begin = 0x2002,
@@ -286,6 +331,26 @@ enum DwarfAttribute {
DW_AT_PGI_lstride = 0x3a02
};
+// .debug_rngslist entry types
+enum DwarfRngListEntry {
+ DW_RLE_end_of_list = 0,
+ DW_RLE_base_addressx = 1,
+ DW_RLE_startx_endx = 2,
+ DW_RLE_startx_length = 3,
+ DW_RLE_offset_pair = 4,
+ DW_RLE_base_address = 5,
+ DW_RLE_start_end = 6,
+ DW_RLE_start_length = 7,
+};
+
+// Line number content type codes (DWARF 5).
+enum DwarfLineNumberContentType {
+ DW_LNCT_path = 1,
+ DW_LNCT_directory_index = 2,
+ DW_LNCT_timestamp = 3,
+ DW_LNCT_size = 4,
+ DW_LNCT_MD5 = 5,
+};
// Line number opcodes.
enum DwarfLineNumberOps {
@@ -675,5 +740,5 @@ enum DwarfPointerEncoding
DW_EH_PE_indirect = 0x80
};
-} // namespace dwarf2reader
+} // namespace google_breakpad
#endif // COMMON_DWARF_DWARF2ENUMS_H__
diff --git a/src/common/dwarf/dwarf2reader.cc b/src/common/dwarf/dwarf2reader.cc
index 6b9ce2b4..b191d78c 100644
--- a/src/common/dwarf/dwarf2reader.cc
+++ b/src/common/dwarf/dwarf2reader.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2010 Google Inc. All Rights Reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -10,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -28,16 +28,16 @@
// CFI reader author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com>
-// Implementation of dwarf2reader::LineInfo, dwarf2reader::CompilationUnit,
-// and dwarf2reader::CallFrameInfo. See dwarf2reader.h for details.
+// Implementation of LineInfo, CompilationUnit,
+// and CallFrameInfo. See dwarf2reader.h for details.
#include "common/dwarf/dwarf2reader.h"
-#include <assert.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
+#include <algorithm>
#include <map>
#include <memory>
#include <stack>
@@ -52,7 +52,19 @@
#include "common/using_std_string.h"
#include "google_breakpad/common/breakpad_types.h"
-namespace dwarf2reader {
+namespace google_breakpad {
+
+const SectionMap::const_iterator GetSectionByName(const SectionMap&
+ sections, const char *name) {
+ assert(name[0] == '.');
+ auto iter = sections.find(name);
+ if (iter != sections.end())
+ return iter;
+ std::string macho_name("__");
+ macho_name += name + 1;
+ iter = sections.find(macho_name);
+ return iter;
+}
CompilationUnit::CompilationUnit(const string& path,
const SectionMap& sections, uint64_t offset,
@@ -60,11 +72,12 @@ CompilationUnit::CompilationUnit(const string& path,
: path_(path), offset_from_section_start_(offset), reader_(reader),
sections_(sections), handler_(handler), abbrevs_(),
string_buffer_(NULL), string_buffer_length_(0),
+ line_string_buffer_(NULL), line_string_buffer_length_(0),
str_offsets_buffer_(NULL), str_offsets_buffer_length_(0),
addr_buffer_(NULL), addr_buffer_length_(0),
- is_split_dwarf_(false), dwo_id_(0), dwo_name_(),
+ is_split_dwarf_(false), is_type_unit_(false), dwo_id_(0), dwo_name_(),
skeleton_dwo_id_(0), ranges_base_(0), addr_base_(0),
- have_checked_for_dwp_(false), dwp_path_(),
+ str_offsets_base_(0), have_checked_for_dwp_(false), dwp_path_(),
dwp_byte_reader_(), dwp_reader_() {}
// Initialize a compilation unit from a .dwo or .dwp file.
@@ -99,12 +112,9 @@ void CompilationUnit::ReadAbbrevs() {
if (abbrevs_)
return;
- // First get the debug_abbrev section. ".debug_abbrev" is the name
- // recommended in the DWARF spec, and used on Linux;
- // "__debug_abbrev" is the name used in Mac OS X Mach-O files.
- SectionMap::const_iterator iter = sections_.find(".debug_abbrev");
- if (iter == sections_.end())
- iter = sections_.find("__debug_abbrev");
+ // First get the debug_abbrev section.
+ SectionMap::const_iterator iter =
+ GetSectionByName(sections_, ".debug_abbrev");
assert(iter != sections_.end());
abbrevs_ = new std::vector<Abbrev>;
@@ -113,17 +123,20 @@ void CompilationUnit::ReadAbbrevs() {
// The only way to check whether we are reading over the end of the
// buffer would be to first compute the size of the leb128 data by
// reading it, then go back and read it again.
- const uint8_t *abbrev_start = iter->second.first +
+ const uint8_t* abbrev_start = iter->second.first +
header_.abbrev_offset;
- const uint8_t *abbrevptr = abbrev_start;
+ const uint8_t* abbrevptr = abbrev_start;
#ifndef NDEBUG
const uint64_t abbrev_length = iter->second.second - header_.abbrev_offset;
#endif
+ uint64_t highest_number = 0;
+
while (1) {
CompilationUnit::Abbrev abbrev;
size_t len;
const uint64_t number = reader_->ReadUnsignedLEB128(abbrevptr, &len);
+ highest_number = std::max(highest_number, number);
if (number == 0)
break;
@@ -151,29 +164,42 @@ void CompilationUnit::ReadAbbrevs() {
if (nametemp == 0 && formtemp == 0)
break;
- const enum DwarfAttribute name =
- static_cast<enum DwarfAttribute>(nametemp);
- const enum DwarfForm form = static_cast<enum DwarfForm>(formtemp);
- abbrev.attributes.push_back(std::make_pair(name, form));
+ uint64_t value = 0;
+ if (formtemp == DW_FORM_implicit_const) {
+ value = reader_->ReadUnsignedLEB128(abbrevptr, &len);
+ abbrevptr += len;
+ }
+ AttrForm abbrev_attr(static_cast<enum DwarfAttribute>(nametemp),
+ static_cast<enum DwarfForm>(formtemp),
+ value);
+ abbrev.attributes.push_back(abbrev_attr);
}
- assert(abbrev.number == abbrevs_->size());
abbrevs_->push_back(abbrev);
}
+
+ // Account of cases where entries are out of order.
+ std::sort(abbrevs_->begin(), abbrevs_->end(),
+ [](const CompilationUnit::Abbrev& lhs, const CompilationUnit::Abbrev& rhs) {
+ return lhs.number < rhs.number;
+ });
+
+ // Ensure that there are no missing sections.
+ assert(abbrevs_->size() == highest_number + 1);
}
// Skips a single DIE's attributes.
-const uint8_t *CompilationUnit::SkipDIE(const uint8_t* start,
+const uint8_t* CompilationUnit::SkipDIE(const uint8_t* start,
const Abbrev& abbrev) {
for (AttributeList::const_iterator i = abbrev.attributes.begin();
i != abbrev.attributes.end();
i++) {
- start = SkipAttribute(start, i->second);
+ start = SkipAttribute(start, i->form_);
}
return start;
}
// Skips a single attribute form's data.
-const uint8_t *CompilationUnit::SkipAttribute(const uint8_t *start,
+const uint8_t* CompilationUnit::SkipAttribute(const uint8_t* start,
enum DwarfForm form) {
size_t len;
@@ -185,27 +211,45 @@ const uint8_t *CompilationUnit::SkipAttribute(const uint8_t *start,
return SkipAttribute(start, form);
case DW_FORM_flag_present:
+ case DW_FORM_implicit_const:
return start;
+ case DW_FORM_addrx1:
case DW_FORM_data1:
case DW_FORM_flag:
case DW_FORM_ref1:
+ case DW_FORM_strx1:
return start + 1;
+ case DW_FORM_addrx2:
case DW_FORM_ref2:
case DW_FORM_data2:
+ case DW_FORM_strx2:
return start + 2;
+ case DW_FORM_addrx3:
+ case DW_FORM_strx3:
+ return start + 3;
+ case DW_FORM_addrx4:
case DW_FORM_ref4:
case DW_FORM_data4:
+ case DW_FORM_strx4:
+ case DW_FORM_ref_sup4:
return start + 4;
case DW_FORM_ref8:
case DW_FORM_data8:
case DW_FORM_ref_sig8:
+ case DW_FORM_ref_sup8:
return start + 8;
+ case DW_FORM_data16:
+ return start + 16;
case DW_FORM_string:
- return start + strlen(reinterpret_cast<const char *>(start)) + 1;
+ return start + strlen(reinterpret_cast<const char*>(start)) + 1;
case DW_FORM_udata:
case DW_FORM_ref_udata:
+ case DW_FORM_strx:
case DW_FORM_GNU_str_index:
case DW_FORM_GNU_addr_index:
+ case DW_FORM_addrx:
+ case DW_FORM_rnglistx:
+ case DW_FORM_loclistx:
reader_->ReadUnsignedLEB128(start, &len);
return start + len;
@@ -237,6 +281,8 @@ const uint8_t *CompilationUnit::SkipAttribute(const uint8_t *start,
return start + size + len;
}
case DW_FORM_strp:
+ case DW_FORM_line_strp:
+ case DW_FORM_strp_sup:
case DW_FORM_sec_offset:
return start + reader_->OffsetSize();
}
@@ -244,13 +290,52 @@ const uint8_t *CompilationUnit::SkipAttribute(const uint8_t *start,
return NULL;
}
-// Read a DWARF2/3 header.
-// The header is variable length in DWARF3 (and DWARF2 as extended by
-// most compilers), and consists of an length field, a version number,
-// the offset in the .debug_abbrev section for our abbrevs, and an
-// address size.
+// Read the abbreviation offset from a compilation unit header.
+size_t CompilationUnit::ReadAbbrevOffset(const uint8_t* headerptr) {
+ assert(headerptr + reader_->OffsetSize() < buffer_ + buffer_length_);
+ header_.abbrev_offset = reader_->ReadOffset(headerptr);
+ return reader_->OffsetSize();
+}
+
+// Read the address size from a compilation unit header.
+size_t CompilationUnit::ReadAddressSize(const uint8_t* headerptr) {
+ // Compare against less than or equal because this may be the last
+ // section in the file.
+ assert(headerptr + 1 <= buffer_ + buffer_length_);
+ header_.address_size = reader_->ReadOneByte(headerptr);
+ reader_->SetAddressSize(header_.address_size);
+ return 1;
+}
+
+// Read the DWO id from a split or skeleton compilation unit header.
+size_t CompilationUnit::ReadDwoId(const uint8_t* headerptr) {
+ assert(headerptr + 8 <= buffer_ + buffer_length_);
+ dwo_id_ = reader_->ReadEightBytes(headerptr);
+ return 8;
+}
+
+// Read the type signature from a type or split type compilation unit header.
+size_t CompilationUnit::ReadTypeSignature(const uint8_t* headerptr) {
+ assert(headerptr + 8 <= buffer_ + buffer_length_);
+ type_signature_ = reader_->ReadEightBytes(headerptr);
+ return 8;
+}
+
+// Read the DWO id from a split or skeleton compilation unit header.
+size_t CompilationUnit::ReadTypeOffset(const uint8_t* headerptr) {
+ assert(headerptr + reader_->OffsetSize() < buffer_ + buffer_length_);
+ type_offset_ = reader_->ReadOffset(headerptr);
+ return reader_->OffsetSize();
+}
+
+
+// Read a DWARF header. The header is variable length in DWARF3 and DWARF4
+// (and DWARF2 as extended by most compilers), and consists of an length
+// field, a version number, the offset in the .debug_abbrev section for our
+// abbrevs, and an address size. DWARF5 adds a unit_type to distinguish
+// between partial-, full-, skeleton-, split-, and type- compilation units.
void CompilationUnit::ReadHeader() {
- const uint8_t *headerptr = buffer_;
+ const uint8_t* headerptr = buffer_;
size_t initial_length_size;
assert(headerptr + 4 < buffer_ + buffer_length_);
@@ -263,17 +348,37 @@ void CompilationUnit::ReadHeader() {
header_.version = reader_->ReadTwoBytes(headerptr);
headerptr += 2;
- assert(headerptr + reader_->OffsetSize() < buffer_ + buffer_length_);
- header_.abbrev_offset = reader_->ReadOffset(headerptr);
- headerptr += reader_->OffsetSize();
-
- // Compare against less than or equal because this may be the last
- // section in the file.
- assert(headerptr + 1 <= buffer_ + buffer_length_);
- header_.address_size = reader_->ReadOneByte(headerptr);
- reader_->SetAddressSize(header_.address_size);
- headerptr += 1;
-
+ if (header_.version <= 4) {
+ // Older versions of dwarf have a relatively simple structure.
+ headerptr += ReadAbbrevOffset(headerptr);
+ headerptr += ReadAddressSize(headerptr);
+ } else {
+ // DWARF5 adds a unit_type field, and various fields based on unit_type.
+ assert(headerptr + 1 < buffer_ + buffer_length_);
+ uint8_t unit_type = reader_->ReadOneByte(headerptr);
+ headerptr += 1;
+ headerptr += ReadAddressSize(headerptr);
+ headerptr += ReadAbbrevOffset(headerptr);
+ switch (unit_type) {
+ case DW_UT_compile:
+ case DW_UT_partial:
+ // nothing else to read
+ break;
+ case DW_UT_skeleton:
+ case DW_UT_split_compile:
+ headerptr += ReadDwoId(headerptr);
+ break;
+ case DW_UT_type:
+ case DW_UT_split_type:
+ is_type_unit_ = true;
+ headerptr += ReadTypeSignature(headerptr);
+ headerptr += ReadTypeOffset(headerptr);
+ break;
+ default:
+ fprintf(stderr, "Unhandled compilation unit type 0x%x", unit_type);
+ break;
+ }
+ }
after_header_ = headerptr;
// This check ensures that we don't have to do checking during the
@@ -284,12 +389,9 @@ void CompilationUnit::ReadHeader() {
}
uint64_t CompilationUnit::Start() {
- // First get the debug_info section. ".debug_info" is the name
- // recommended in the DWARF spec, and used on Linux; "__debug_info"
- // is the name used in Mac OS X Mach-O files.
- SectionMap::const_iterator iter = sections_.find(".debug_info");
- if (iter == sections_.end())
- iter = sections_.find("__debug_info");
+ // First get the debug_info section.
+ SectionMap::const_iterator iter =
+ GetSectionByName(sections_, ".debug_info");
assert(iter != sections_.end());
// Set up our buffer
@@ -315,30 +417,35 @@ uint64_t CompilationUnit::Start() {
header_.length,
header_.version))
return ourlength;
+ else if (header_.version == 5 && is_type_unit_)
+ return ourlength;
// Otherwise, continue by reading our abbreviation entries.
ReadAbbrevs();
- // Set the string section if we have one. ".debug_str" is the name
- // recommended in the DWARF spec, and used on Linux; "__debug_str"
- // is the name used in Mac OS X Mach-O files.
- iter = sections_.find(".debug_str");
- if (iter == sections_.end())
- iter = sections_.find("__debug_str");
+ // Set the string section if we have one.
+ iter = GetSectionByName(sections_, ".debug_str");
if (iter != sections_.end()) {
string_buffer_ = iter->second.first;
string_buffer_length_ = iter->second.second;
}
+ // Set the line string section if we have one.
+ iter = GetSectionByName(sections_, ".debug_line_str");
+ if (iter != sections_.end()) {
+ line_string_buffer_ = iter->second.first;
+ line_string_buffer_length_ = iter->second.second;
+ }
+
// Set the string offsets section if we have one.
- iter = sections_.find(".debug_str_offsets");
+ iter = GetSectionByName(sections_, ".debug_str_offsets");
if (iter != sections_.end()) {
str_offsets_buffer_ = iter->second.first;
str_offsets_buffer_length_ = iter->second.second;
}
// Set the address section if we have one.
- iter = sections_.find(".debug_addr");
+ iter = GetSectionByName(sections_, ".debug_addr");
if (iter != sections_.end()) {
addr_buffer_ = iter->second.first;
addr_buffer_length_ = iter->second.second;
@@ -358,12 +465,189 @@ uint64_t CompilationUnit::Start() {
return ourlength;
}
+void CompilationUnit::ProcessFormStringIndex(
+ uint64_t dieoffset, enum DwarfAttribute attr, enum DwarfForm form,
+ uint64_t str_index) {
+ const size_t kStringOffsetsTableHeaderSize =
+ header_.version >= 5 ? (reader_->OffsetSize() == 8 ? 16 : 8) : 0;
+ const uint8_t* str_offsets_table_after_header = str_offsets_base_ ?
+ str_offsets_buffer_ + str_offsets_base_ :
+ str_offsets_buffer_ + kStringOffsetsTableHeaderSize;
+ const uint8_t* offset_ptr =
+ str_offsets_table_after_header + str_index * reader_->OffsetSize();
+
+ const uint64_t offset = reader_->ReadOffset(offset_ptr);
+ if (offset >= string_buffer_length_) {
+ return;
+ }
+
+ const char* str = reinterpret_cast<const char*>(string_buffer_) + offset;
+ ProcessAttributeString(dieoffset, attr, form, str);
+}
+
+// Special function for pre-processing the
+// DW_AT_str_offsets_base and DW_AT_addr_base in a DW_TAG_compile_unit die (for
+// DWARF v5). We must make sure to find and process the
+// DW_AT_str_offsets_base and DW_AT_addr_base attributes before attempting to
+// read any string and address attribute in the compile unit.
+const uint8_t* CompilationUnit::ProcessOffsetBaseAttribute(
+ uint64_t dieoffset, const uint8_t* start, enum DwarfAttribute attr,
+ enum DwarfForm form, uint64_t implicit_const) {
+ size_t len;
+
+ switch (form) {
+ // DW_FORM_indirect is never used because it is such a space
+ // waster.
+ case DW_FORM_indirect:
+ form = static_cast<enum DwarfForm>(reader_->ReadUnsignedLEB128(start,
+ &len));
+ start += len;
+ return ProcessOffsetBaseAttribute(dieoffset, start, attr, form,
+ implicit_const);
+
+ case DW_FORM_flag_present:
+ return start;
+ case DW_FORM_data1:
+ case DW_FORM_flag:
+ return start + 1;
+ case DW_FORM_data2:
+ return start + 2;
+ case DW_FORM_data4:
+ return start + 4;
+ case DW_FORM_data8:
+ return start + 8;
+ case DW_FORM_data16:
+ // This form is designed for an md5 checksum inside line tables.
+ return start + 16;
+ case DW_FORM_string: {
+ const char* str = reinterpret_cast<const char*>(start);
+ return start + strlen(str) + 1;
+ }
+ case DW_FORM_udata:
+ reader_->ReadUnsignedLEB128(start, &len);
+ return start + len;
+ case DW_FORM_sdata:
+ reader_->ReadSignedLEB128(start, &len);
+ return start + len;
+ case DW_FORM_addr:
+ reader_->ReadAddress(start);
+ return start + reader_->AddressSize();
+
+ // This is the important one here!
+ case DW_FORM_sec_offset:
+ if (attr == DW_AT_str_offsets_base ||
+ attr == DW_AT_addr_base)
+ ProcessAttributeUnsigned(dieoffset, attr, form,
+ reader_->ReadOffset(start));
+ else
+ reader_->ReadOffset(start);
+ return start + reader_->OffsetSize();
+
+ case DW_FORM_ref1:
+ return start + 1;
+ case DW_FORM_ref2:
+ return start + 2;
+ case DW_FORM_ref4:
+ return start + 4;
+ case DW_FORM_ref8:
+ return start + 8;
+ case DW_FORM_ref_udata:
+ reader_->ReadUnsignedLEB128(start, &len);
+ return start + len;
+ case DW_FORM_ref_addr:
+ // DWARF2 and 3/4 differ on whether ref_addr is address size or
+ // offset size.
+ assert(header_.version >= 2);
+ if (header_.version == 2) {
+ reader_->ReadAddress(start);
+ return start + reader_->AddressSize();
+ } else if (header_.version >= 3) {
+ reader_->ReadOffset(start);
+ return start + reader_->OffsetSize();
+ }
+ break;
+ case DW_FORM_ref_sig8:
+ return start + 8;
+ case DW_FORM_implicit_const:
+ return start;
+ case DW_FORM_block1: {
+ uint64_t datalen = reader_->ReadOneByte(start);
+ return start + 1 + datalen;
+ }
+ case DW_FORM_block2: {
+ uint64_t datalen = reader_->ReadTwoBytes(start);
+ return start + 2 + datalen;
+ }
+ case DW_FORM_block4: {
+ uint64_t datalen = reader_->ReadFourBytes(start);
+ return start + 4 + datalen;
+ }
+ case DW_FORM_block:
+ case DW_FORM_exprloc: {
+ uint64_t datalen = reader_->ReadUnsignedLEB128(start, &len);
+ return start + datalen + len;
+ }
+ case DW_FORM_strp: {
+ reader_->ReadOffset(start);
+ return start + reader_->OffsetSize();
+ }
+ case DW_FORM_line_strp: {
+ reader_->ReadOffset(start);
+ return start + reader_->OffsetSize();
+ }
+ case DW_FORM_strp_sup:
+ return start + 4;
+ case DW_FORM_ref_sup4:
+ return start + 4;
+ case DW_FORM_ref_sup8:
+ return start + 8;
+ case DW_FORM_loclistx:
+ reader_->ReadUnsignedLEB128(start, &len);
+ return start + len;
+ case DW_FORM_strx:
+ case DW_FORM_GNU_str_index: {
+ reader_->ReadUnsignedLEB128(start, &len);
+ return start + len;
+ }
+ case DW_FORM_strx1: {
+ return start + 1;
+ }
+ case DW_FORM_strx2: {
+ return start + 2;
+ }
+ case DW_FORM_strx3: {
+ return start + 3;
+ }
+ case DW_FORM_strx4: {
+ return start + 4;
+ }
+
+ case DW_FORM_addrx:
+ case DW_FORM_GNU_addr_index:
+ reader_->ReadUnsignedLEB128(start, &len);
+ return start + len;
+ case DW_FORM_addrx1:
+ return start + 1;
+ case DW_FORM_addrx2:
+ return start + 2;
+ case DW_FORM_addrx3:
+ return start + 3;
+ case DW_FORM_addrx4:
+ return start + 4;
+ case DW_FORM_rnglistx:
+ reader_->ReadUnsignedLEB128(start, &len);
+ return start + len;
+ }
+ fprintf(stderr, "Unhandled form type\n");
+ return NULL;
+}
+
// If one really wanted, you could merge SkipAttribute and
// ProcessAttribute
// This is all boring data manipulation and calling of the handler.
-const uint8_t *CompilationUnit::ProcessAttribute(
- uint64_t dieoffset, const uint8_t *start, enum DwarfAttribute attr,
- enum DwarfForm form) {
+const uint8_t* CompilationUnit::ProcessAttribute(
+ uint64_t dieoffset, const uint8_t* start, enum DwarfAttribute attr,
+ enum DwarfForm form, uint64_t implicit_const) {
size_t len;
switch (form) {
@@ -373,7 +657,7 @@ const uint8_t *CompilationUnit::ProcessAttribute(
form = static_cast<enum DwarfForm>(reader_->ReadUnsignedLEB128(start,
&len));
start += len;
- return ProcessAttribute(dieoffset, start, attr, form);
+ return ProcessAttribute(dieoffset, start, attr, form, implicit_const);
case DW_FORM_flag_present:
ProcessAttributeUnsigned(dieoffset, attr, form, 1);
@@ -395,8 +679,12 @@ const uint8_t *CompilationUnit::ProcessAttribute(
ProcessAttributeUnsigned(dieoffset, attr, form,
reader_->ReadEightBytes(start));
return start + 8;
+ case DW_FORM_data16:
+ // This form is designed for an md5 checksum inside line tables.
+ fprintf(stderr, "Unhandled form type: DW_FORM_data16\n");
+ return start + 16;
case DW_FORM_string: {
- const char *str = reinterpret_cast<const char *>(start);
+ const char* str = reinterpret_cast<const char*>(start);
ProcessAttributeString(dieoffset, attr, form, str);
return start + strlen(str) + 1;
}
@@ -462,7 +750,10 @@ const uint8_t *CompilationUnit::ProcessAttribute(
handler_->ProcessAttributeSignature(dieoffset, attr, form,
reader_->ReadEightBytes(start));
return start + 8;
-
+ case DW_FORM_implicit_const:
+ handler_->ProcessAttributeUnsigned(dieoffset, attr, form,
+ implicit_const);
+ return start;
case DW_FORM_block1: {
uint64_t datalen = reader_->ReadOneByte(start);
handler_->ProcessAttributeBuffer(dieoffset, attr, form, start + 1,
@@ -494,45 +785,118 @@ const uint8_t *CompilationUnit::ProcessAttribute(
const uint64_t offset = reader_->ReadOffset(start);
assert(string_buffer_ + offset < string_buffer_ + string_buffer_length_);
- const char *str = reinterpret_cast<const char *>(string_buffer_ + offset);
+ const char* str = reinterpret_cast<const char*>(string_buffer_ + offset);
ProcessAttributeString(dieoffset, attr, form, str);
return start + reader_->OffsetSize();
}
+ case DW_FORM_line_strp: {
+ assert(line_string_buffer_ != NULL);
- case DW_FORM_GNU_str_index: {
- uint64_t str_index = reader_->ReadUnsignedLEB128(start, &len);
- const uint8_t* offset_ptr =
- str_offsets_buffer_ + str_index * reader_->OffsetSize();
- const uint64_t offset = reader_->ReadOffset(offset_ptr);
- if (offset >= string_buffer_length_) {
- return NULL;
- }
+ const uint64_t offset = reader_->ReadOffset(start);
+ assert(line_string_buffer_ + offset <
+ line_string_buffer_ + line_string_buffer_length_);
- const char* str = reinterpret_cast<const char *>(string_buffer_) + offset;
+ const char* str =
+ reinterpret_cast<const char*>(line_string_buffer_ + offset);
ProcessAttributeString(dieoffset, attr, form, str);
- return start + len;
- break;
+ return start + reader_->OffsetSize();
}
- case DW_FORM_GNU_addr_index: {
- uint64_t addr_index = reader_->ReadUnsignedLEB128(start, &len);
- const uint8_t* addr_ptr =
- addr_buffer_ + addr_base_ + addr_index * reader_->AddressSize();
+ case DW_FORM_strp_sup:
+ // No support currently for suplementary object files.
+ fprintf(stderr, "Unhandled form type: DW_FORM_strp_sup\n");
+ return start + 4;
+ case DW_FORM_ref_sup4:
+ // No support currently for suplementary object files.
+ fprintf(stderr, "Unhandled form type: DW_FORM_ref_sup4\n");
+ return start + 4;
+ case DW_FORM_ref_sup8:
+ // No support currently for suplementary object files.
+ fprintf(stderr, "Unhandled form type: DW_FORM_ref_sup8\n");
+ return start + 8;
+ case DW_FORM_loclistx:
ProcessAttributeUnsigned(dieoffset, attr, form,
- reader_->ReadAddress(addr_ptr));
+ reader_->ReadUnsignedLEB128(start, &len));
return start + len;
+ case DW_FORM_strx:
+ case DW_FORM_GNU_str_index: {
+ uint64_t str_index = reader_->ReadUnsignedLEB128(start, &len);
+ ProcessFormStringIndex(dieoffset, attr, form, str_index);
+ return start + len;
+ }
+ case DW_FORM_strx1: {
+ uint64_t str_index = reader_->ReadOneByte(start);
+ ProcessFormStringIndex(dieoffset, attr, form, str_index);
+ return start + 1;
+ }
+ case DW_FORM_strx2: {
+ uint64_t str_index = reader_->ReadTwoBytes(start);
+ ProcessFormStringIndex(dieoffset, attr, form, str_index);
+ return start + 2;
+ }
+ case DW_FORM_strx3: {
+ uint64_t str_index = reader_->ReadThreeBytes(start);
+ ProcessFormStringIndex(dieoffset, attr, form, str_index);
+ return start + 3;
+ }
+ case DW_FORM_strx4: {
+ uint64_t str_index = reader_->ReadFourBytes(start);
+ ProcessFormStringIndex(dieoffset, attr, form, str_index);
+ return start + 4;
}
+
+ case DW_FORM_addrx:
+ case DW_FORM_GNU_addr_index:
+ ProcessAttributeAddrIndex(
+ dieoffset, attr, form, reader_->ReadUnsignedLEB128(start, &len));
+ return start + len;
+ case DW_FORM_addrx1:
+ ProcessAttributeAddrIndex(
+ dieoffset, attr, form, reader_->ReadOneByte(start));
+ return start + 1;
+ case DW_FORM_addrx2:
+ ProcessAttributeAddrIndex(
+ dieoffset, attr, form, reader_->ReadTwoBytes(start));
+ return start + 2;
+ case DW_FORM_addrx3:
+ ProcessAttributeAddrIndex(
+ dieoffset, attr, form, reader_->ReadThreeBytes(start));
+ return start + 3;
+ case DW_FORM_addrx4:
+ ProcessAttributeAddrIndex(
+ dieoffset, attr, form, reader_->ReadFourBytes(start));
+ return start + 4;
+ case DW_FORM_rnglistx:
+ ProcessAttributeUnsigned(
+ dieoffset, attr, form, reader_->ReadUnsignedLEB128(start, &len));
+ return start + len;
}
fprintf(stderr, "Unhandled form type\n");
return NULL;
}
-const uint8_t *CompilationUnit::ProcessDIE(uint64_t dieoffset,
- const uint8_t *start,
+const uint8_t* CompilationUnit::ProcessDIE(uint64_t dieoffset,
+ const uint8_t* start,
const Abbrev& abbrev) {
+ // With DWARF v5, the compile_unit die may contain a
+ // DW_AT_str_offsets_base or DW_AT_addr_base. If it does, that attribute must
+ // be found and processed before trying to process the other attributes;
+ // otherwise the string or address values will all come out incorrect.
+ if (abbrev.tag == DW_TAG_compile_unit && header_.version == 5) {
+ uint64_t dieoffset_copy = dieoffset;
+ const uint8_t* start_copy = start;
+ for (AttributeList::const_iterator i = abbrev.attributes.begin();
+ i != abbrev.attributes.end();
+ i++) {
+ start_copy = ProcessOffsetBaseAttribute(dieoffset_copy, start_copy,
+ i->attr_, i->form_,
+ i->value_);
+ }
+ }
+
for (AttributeList::const_iterator i = abbrev.attributes.begin();
i != abbrev.attributes.end();
i++) {
- start = ProcessAttribute(dieoffset, start, i->first, i->second);
+ start = ProcessAttribute(dieoffset, start, i->attr_, i->form_, i->value_);
}
// If this is a compilation unit in a split DWARF object, verify that
@@ -548,12 +912,12 @@ const uint8_t *CompilationUnit::ProcessDIE(uint64_t dieoffset,
}
void CompilationUnit::ProcessDIEs() {
- const uint8_t *dieptr = after_header_;
+ const uint8_t* dieptr = after_header_;
size_t len;
// lengthstart is the place the length field is based on.
// It is the point in the header after the initial length field
- const uint8_t *lengthstart = buffer_;
+ const uint8_t* lengthstart = buffer_;
// In 64 bit dwarf, the initial length is 12 bytes, because of the
// 0xffffffff at the start.
@@ -563,7 +927,7 @@ void CompilationUnit::ProcessDIEs() {
lengthstart += 4;
std::stack<uint64_t> die_stack;
-
+
while (dieptr < (lengthstart + header_.length)) {
// We give the user the absolute offset from the beginning of
// debug_info, since they need it to deal with ref_addr forms.
@@ -589,8 +953,23 @@ void CompilationUnit::ProcessDIEs() {
const enum DwarfTag tag = abbrev.tag;
if (!handler_->StartDIE(absolute_offset, tag)) {
dieptr = SkipDIE(dieptr, abbrev);
+ if (!dieptr) {
+ fprintf(stderr,
+ "An error happens when skipping a DIE's attributes at offset "
+ "0x%" PRIx64
+ ". Stopped processing following DIEs in this CU.\n",
+ absolute_offset);
+ exit(1);
+ }
} else {
dieptr = ProcessDIE(absolute_offset, dieptr, abbrev);
+ if (!dieptr) {
+ fprintf(stderr,
+ "An error happens when processing a DIE at offset 0x%" PRIx64
+ ". Stopped processing following DIEs in this CU.\n",
+ absolute_offset);
+ exit(1);
+ }
}
if (abbrev.has_children) {
@@ -691,7 +1070,7 @@ void CompilationUnit::ReadDebugSectionsFromDwo(ElfReader* elf_reader,
if (section_data != NULL)
sections->insert(std::make_pair(
base_name, std::make_pair(
- reinterpret_cast<const uint8_t *>(section_data),
+ reinterpret_cast<const uint8_t*>(section_data),
section_size)));
}
}
@@ -720,11 +1099,11 @@ void DwpReader::Initialize() {
&string_buffer_size_);
version_ = byte_reader_.ReadFourBytes(
- reinterpret_cast<const uint8_t *>(cu_index_));
+ reinterpret_cast<const uint8_t*>(cu_index_));
if (version_ == 1) {
nslots_ = byte_reader_.ReadFourBytes(
- reinterpret_cast<const uint8_t *>(cu_index_)
+ reinterpret_cast<const uint8_t*>(cu_index_)
+ 3 * sizeof(uint32_t));
phash_ = cu_index_ + 4 * sizeof(uint32_t);
pindex_ = phash_ + nslots_ * sizeof(uint64_t);
@@ -732,13 +1111,13 @@ void DwpReader::Initialize() {
if (shndx_pool_ >= cu_index_ + cu_index_size_) {
version_ = 0;
}
- } else if (version_ == 2) {
+ } else if (version_ == 2 || version_ == 5) {
ncolumns_ = byte_reader_.ReadFourBytes(
- reinterpret_cast<const uint8_t *>(cu_index_) + sizeof(uint32_t));
+ reinterpret_cast<const uint8_t*>(cu_index_) + sizeof(uint32_t));
nunits_ = byte_reader_.ReadFourBytes(
- reinterpret_cast<const uint8_t *>(cu_index_) + 2 * sizeof(uint32_t));
+ reinterpret_cast<const uint8_t*>(cu_index_) + 2 * sizeof(uint32_t));
nslots_ = byte_reader_.ReadFourBytes(
- reinterpret_cast<const uint8_t *>(cu_index_) + 3 * sizeof(uint32_t));
+ reinterpret_cast<const uint8_t*>(cu_index_) + 3 * sizeof(uint32_t));
phash_ = cu_index_ + 4 * sizeof(uint32_t);
pindex_ = phash_ + nslots_ * sizeof(uint64_t);
offset_table_ = pindex_ + nslots_ * sizeof(uint32_t);
@@ -766,7 +1145,7 @@ void DwpReader::ReadDebugSectionsForCU(uint64_t dwo_id,
// can read a list of section indexes for the debug sections
// for the CU whose dwo_id we are looking for.
int index = byte_reader_.ReadFourBytes(
- reinterpret_cast<const uint8_t *>(pindex_)
+ reinterpret_cast<const uint8_t*>(pindex_)
+ slot * sizeof(uint32_t));
const char* shndx_list = shndx_pool_ + index * sizeof(uint32_t);
for (;;) {
@@ -775,7 +1154,7 @@ void DwpReader::ReadDebugSectionsForCU(uint64_t dwo_id,
return;
}
unsigned int shndx = byte_reader_.ReadFourBytes(
- reinterpret_cast<const uint8_t *>(shndx_list));
+ reinterpret_cast<const uint8_t*>(shndx_list));
shndx_list += sizeof(uint32_t);
if (shndx == 0)
break;
@@ -789,28 +1168,28 @@ void DwpReader::ReadDebugSectionsForCU(uint64_t dwo_id,
section_data = elf_reader_->GetSectionByIndex(shndx, &section_size);
sections->insert(std::make_pair(
".debug_abbrev",
- std::make_pair(reinterpret_cast<const uint8_t *> (section_data),
+ std::make_pair(reinterpret_cast<const uint8_t*> (section_data),
section_size)));
} else if (!strncmp(section_name, ".debug_info", strlen(".debug_info"))) {
section_data = elf_reader_->GetSectionByIndex(shndx, &section_size);
sections->insert(std::make_pair(
".debug_info",
- std::make_pair(reinterpret_cast<const uint8_t *> (section_data),
+ std::make_pair(reinterpret_cast<const uint8_t*> (section_data),
section_size)));
} else if (!strncmp(section_name, ".debug_str_offsets",
strlen(".debug_str_offsets"))) {
section_data = elf_reader_->GetSectionByIndex(shndx, &section_size);
sections->insert(std::make_pair(
".debug_str_offsets",
- std::make_pair(reinterpret_cast<const uint8_t *> (section_data),
+ std::make_pair(reinterpret_cast<const uint8_t*> (section_data),
section_size)));
}
}
sections->insert(std::make_pair(
".debug_str",
- std::make_pair(reinterpret_cast<const uint8_t *> (string_buffer_),
+ std::make_pair(reinterpret_cast<const uint8_t*> (string_buffer_),
string_buffer_size_)));
- } else if (version_ == 2) {
+ } else if (version_ == 2 || version_ == 5) {
uint32_t index = LookupCUv2(dwo_id);
if (index == 0) {
return;
@@ -833,33 +1212,33 @@ void DwpReader::ReadDebugSectionsForCU(uint64_t dwo_id,
}
for (unsigned int col = 0u; col < ncolumns_; ++col) {
uint32_t section_id =
- byte_reader_.ReadFourBytes(reinterpret_cast<const uint8_t *>(id_row)
+ byte_reader_.ReadFourBytes(reinterpret_cast<const uint8_t*>(id_row)
+ col * sizeof(uint32_t));
uint32_t offset = byte_reader_.ReadFourBytes(
- reinterpret_cast<const uint8_t *>(offset_row)
+ reinterpret_cast<const uint8_t*>(offset_row)
+ col * sizeof(uint32_t));
uint32_t size = byte_reader_.ReadFourBytes(
- reinterpret_cast<const uint8_t *>(size_row) + col * sizeof(uint32_t));
+ reinterpret_cast<const uint8_t*>(size_row) + col * sizeof(uint32_t));
if (section_id == DW_SECT_ABBREV) {
sections->insert(std::make_pair(
".debug_abbrev",
- std::make_pair(reinterpret_cast<const uint8_t *> (abbrev_data_)
+ std::make_pair(reinterpret_cast<const uint8_t*> (abbrev_data_)
+ offset, size)));
} else if (section_id == DW_SECT_INFO) {
sections->insert(std::make_pair(
".debug_info",
- std::make_pair(reinterpret_cast<const uint8_t *> (info_data_)
+ std::make_pair(reinterpret_cast<const uint8_t*> (info_data_)
+ offset, size)));
} else if (section_id == DW_SECT_STR_OFFSETS) {
sections->insert(std::make_pair(
".debug_str_offsets",
- std::make_pair(reinterpret_cast<const uint8_t *> (str_offsets_data_)
+ std::make_pair(reinterpret_cast<const uint8_t*> (str_offsets_data_)
+ offset, size)));
}
}
sections->insert(std::make_pair(
".debug_str",
- std::make_pair(reinterpret_cast<const uint8_t *> (string_buffer_),
+ std::make_pair(reinterpret_cast<const uint8_t*> (string_buffer_),
string_buffer_size_)));
}
}
@@ -867,14 +1246,14 @@ void DwpReader::ReadDebugSectionsForCU(uint64_t dwo_id,
int DwpReader::LookupCU(uint64_t dwo_id) {
uint32_t slot = static_cast<uint32_t>(dwo_id) & (nslots_ - 1);
uint64_t probe = byte_reader_.ReadEightBytes(
- reinterpret_cast<const uint8_t *>(phash_) + slot * sizeof(uint64_t));
+ reinterpret_cast<const uint8_t*>(phash_) + slot * sizeof(uint64_t));
if (probe != 0 && probe != dwo_id) {
uint32_t secondary_hash =
(static_cast<uint32_t>(dwo_id >> 32) & (nslots_ - 1)) | 1;
do {
slot = (slot + secondary_hash) & (nslots_ - 1);
probe = byte_reader_.ReadEightBytes(
- reinterpret_cast<const uint8_t *>(phash_) + slot * sizeof(uint64_t));
+ reinterpret_cast<const uint8_t*>(phash_) + slot * sizeof(uint64_t));
} while (probe != 0 && probe != dwo_id);
}
if (probe == 0)
@@ -885,28 +1264,35 @@ int DwpReader::LookupCU(uint64_t dwo_id) {
uint32_t DwpReader::LookupCUv2(uint64_t dwo_id) {
uint32_t slot = static_cast<uint32_t>(dwo_id) & (nslots_ - 1);
uint64_t probe = byte_reader_.ReadEightBytes(
- reinterpret_cast<const uint8_t *>(phash_) + slot * sizeof(uint64_t));
+ reinterpret_cast<const uint8_t*>(phash_) + slot * sizeof(uint64_t));
uint32_t index = byte_reader_.ReadFourBytes(
- reinterpret_cast<const uint8_t *>(pindex_) + slot * sizeof(uint32_t));
+ reinterpret_cast<const uint8_t*>(pindex_) + slot * sizeof(uint32_t));
if (index != 0 && probe != dwo_id) {
uint32_t secondary_hash =
(static_cast<uint32_t>(dwo_id >> 32) & (nslots_ - 1)) | 1;
do {
slot = (slot + secondary_hash) & (nslots_ - 1);
probe = byte_reader_.ReadEightBytes(
- reinterpret_cast<const uint8_t *>(phash_) + slot * sizeof(uint64_t));
+ reinterpret_cast<const uint8_t*>(phash_) + slot * sizeof(uint64_t));
index = byte_reader_.ReadFourBytes(
- reinterpret_cast<const uint8_t *>(pindex_) + slot * sizeof(uint32_t));
+ reinterpret_cast<const uint8_t*>(pindex_) + slot * sizeof(uint32_t));
} while (index != 0 && probe != dwo_id);
}
return index;
}
-LineInfo::LineInfo(const uint8_t *buffer, uint64_t buffer_length,
- ByteReader* reader, LineInfoHandler* handler):
- handler_(handler), reader_(reader), buffer_(buffer) {
+LineInfo::LineInfo(const uint8_t* buffer, uint64_t buffer_length,
+ ByteReader* reader, const uint8_t* string_buffer,
+ size_t string_buffer_length,
+ const uint8_t* line_string_buffer,
+ size_t line_string_buffer_length, LineInfoHandler* handler):
+ handler_(handler), reader_(reader), buffer_(buffer),
+ string_buffer_(string_buffer),
+ line_string_buffer_(line_string_buffer) {
#ifndef NDEBUG
buffer_length_ = buffer_length;
+ string_buffer_length_ = string_buffer_length;
+ line_string_buffer_length_ = line_string_buffer_length;
#endif
header_.std_opcode_lengths = NULL;
}
@@ -917,10 +1303,132 @@ uint64_t LineInfo::Start() {
return after_header_ - buffer_;
}
+void LineInfo::ReadTypesAndForms(const uint8_t** lineptr,
+ uint32_t* content_types,
+ uint32_t* content_forms,
+ uint32_t max_types,
+ uint32_t* format_count) {
+ size_t len;
+
+ uint32_t count = reader_->ReadUnsignedLEB128(*lineptr, &len);
+ *lineptr += len;
+ if (count < 1 || count > max_types) {
+ return;
+ }
+ for (uint32_t col = 0; col < count; ++col) {
+ content_types[col] = reader_->ReadUnsignedLEB128(*lineptr, &len);
+ *lineptr += len;
+ content_forms[col] = reader_->ReadUnsignedLEB128(*lineptr, &len);
+ *lineptr += len;
+ }
+ *format_count = count;
+}
+
+const char* LineInfo::ReadStringForm(uint32_t form, const uint8_t** lineptr) {
+ const char* name = nullptr;
+ if (form == DW_FORM_string) {
+ name = reinterpret_cast<const char*>(*lineptr);
+ *lineptr += strlen(name) + 1;
+ return name;
+ } else if (form == DW_FORM_strp) {
+ uint64_t offset = reader_->ReadOffset(*lineptr);
+ assert(offset < string_buffer_length_);
+ *lineptr += reader_->OffsetSize();
+ if (string_buffer_ != nullptr) {
+ name = reinterpret_cast<const char*>(string_buffer_) + offset;
+ return name;
+ }
+ } else if (form == DW_FORM_line_strp) {
+ uint64_t offset = reader_->ReadOffset(*lineptr);
+ assert(offset < line_string_buffer_length_);
+ *lineptr += reader_->OffsetSize();
+ if (line_string_buffer_ != nullptr) {
+ name = reinterpret_cast<const char*>(line_string_buffer_) + offset;
+ return name;
+ }
+ }
+ // Shouldn't be called with a non-string-form, and
+ // if there is a string form but no string buffer,
+ // that is a problem too.
+ assert(0);
+ return nullptr;
+}
+
+uint64_t LineInfo::ReadUnsignedData(uint32_t form, const uint8_t** lineptr) {
+ size_t len;
+ uint64_t value;
+
+ switch (form) {
+ case DW_FORM_data1:
+ value = reader_->ReadOneByte(*lineptr);
+ *lineptr += 1;
+ return value;
+ case DW_FORM_data2:
+ value = reader_->ReadTwoBytes(*lineptr);
+ *lineptr += 2;
+ return value;
+ case DW_FORM_data4:
+ value = reader_->ReadFourBytes(*lineptr);
+ *lineptr += 4;
+ return value;
+ case DW_FORM_data8:
+ value = reader_->ReadEightBytes(*lineptr);
+ *lineptr += 8;
+ return value;
+ case DW_FORM_udata:
+ value = reader_->ReadUnsignedLEB128(*lineptr, &len);
+ *lineptr += len;
+ return value;
+ default:
+ fprintf(stderr, "Unrecognized data form.");
+ return 0;
+ }
+}
+
+void LineInfo::ReadFileRow(const uint8_t** lineptr,
+ const uint32_t* content_types,
+ const uint32_t* content_forms, uint32_t row,
+ uint32_t format_count) {
+ const char* filename = nullptr;
+ uint64_t dirindex = 0;
+ uint64_t mod_time = 0;
+ uint64_t filelength = 0;
+
+ for (uint32_t col = 0; col < format_count; ++col) {
+ switch (content_types[col]) {
+ case DW_LNCT_path:
+ filename = ReadStringForm(content_forms[col], lineptr);
+ break;
+ case DW_LNCT_directory_index:
+ dirindex = ReadUnsignedData(content_forms[col], lineptr);
+ break;
+ case DW_LNCT_timestamp:
+ mod_time = ReadUnsignedData(content_forms[col], lineptr);
+ break;
+ case DW_LNCT_size:
+ filelength = ReadUnsignedData(content_forms[col], lineptr);
+ break;
+ case DW_LNCT_MD5:
+ // MD5 entries help a debugger sort different versions of files with
+ // the same name. It is always paired with a DW_FORM_data16 and is
+ // unused in this case.
+ *lineptr += 16;
+ break;
+ default:
+ fprintf(stderr, "Unrecognized form in line table header. %d\n",
+ content_types[col]);
+ assert(false);
+ break;
+ }
+ }
+ assert(filename != nullptr);
+ handler_->DefineFile(filename, row, dirindex, mod_time, filelength);
+}
+
// The header for a debug_line section is mildly complicated, because
// the line info is very tightly encoded.
void LineInfo::ReadHeader() {
- const uint8_t *lineptr = buffer_;
+ const uint8_t* lineptr = buffer_;
size_t initial_length_size;
const uint64_t initial_length
@@ -931,12 +1439,24 @@ void LineInfo::ReadHeader() {
assert(buffer_ + initial_length_size + header_.total_length <=
buffer_ + buffer_length_);
- // Address size *must* be set by CU ahead of time.
- assert(reader_->AddressSize() != 0);
header_.version = reader_->ReadTwoBytes(lineptr);
lineptr += 2;
+ if (header_.version >= 5) {
+ uint8_t address_size = reader_->ReadOneByte(lineptr);
+ reader_->SetAddressSize(address_size);
+ lineptr += 1;
+ uint8_t segment_selector_size = reader_->ReadOneByte(lineptr);
+ if (segment_selector_size != 0) {
+ fprintf(stderr,"No support for segmented memory.");
+ }
+ lineptr += 1;
+ } else {
+ // Address size *must* be set by CU ahead of time.
+ assert(reader_->AddressSize() != 0);
+ }
+
header_.prologue_length = reader_->ReadOffset(lineptr);
lineptr += reader_->OffsetSize();
@@ -970,53 +1490,96 @@ void LineInfo::ReadHeader() {
lineptr += 1;
}
- // It is legal for the directory entry table to be empty.
- if (*lineptr) {
- uint32_t dirindex = 1;
- while (*lineptr) {
- const char *dirname = reinterpret_cast<const char *>(lineptr);
- handler_->DefineDir(dirname, dirindex);
- lineptr += strlen(dirname) + 1;
- dirindex++;
+ if (header_.version <= 4) {
+ // Directory zero is assumed to be the compilation directory and special
+ // cased where used. It is not actually stored in the dwarf data. But an
+ // empty entry here avoids off-by-one errors elsewhere in the code.
+ handler_->DefineDir("", 0);
+ // It is legal for the directory entry table to be empty.
+ if (*lineptr) {
+ uint32_t dirindex = 1;
+ while (*lineptr) {
+ const char* dirname = reinterpret_cast<const char*>(lineptr);
+ handler_->DefineDir(dirname, dirindex);
+ lineptr += strlen(dirname) + 1;
+ dirindex++;
+ }
}
- }
- lineptr++;
-
- // It is also legal for the file entry table to be empty.
- if (*lineptr) {
- uint32_t fileindex = 1;
+ lineptr++;
+ // It is also legal for the file entry table to be empty.
+
+ // Similarly for file zero.
+ handler_->DefineFile("", 0, 0, 0, 0);
+ if (*lineptr) {
+ uint32_t fileindex = 1;
+ size_t len;
+ while (*lineptr) {
+ const char* filename = ReadStringForm(DW_FORM_string, &lineptr);
+
+ uint64_t dirindex = reader_->ReadUnsignedLEB128(lineptr, &len);
+ lineptr += len;
+
+ uint64_t mod_time = reader_->ReadUnsignedLEB128(lineptr, &len);
+ lineptr += len;
+
+ uint64_t filelength = reader_->ReadUnsignedLEB128(lineptr, &len);
+ lineptr += len;
+ handler_->DefineFile(filename, fileindex,
+ static_cast<uint32_t>(dirindex), mod_time,
+ filelength);
+ fileindex++;
+ }
+ }
+ lineptr++;
+ } else {
+ // Read the DWARF-5 directory table.
+
+ // Dwarf5 supports five different types and forms per directory- and
+ // file-table entry. Theoretically, there could be duplicate entries
+ // in this table, but that would be quite unusual.
+ static const uint32_t kMaxTypesAndForms = 5;
+ uint32_t content_types[kMaxTypesAndForms];
+ uint32_t content_forms[kMaxTypesAndForms];
+ uint32_t format_count;
size_t len;
- while (*lineptr) {
- const char *filename = reinterpret_cast<const char *>(lineptr);
- lineptr += strlen(filename) + 1;
- uint64_t dirindex = reader_->ReadUnsignedLEB128(lineptr, &len);
- lineptr += len;
+ ReadTypesAndForms(&lineptr, content_types, content_forms, kMaxTypesAndForms,
+ &format_count);
+ uint32_t entry_count = reader_->ReadUnsignedLEB128(lineptr, &len);
+ lineptr += len;
+ for (uint32_t row = 0; row < entry_count; ++row) {
+ const char* dirname = nullptr;
+ for (uint32_t col = 0; col < format_count; ++col) {
+ // The path is the only relevant content type for this implementation.
+ if (content_types[col] == DW_LNCT_path) {
+ dirname = ReadStringForm(content_forms[col], &lineptr);
+ }
+ }
+ handler_->DefineDir(dirname, row);
+ }
- uint64_t mod_time = reader_->ReadUnsignedLEB128(lineptr, &len);
- lineptr += len;
+ // Read the DWARF-5 filename table.
+ ReadTypesAndForms(&lineptr, content_types, content_forms, kMaxTypesAndForms,
+ &format_count);
+ entry_count = reader_->ReadUnsignedLEB128(lineptr, &len);
+ lineptr += len;
- uint64_t filelength = reader_->ReadUnsignedLEB128(lineptr, &len);
- lineptr += len;
- handler_->DefineFile(filename, fileindex, static_cast<uint32_t>(dirindex),
- mod_time, filelength);
- fileindex++;
+ for (uint32_t row = 0; row < entry_count; ++row) {
+ ReadFileRow(&lineptr, content_types, content_forms, row, format_count);
}
}
- lineptr++;
-
after_header_ = lineptr;
}
/* static */
bool LineInfo::ProcessOneOpcode(ByteReader* reader,
LineInfoHandler* handler,
- const struct LineInfoHeader &header,
- const uint8_t *start,
+ const struct LineInfoHeader& header,
+ const uint8_t* start,
struct LineStateMachine* lsm,
size_t* len,
uintptr pc,
- bool *lsm_passes_pc) {
+ bool* lsm_passes_pc) {
size_t oplen = 0;
size_t templen;
uint8_t opcode = reader->ReadOneByte(start);
@@ -1153,7 +1716,7 @@ bool LineInfo::ProcessOneOpcode(ByteReader* reader,
}
break;
case DW_LNE_define_file: {
- const char *filename = reinterpret_cast<const char *>(start);
+ const char* filename = reinterpret_cast<const char*>(start);
templen = strlen(filename) + 1;
start += templen;
@@ -1170,7 +1733,7 @@ bool LineInfo::ProcessOneOpcode(ByteReader* reader,
oplen += templen;
if (handler) {
- handler->DefineFile(filename, -1, static_cast<uint32_t>(dirindex),
+ handler->DefineFile(filename, -1, static_cast<uint32_t>(dirindex),
mod_time, filelength);
}
}
@@ -1200,7 +1763,7 @@ void LineInfo::ReadLines() {
// lengthstart is the place the length field is based on.
// It is the point in the header after the initial length field
- const uint8_t *lengthstart = buffer_;
+ const uint8_t* lengthstart = buffer_;
// In 64 bit dwarf, the initial length is 12 bytes, because of the
// 0xffffffff at the start.
@@ -1209,7 +1772,7 @@ void LineInfo::ReadLines() {
else
lengthstart += 4;
- const uint8_t *lineptr = after_header_;
+ const uint8_t* lineptr = after_header_;
lsm.Reset(header_.default_is_stmt);
// The LineInfoHandler interface expects each line's length along
@@ -1232,7 +1795,7 @@ void LineInfo::ReadLines() {
pending_file_num, pending_line_num,
pending_column_num);
if (lsm.end_sequence) {
- lsm.Reset(header_.default_is_stmt);
+ lsm.Reset(header_.default_is_stmt);
have_pending_line = false;
} else {
pending_address = lsm.address;
@@ -1248,11 +1811,25 @@ void LineInfo::ReadLines() {
after_header_ = lengthstart + header_.total_length;
}
-RangeListReader::RangeListReader(const uint8_t *buffer, uint64_t size,
- ByteReader *reader, RangeListHandler *handler)
- : buffer_(buffer), size_(size), reader_(reader), handler_(handler) { }
+bool RangeListReader::ReadRanges(enum DwarfForm form, uint64_t data) {
+ if (form == DW_FORM_sec_offset) {
+ if (cu_info_->version_ <= 4) {
+ return ReadDebugRanges(data);
+ } else {
+ return ReadDebugRngList(data);
+ }
+ } else if (form == DW_FORM_rnglistx) {
+ offset_array_ = cu_info_->ranges_base_;
+ uint64_t index_offset = reader_->OffsetSize() * data;
+ uint64_t range_list_offset =
+ reader_->ReadOffset(cu_info_->buffer_ + offset_array_ + index_offset);
-bool RangeListReader::ReadRangeList(uint64_t offset) {
+ return ReadDebugRngList(offset_array_ + range_list_offset);
+ }
+ return false;
+}
+
+bool RangeListReader::ReadDebugRanges(uint64_t offset) {
const uint64_t max_address =
(reader_->AddressSize() == 4) ? 0xffffffffUL
: 0xffffffffffffffffULL;
@@ -1260,21 +1837,22 @@ bool RangeListReader::ReadRangeList(uint64_t offset) {
bool list_end = false;
do {
- if (offset > size_ - entry_size) {
+ if (offset > cu_info_->size_ - entry_size) {
return false; // Invalid range detected
}
- uint64_t start_address = reader_->ReadAddress(buffer_ + offset);
- uint64_t end_address =
- reader_->ReadAddress(buffer_ + offset + reader_->AddressSize());
+ uint64_t start_address = reader_->ReadAddress(cu_info_->buffer_ + offset);
+ uint64_t end_address = reader_->ReadAddress(
+ cu_info_->buffer_ + offset + reader_->AddressSize());
if (start_address == max_address) { // Base address selection
- handler_->SetBaseAddress(end_address);
+ cu_info_->base_address_ = end_address;
} else if (start_address == 0 && end_address == 0) { // End-of-list
handler_->Finish();
list_end = true;
} else { // Add a range entry
- handler_->AddRange(start_address, end_address);
+ handler_->AddRange(start_address + cu_info_->base_address_,
+ end_address + cu_info_->base_address_);
}
offset += entry_size;
@@ -1283,6 +1861,62 @@ bool RangeListReader::ReadRangeList(uint64_t offset) {
return true;
}
+bool RangeListReader::ReadDebugRngList(uint64_t offset) {
+ uint64_t start = 0;
+ uint64_t end = 0;
+ uint64_t range_len = 0;
+ uint64_t index = 0;
+ // A uleb128's length isn't known until after it has been read, so overruns
+ // are only caught after an entire entry.
+ while (offset < cu_info_->size_) {
+ uint8_t entry_type = reader_->ReadOneByte(cu_info_->buffer_ + offset);
+ offset += 1;
+ // Handle each entry type per Dwarf 5 Standard, section 2.17.3.
+ switch (entry_type) {
+ case DW_RLE_end_of_list:
+ handler_->Finish();
+ return true;
+ case DW_RLE_base_addressx:
+ offset += ReadULEB(offset, &index);
+ cu_info_->base_address_ = GetAddressAtIndex(index);
+ break;
+ case DW_RLE_startx_endx:
+ offset += ReadULEB(offset, &index);
+ start = GetAddressAtIndex(index);
+ offset += ReadULEB(offset, &index);
+ end = GetAddressAtIndex(index);
+ handler_->AddRange(start, end);
+ break;
+ case DW_RLE_startx_length:
+ offset += ReadULEB(offset, &index);
+ start = GetAddressAtIndex(index);
+ offset += ReadULEB(offset, &range_len);
+ handler_->AddRange(start, start + range_len);
+ break;
+ case DW_RLE_offset_pair:
+ offset += ReadULEB(offset, &start);
+ offset += ReadULEB(offset, &end);
+ handler_->AddRange(start + cu_info_->base_address_,
+ end + cu_info_->base_address_);
+ break;
+ case DW_RLE_base_address:
+ offset += ReadAddress(offset, &cu_info_->base_address_);
+ break;
+ case DW_RLE_start_end:
+ offset += ReadAddress(offset, &start);
+ offset += ReadAddress(offset, &end);
+ handler_->AddRange(start, end);
+ break;
+ case DW_RLE_start_length:
+ offset += ReadAddress(offset, &start);
+ offset += ReadULEB(offset, &end);
+ handler_->AddRange(start, start + end);
+ break;
+ }
+ }
+ return false;
+}
+
// A DWARF rule for recovering the address or value of a register, or
// computing the canonical frame address. There is one subclass of this for
// each '*Rule' member function in CallFrameInfo::Handler.
@@ -1305,17 +1939,17 @@ class CallFrameInfo::Rule {
// this rule. If REG is kCFARegister, then this rule describes how to compute
// the canonical frame address. Return what the HANDLER member function
// returned.
- virtual bool Handle(Handler *handler,
+ virtual bool Handle(Handler* handler,
uint64_t address, int reg) const = 0;
// Equality on rules. We use these to decide which rules we need
// to report after a DW_CFA_restore_state instruction.
- virtual bool operator==(const Rule &rhs) const = 0;
+ virtual bool operator==(const Rule& rhs) const = 0;
- bool operator!=(const Rule &rhs) const { return ! (*this == rhs); }
+ bool operator!=(const Rule& rhs) const { return ! (*this == rhs); }
// Return a pointer to a copy of this rule.
- virtual Rule *Copy() const = 0;
+ virtual Rule* Copy() const = 0;
// If this is a base+offset rule, change its base register to REG.
// Otherwise, do nothing. (Ugly, but required for DW_CFA_def_cfa_register.)
@@ -1331,16 +1965,16 @@ class CallFrameInfo::UndefinedRule: public CallFrameInfo::Rule {
public:
UndefinedRule() { }
~UndefinedRule() { }
- bool Handle(Handler *handler, uint64_t address, int reg) const {
+ bool Handle(Handler* handler, uint64_t address, int reg) const {
return handler->UndefinedRule(address, reg);
}
- bool operator==(const Rule &rhs) const {
+ bool operator==(const Rule& rhs) const {
// dynamic_cast is allowed by the Google C++ Style Guide, if the use has
// been carefully considered; cheap RTTI-like workarounds are forbidden.
- const UndefinedRule *our_rhs = dynamic_cast<const UndefinedRule *>(&rhs);
+ const UndefinedRule* our_rhs = dynamic_cast<const UndefinedRule*>(&rhs);
return (our_rhs != NULL);
}
- Rule *Copy() const { return new UndefinedRule(*this); }
+ Rule* Copy() const { return new UndefinedRule(*this); }
};
// Rule: the register's value is the same as that it had in the caller.
@@ -1348,16 +1982,16 @@ class CallFrameInfo::SameValueRule: public CallFrameInfo::Rule {
public:
SameValueRule() { }
~SameValueRule() { }
- bool Handle(Handler *handler, uint64_t address, int reg) const {
+ bool Handle(Handler* handler, uint64_t address, int reg) const {
return handler->SameValueRule(address, reg);
}
- bool operator==(const Rule &rhs) const {
+ bool operator==(const Rule& rhs) const {
// dynamic_cast is allowed by the Google C++ Style Guide, if the use has
// been carefully considered; cheap RTTI-like workarounds are forbidden.
- const SameValueRule *our_rhs = dynamic_cast<const SameValueRule *>(&rhs);
+ const SameValueRule* our_rhs = dynamic_cast<const SameValueRule*>(&rhs);
return (our_rhs != NULL);
}
- Rule *Copy() const { return new SameValueRule(*this); }
+ Rule* Copy() const { return new SameValueRule(*this); }
};
// Rule: the register is saved at OFFSET from BASE_REGISTER. BASE_REGISTER
@@ -1367,18 +2001,18 @@ class CallFrameInfo::OffsetRule: public CallFrameInfo::Rule {
OffsetRule(int base_register, long offset)
: base_register_(base_register), offset_(offset) { }
~OffsetRule() { }
- bool Handle(Handler *handler, uint64_t address, int reg) const {
+ bool Handle(Handler* handler, uint64_t address, int reg) const {
return handler->OffsetRule(address, reg, base_register_, offset_);
}
- bool operator==(const Rule &rhs) const {
+ bool operator==(const Rule& rhs) const {
// dynamic_cast is allowed by the Google C++ Style Guide, if the use has
// been carefully considered; cheap RTTI-like workarounds are forbidden.
- const OffsetRule *our_rhs = dynamic_cast<const OffsetRule *>(&rhs);
+ const OffsetRule* our_rhs = dynamic_cast<const OffsetRule*>(&rhs);
return (our_rhs &&
base_register_ == our_rhs->base_register_ &&
offset_ == our_rhs->offset_);
}
- Rule *Copy() const { return new OffsetRule(*this); }
+ Rule* Copy() const { return new OffsetRule(*this); }
// We don't actually need SetBaseRegister or SetOffset here, since they
// are only ever applied to CFA rules, for DW_CFA_def_cfa_offset, and it
// doesn't make sense to use OffsetRule for computing the CFA: it
@@ -1396,18 +2030,18 @@ class CallFrameInfo::ValOffsetRule: public CallFrameInfo::Rule {
ValOffsetRule(int base_register, long offset)
: base_register_(base_register), offset_(offset) { }
~ValOffsetRule() { }
- bool Handle(Handler *handler, uint64_t address, int reg) const {
+ bool Handle(Handler* handler, uint64_t address, int reg) const {
return handler->ValOffsetRule(address, reg, base_register_, offset_);
}
- bool operator==(const Rule &rhs) const {
+ bool operator==(const Rule& rhs) const {
// dynamic_cast is allowed by the Google C++ Style Guide, if the use has
// been carefully considered; cheap RTTI-like workarounds are forbidden.
- const ValOffsetRule *our_rhs = dynamic_cast<const ValOffsetRule *>(&rhs);
+ const ValOffsetRule* our_rhs = dynamic_cast<const ValOffsetRule*>(&rhs);
return (our_rhs &&
base_register_ == our_rhs->base_register_ &&
offset_ == our_rhs->offset_);
}
- Rule *Copy() const { return new ValOffsetRule(*this); }
+ Rule* Copy() const { return new ValOffsetRule(*this); }
void SetBaseRegister(unsigned reg) { base_register_ = reg; }
void SetOffset(long long offset) { offset_ = offset; }
private:
@@ -1421,16 +2055,16 @@ class CallFrameInfo::RegisterRule: public CallFrameInfo::Rule {
explicit RegisterRule(int register_number)
: register_number_(register_number) { }
~RegisterRule() { }
- bool Handle(Handler *handler, uint64_t address, int reg) const {
+ bool Handle(Handler* handler, uint64_t address, int reg) const {
return handler->RegisterRule(address, reg, register_number_);
}
- bool operator==(const Rule &rhs) const {
+ bool operator==(const Rule& rhs) const {
// dynamic_cast is allowed by the Google C++ Style Guide, if the use has
// been carefully considered; cheap RTTI-like workarounds are forbidden.
- const RegisterRule *our_rhs = dynamic_cast<const RegisterRule *>(&rhs);
+ const RegisterRule* our_rhs = dynamic_cast<const RegisterRule*>(&rhs);
return (our_rhs && register_number_ == our_rhs->register_number_);
}
- Rule *Copy() const { return new RegisterRule(*this); }
+ Rule* Copy() const { return new RegisterRule(*this); }
private:
int register_number_;
};
@@ -1438,19 +2072,19 @@ class CallFrameInfo::RegisterRule: public CallFrameInfo::Rule {
// Rule: EXPRESSION evaluates to the address at which the register is saved.
class CallFrameInfo::ExpressionRule: public CallFrameInfo::Rule {
public:
- explicit ExpressionRule(const string &expression)
+ explicit ExpressionRule(const string& expression)
: expression_(expression) { }
~ExpressionRule() { }
- bool Handle(Handler *handler, uint64_t address, int reg) const {
+ bool Handle(Handler* handler, uint64_t address, int reg) const {
return handler->ExpressionRule(address, reg, expression_);
}
- bool operator==(const Rule &rhs) const {
+ bool operator==(const Rule& rhs) const {
// dynamic_cast is allowed by the Google C++ Style Guide, if the use has
// been carefully considered; cheap RTTI-like workarounds are forbidden.
- const ExpressionRule *our_rhs = dynamic_cast<const ExpressionRule *>(&rhs);
+ const ExpressionRule* our_rhs = dynamic_cast<const ExpressionRule*>(&rhs);
return (our_rhs && expression_ == our_rhs->expression_);
}
- Rule *Copy() const { return new ExpressionRule(*this); }
+ Rule* Copy() const { return new ExpressionRule(*this); }
private:
string expression_;
};
@@ -1458,20 +2092,20 @@ class CallFrameInfo::ExpressionRule: public CallFrameInfo::Rule {
// Rule: EXPRESSION evaluates to the address at which the register is saved.
class CallFrameInfo::ValExpressionRule: public CallFrameInfo::Rule {
public:
- explicit ValExpressionRule(const string &expression)
+ explicit ValExpressionRule(const string& expression)
: expression_(expression) { }
~ValExpressionRule() { }
- bool Handle(Handler *handler, uint64_t address, int reg) const {
+ bool Handle(Handler* handler, uint64_t address, int reg) const {
return handler->ValExpressionRule(address, reg, expression_);
}
- bool operator==(const Rule &rhs) const {
+ bool operator==(const Rule& rhs) const {
// dynamic_cast is allowed by the Google C++ Style Guide, if the use has
// been carefully considered; cheap RTTI-like workarounds are forbidden.
- const ValExpressionRule *our_rhs =
- dynamic_cast<const ValExpressionRule *>(&rhs);
+ const ValExpressionRule* our_rhs =
+ dynamic_cast<const ValExpressionRule*>(&rhs);
return (our_rhs && expression_ == our_rhs->expression_);
}
- Rule *Copy() const { return new ValExpressionRule(*this); }
+ Rule* Copy() const { return new ValExpressionRule(*this); }
private:
string expression_;
};
@@ -1480,51 +2114,51 @@ class CallFrameInfo::ValExpressionRule: public CallFrameInfo::Rule {
class CallFrameInfo::RuleMap {
public:
RuleMap() : cfa_rule_(NULL) { }
- RuleMap(const RuleMap &rhs) : cfa_rule_(NULL) { *this = rhs; }
+ RuleMap(const RuleMap& rhs) : cfa_rule_(NULL) { *this = rhs; }
~RuleMap() { Clear(); }
- RuleMap &operator=(const RuleMap &rhs);
+ RuleMap& operator=(const RuleMap& rhs);
// Set the rule for computing the CFA to RULE. Take ownership of RULE.
- void SetCFARule(Rule *rule) { delete cfa_rule_; cfa_rule_ = rule; }
+ void SetCFARule(Rule* rule) { delete cfa_rule_; cfa_rule_ = rule; }
// Return the current CFA rule. Unlike RegisterRule, this RuleMap retains
// ownership of the rule. We use this for DW_CFA_def_cfa_offset and
// DW_CFA_def_cfa_register, and for detecting references to the CFA before
// a rule for it has been established.
- Rule *CFARule() const { return cfa_rule_; }
+ Rule* CFARule() const { return cfa_rule_; }
// Return the rule for REG, or NULL if there is none. The caller takes
// ownership of the result.
- Rule *RegisterRule(int reg) const;
+ Rule* RegisterRule(int reg) const;
// Set the rule for computing REG to RULE. Take ownership of RULE.
- void SetRegisterRule(int reg, Rule *rule);
+ void SetRegisterRule(int reg, Rule* rule);
// Make all the appropriate calls to HANDLER as if we were changing from
// this RuleMap to NEW_RULES at ADDRESS. We use this to implement
// DW_CFA_restore_state, where lots of rules can change simultaneously.
// Return true if all handlers returned true; otherwise, return false.
- bool HandleTransitionTo(Handler *handler, uint64_t address,
- const RuleMap &new_rules) const;
+ bool HandleTransitionTo(Handler* handler, uint64_t address,
+ const RuleMap& new_rules) const;
private:
// A map from register numbers to Rules.
- typedef std::map<int, Rule *> RuleByNumber;
+ typedef std::map<int, Rule*> RuleByNumber;
// Remove all register rules and clear cfa_rule_.
void Clear();
// The rule for computing the canonical frame address. This RuleMap owns
// this rule.
- Rule *cfa_rule_;
+ Rule* cfa_rule_;
// A map from register numbers to postfix expressions to recover
// their values. This RuleMap owns the Rules the map refers to.
RuleByNumber registers_;
};
-CallFrameInfo::RuleMap &CallFrameInfo::RuleMap::operator=(const RuleMap &rhs) {
+CallFrameInfo::RuleMap& CallFrameInfo::RuleMap::operator=(const RuleMap& rhs) {
Clear();
// Since each map owns the rules it refers to, assignment must copy them.
if (rhs.cfa_rule_) cfa_rule_ = rhs.cfa_rule_->Copy();
@@ -1534,7 +2168,7 @@ CallFrameInfo::RuleMap &CallFrameInfo::RuleMap::operator=(const RuleMap &rhs) {
return *this;
}
-CallFrameInfo::Rule *CallFrameInfo::RuleMap::RegisterRule(int reg) const {
+CallFrameInfo::Rule* CallFrameInfo::RuleMap::RegisterRule(int reg) const {
assert(reg != Handler::kCFARegister);
RuleByNumber::const_iterator it = registers_.find(reg);
if (it != registers_.end())
@@ -1543,18 +2177,18 @@ CallFrameInfo::Rule *CallFrameInfo::RuleMap::RegisterRule(int reg) const {
return NULL;
}
-void CallFrameInfo::RuleMap::SetRegisterRule(int reg, Rule *rule) {
+void CallFrameInfo::RuleMap::SetRegisterRule(int reg, Rule* rule) {
assert(reg != Handler::kCFARegister);
assert(rule);
- Rule **slot = &registers_[reg];
+ Rule** slot = &registers_[reg];
delete *slot;
*slot = rule;
}
bool CallFrameInfo::RuleMap::HandleTransitionTo(
- Handler *handler,
+ Handler* handler,
uint64_t address,
- const RuleMap &new_rules) const {
+ const RuleMap& new_rules) const {
// Transition from cfa_rule_ to new_rules.cfa_rule_.
if (cfa_rule_ && new_rules.cfa_rule_) {
if (*cfa_rule_ != *new_rules.cfa_rule_ &&
@@ -1634,7 +2268,7 @@ class CallFrameInfo::State {
public:
// Create a call frame information interpreter state with the given
// reporter, reader, handler, and initial call frame info address.
- State(ByteReader *reader, Handler *handler, Reporter *reporter,
+ State(ByteReader* reader, Handler* handler, Reporter* reporter,
uint64_t address)
: reader_(reader), handler_(handler), reporter_(reporter),
address_(address), entry_(NULL), cursor_(NULL) { }
@@ -1642,13 +2276,13 @@ class CallFrameInfo::State {
// Interpret instructions from CIE, save the resulting rule set for
// DW_CFA_restore instructions, and return true. On error, report
// the problem to reporter_ and return false.
- bool InterpretCIE(const CIE &cie);
+ bool InterpretCIE(const CIE& cie);
// Interpret instructions from FDE, and return true. On error,
// report the problem to reporter_ and return false.
- bool InterpretFDE(const FDE &fde);
+ bool InterpretFDE(const FDE& fde);
- private:
+ private:
// The operands of a CFI instruction, for ParseOperands.
struct Operands {
unsigned register_number; // A register number.
@@ -1676,7 +2310,7 @@ class CallFrameInfo::State {
// '8' an eight-byte offset (OPERANDS->offset)
// 'e' a DW_FORM_block holding a (OPERANDS->expression)
// DWARF expression
- bool ParseOperands(const char *format, Operands *operands);
+ bool ParseOperands(const char* format, Operands* operands);
// Interpret one CFI instruction from STATE's instruction stream, update
// STATE, report any rule changes to handler_, and return true. On
@@ -1699,7 +2333,7 @@ class CallFrameInfo::State {
// Specify that REG can be recovered using RULE, and return true. On
// failure, report and return false.
- bool DoRule(unsigned reg, Rule *rule);
+ bool DoRule(unsigned reg, Rule* rule);
// Specify that REG can be found at OFFSET from the CFA, and return true.
// On failure, report and return false. (Subroutine for DW_CFA_offset,
@@ -1727,23 +2361,23 @@ class CallFrameInfo::State {
}
// For reading multi-byte values with the appropriate endianness.
- ByteReader *reader_;
+ ByteReader* reader_;
// The handler to which we should report the data we find.
- Handler *handler_;
+ Handler* handler_;
// For reporting problems in the info we're parsing.
- Reporter *reporter_;
+ Reporter* reporter_;
// The code address to which the next instruction in the stream applies.
uint64_t address_;
// The entry whose instructions we are currently processing. This is
// first a CIE, and then an FDE.
- const Entry *entry_;
+ const Entry* entry_;
// The next instruction to process.
- const uint8_t *cursor_;
+ const uint8_t* cursor_;
// The current set of rules.
RuleMap rules_;
@@ -1758,7 +2392,7 @@ class CallFrameInfo::State {
std::stack<RuleMap> saved_rules_;
};
-bool CallFrameInfo::State::InterpretCIE(const CIE &cie) {
+bool CallFrameInfo::State::InterpretCIE(const CIE& cie) {
entry_ = &cie;
cursor_ = entry_->instructions;
while (cursor_ < entry_->end)
@@ -1770,7 +2404,7 @@ bool CallFrameInfo::State::InterpretCIE(const CIE &cie) {
return true;
}
-bool CallFrameInfo::State::InterpretFDE(const FDE &fde) {
+bool CallFrameInfo::State::InterpretFDE(const FDE& fde) {
entry_ = &fde;
cursor_ = entry_->instructions;
while (cursor_ < entry_->end)
@@ -1779,10 +2413,10 @@ bool CallFrameInfo::State::InterpretFDE(const FDE &fde) {
return true;
}
-bool CallFrameInfo::State::ParseOperands(const char *format,
- Operands *operands) {
+bool CallFrameInfo::State::ParseOperands(const char* format,
+ Operands* operands) {
size_t len;
- const char *operand;
+ const char* operand;
for (operand = format; *operand; operand++) {
size_t bytes_left = entry_->end - cursor_;
@@ -1841,7 +2475,7 @@ bool CallFrameInfo::State::ParseOperands(const char *format,
if (len > bytes_left || expression_length > bytes_left - len)
return ReportIncomplete();
cursor_ += len;
- operands->expression = string(reinterpret_cast<const char *>(cursor_),
+ operands->expression = string(reinterpret_cast<const char*>(cursor_),
expression_length);
cursor_ += expression_length;
break;
@@ -1856,7 +2490,7 @@ bool CallFrameInfo::State::ParseOperands(const char *format,
}
bool CallFrameInfo::State::DoInstruction() {
- CIE *cie = entry_->cie;
+ CIE* cie = entry_->cie;
Operands ops;
// Our entry's kind should have been set by now.
@@ -1909,19 +2543,19 @@ bool CallFrameInfo::State::DoInstruction() {
if (!ParseOperands("1", &ops)) return false;
address_ += ops.offset * cie->code_alignment_factor;
break;
-
+
// Advance the address.
case DW_CFA_advance_loc2:
if (!ParseOperands("2", &ops)) return false;
address_ += ops.offset * cie->code_alignment_factor;
break;
-
+
// Advance the address.
case DW_CFA_advance_loc4:
if (!ParseOperands("4", &ops)) return false;
address_ += ops.offset * cie->code_alignment_factor;
break;
-
+
// Advance the address.
case DW_CFA_MIPS_advance_loc8:
if (!ParseOperands("8", &ops)) return false;
@@ -1946,7 +2580,7 @@ bool CallFrameInfo::State::DoInstruction() {
// Change the base register used to compute the CFA.
case DW_CFA_def_cfa_register: {
if (!ParseOperands("r", &ops)) return false;
- Rule *cfa_rule = rules_.CFARule();
+ Rule* cfa_rule = rules_.CFARule();
if (!cfa_rule) {
if (!DoDefCFA(ops.register_number, ops.offset)) {
reporter_->NoCFARule(entry_->offset, entry_->kind, CursorOffset());
@@ -1979,7 +2613,7 @@ bool CallFrameInfo::State::DoInstruction() {
case DW_CFA_def_cfa_expression: {
if (!ParseOperands("e", &ops))
return false;
- Rule *rule = new ValExpressionRule(ops.expression);
+ Rule* rule = new ValExpressionRule(ops.expression);
rules_.SetCFARule(rule);
if (!rule->Handle(handler_, address_,
Handler::kCFARegister))
@@ -2086,7 +2720,7 @@ bool CallFrameInfo::State::DoInstruction() {
CursorOffset());
return false;
}
- const RuleMap &new_rules = saved_rules_.top();
+ const RuleMap& new_rules = saved_rules_.top();
if (rules_.CFARule() && !new_rules.CFARule()) {
reporter_->ClearingCFARule(entry_->offset, entry_->kind,
CursorOffset());
@@ -2102,23 +2736,32 @@ bool CallFrameInfo::State::DoInstruction() {
case DW_CFA_nop:
break;
- // A SPARC register window save: Registers 8 through 15 (%o0-%o7)
- // are saved in registers 24 through 31 (%i0-%i7), and registers
- // 16 through 31 (%l0-%l7 and %i0-%i7) are saved at CFA offsets
- // (0-15 * the register size). The register numbers must be
- // hard-coded. A GNU extension, and not a pretty one.
+ // case DW_CFA_AARCH64_negate_ra_state
case DW_CFA_GNU_window_save: {
- // Save %o0-%o7 in %i0-%i7.
- for (int i = 8; i < 16; i++)
- if (!DoRule(i, new RegisterRule(i + 16)))
- return false;
- // Save %l0-%l7 and %i0-%i7 at the CFA.
- for (int i = 16; i < 32; i++)
- // Assume that the byte reader's address size is the same as
- // the architecture's register size. !@#%*^ hilarious.
- if (!DoRule(i, new OffsetRule(Handler::kCFARegister,
- (i - 16) * reader_->AddressSize())))
- return false;
+ if (handler_->Architecture() == "arm64") {
+ // Indicates that the return address, x30 has been signed.
+ // Breakpad will speculatively remove pointer-authentication codes when
+ // interpreting return addresses, regardless of this bit.
+ } else if (handler_->Architecture() == "sparc" ||
+ handler_->Architecture() == "sparcv9") {
+ // A SPARC register window save: Registers 8 through 15 (%o0-%o7)
+ // are saved in registers 24 through 31 (%i0-%i7), and registers
+ // 16 through 31 (%l0-%l7 and %i0-%i7) are saved at CFA offsets
+ // (0-15 * the register size). The register numbers must be
+ // hard-coded. A GNU extension, and not a pretty one.
+
+ // Save %o0-%o7 in %i0-%i7.
+ for (int i = 8; i < 16; i++)
+ if (!DoRule(i, new RegisterRule(i + 16)))
+ return false;
+ // Save %l0-%l7 and %i0-%i7 at the CFA.
+ for (int i = 16; i < 32; i++)
+ // Assume that the byte reader's address size is the same as
+ // the architecture's register size. !@#%*^ hilarious.
+ if (!DoRule(i, new OffsetRule(Handler::kCFARegister,
+ (i - 16) * reader_->AddressSize())))
+ return false;
+ }
break;
}
@@ -2138,14 +2781,14 @@ bool CallFrameInfo::State::DoInstruction() {
}
bool CallFrameInfo::State::DoDefCFA(unsigned base_register, long offset) {
- Rule *rule = new ValOffsetRule(base_register, offset);
+ Rule* rule = new ValOffsetRule(base_register, offset);
rules_.SetCFARule(rule);
return rule->Handle(handler_, address_,
Handler::kCFARegister);
}
bool CallFrameInfo::State::DoDefCFAOffset(long offset) {
- Rule *cfa_rule = rules_.CFARule();
+ Rule* cfa_rule = rules_.CFARule();
if (!cfa_rule) {
reporter_->NoCFARule(entry_->offset, entry_->kind, CursorOffset());
return false;
@@ -2155,7 +2798,7 @@ bool CallFrameInfo::State::DoDefCFAOffset(long offset) {
Handler::kCFARegister);
}
-bool CallFrameInfo::State::DoRule(unsigned reg, Rule *rule) {
+bool CallFrameInfo::State::DoRule(unsigned reg, Rule* rule) {
rules_.SetRegisterRule(reg, rule);
return rule->Handle(handler_, address_, reg);
}
@@ -2184,7 +2827,7 @@ bool CallFrameInfo::State::DoRestore(unsigned reg) {
reporter_->RestoreInCIE(entry_->offset, CursorOffset());
return false;
}
- Rule *rule = cie_rules_.RegisterRule(reg);
+ Rule* rule = cie_rules_.RegisterRule(reg);
if (!rule) {
// This isn't really the right thing to do, but since CFI generally
// only mentions callee-saves registers, and GCC's convention for
@@ -2195,8 +2838,8 @@ bool CallFrameInfo::State::DoRestore(unsigned reg) {
return DoRule(reg, rule);
}
-bool CallFrameInfo::ReadEntryPrologue(const uint8_t *cursor, Entry *entry) {
- const uint8_t *buffer_end = buffer_ + buffer_length_;
+bool CallFrameInfo::ReadEntryPrologue(const uint8_t* cursor, Entry* entry) {
+ const uint8_t* buffer_end = buffer_ + buffer_length_;
// Initialize enough of ENTRY for use in error reporting.
entry->offset = cursor - buffer_;
@@ -2222,7 +2865,7 @@ bool CallFrameInfo::ReadEntryPrologue(const uint8_t *cursor, Entry *entry) {
// Validate the length.
if (length > size_t(buffer_end - cursor))
return ReportIncomplete(entry);
-
+
// The length is the number of bytes after the initial length field;
// we have that position handy at this point, so compute the end
// now. (If we're parsing 64-bit-offset DWARF on a 32-bit machine,
@@ -2264,7 +2907,7 @@ bool CallFrameInfo::ReadEntryPrologue(const uint8_t *cursor, Entry *entry) {
// Now advance cursor past the id.
cursor += offset_size;
-
+
// The fields specific to this kind of entry start here.
entry->fields = cursor;
@@ -2273,8 +2916,8 @@ bool CallFrameInfo::ReadEntryPrologue(const uint8_t *cursor, Entry *entry) {
return true;
}
-bool CallFrameInfo::ReadCIEFields(CIE *cie) {
- const uint8_t *cursor = cie->fields;
+bool CallFrameInfo::ReadCIEFields(CIE* cie) {
+ const uint8_t* cursor = cie->fields;
size_t len;
assert(cie->kind == kCIE);
@@ -2305,13 +2948,13 @@ bool CallFrameInfo::ReadCIEFields(CIE *cie) {
return false;
}
- const uint8_t *augmentation_start = cursor;
- const uint8_t *augmentation_end =
- reinterpret_cast<const uint8_t *>(memchr(augmentation_start, '\0',
+ const uint8_t* augmentation_start = cursor;
+ const uint8_t* augmentation_end =
+ reinterpret_cast<const uint8_t*>(memchr(augmentation_start, '\0',
cie->end - augmentation_start));
if (! augmentation_end) return ReportIncomplete(cie);
cursor = augmentation_end;
- cie->augmentation = string(reinterpret_cast<const char *>(augmentation_start),
+ cie->augmentation = string(reinterpret_cast<const char*>(augmentation_start),
cursor - augmentation_start);
// Skip the terminating '\0'.
cursor++;
@@ -2372,9 +3015,9 @@ bool CallFrameInfo::ReadCIEFields(CIE *cie) {
if (size_t(cie->end - cursor) < len + data_size)
return ReportIncomplete(cie);
cursor += len;
- const uint8_t *data = cursor;
+ const uint8_t* data = cursor;
cursor += data_size;
- const uint8_t *data_end = cursor;
+ const uint8_t* data_end = cursor;
cie->has_z_lsda = false;
cie->has_z_personality = false;
@@ -2465,8 +3108,8 @@ bool CallFrameInfo::ReadCIEFields(CIE *cie) {
return true;
}
-bool CallFrameInfo::ReadFDEFields(FDE *fde) {
- const uint8_t *cursor = fde->fields;
+bool CallFrameInfo::ReadFDEFields(FDE* fde) {
+ const uint8_t* cursor = fde->fields;
size_t size;
fde->address = reader_->ReadEncodedPointer(cursor, fde->cie->pointer_encoding,
@@ -2492,7 +3135,7 @@ bool CallFrameInfo::ReadFDEFields(FDE *fde) {
if (size_t(fde->end - cursor) < size + data_size)
return ReportIncomplete(fde);
cursor += size;
-
+
// In the abstract, we should walk the augmentation string, and extract
// items from the FDE's augmentation data as we encounter augmentation
// string characters that specify their presence: the ordering of items
@@ -2530,12 +3173,12 @@ bool CallFrameInfo::ReadFDEFields(FDE *fde) {
return true;
}
-
+
bool CallFrameInfo::Start() {
- const uint8_t *buffer_end = buffer_ + buffer_length_;
- const uint8_t *cursor;
+ const uint8_t* buffer_end = buffer_ + buffer_length_;
+ const uint8_t* cursor;
bool all_ok = true;
- const uint8_t *entry_end;
+ const uint8_t* entry_end;
bool ok;
// Traverse all the entries in buffer_, skipping CIEs and offering
@@ -2587,7 +3230,7 @@ bool CallFrameInfo::Start() {
reporter_->CIEPointerOutOfRange(fde.offset, fde.id);
continue;
}
-
+
CIE cie;
// Parse this FDE's CIE header.
@@ -2626,7 +3269,7 @@ bool CallFrameInfo::Start() {
ok = true;
continue;
}
-
+
if (cie.has_z_augmentation) {
// Report the personality routine address, if we have one.
if (cie.has_z_personality) {
@@ -2666,7 +3309,7 @@ bool CallFrameInfo::Start() {
return all_ok;
}
-const char *CallFrameInfo::KindName(EntryKind kind) {
+const char* CallFrameInfo::KindName(EntryKind kind) {
if (kind == CallFrameInfo::kUnknown)
return "entry";
else if (kind == CallFrameInfo::kCIE)
@@ -2679,7 +3322,7 @@ const char *CallFrameInfo::KindName(EntryKind kind) {
}
}
-bool CallFrameInfo::ReportIncomplete(Entry *entry) {
+bool CallFrameInfo::ReportIncomplete(Entry* entry) {
reporter_->Incomplete(entry->offset, entry->kind);
return false;
}
@@ -2738,7 +3381,7 @@ void CallFrameInfo::Reporter::UnrecognizedVersion(uint64_t offset, int version)
}
void CallFrameInfo::Reporter::UnrecognizedAugmentation(uint64_t offset,
- const string &aug) {
+ const string& aug) {
fprintf(stderr,
"%s: CFI frame description entry at offset 0x%" PRIx64 " in '%s':"
" CIE specifies unrecognized augmentation: '%s'\n",
@@ -2813,4 +3456,4 @@ void CallFrameInfo::Reporter::ClearingCFARule(uint64_t offset,
section_.c_str(), insn_offset);
}
-} // namespace dwarf2reader
+} // namespace google_breakpad
diff --git a/src/common/dwarf/dwarf2reader.h b/src/common/dwarf/dwarf2reader.h
index 0b194c17..ddcdd801 100644
--- a/src/common/dwarf/dwarf2reader.h
+++ b/src/common/dwarf/dwarf2reader.h
@@ -1,6 +1,6 @@
// -*- mode: C++ -*-
-// Copyright (c) 2010 Google Inc. All Rights Reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -12,7 +12,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -40,6 +40,7 @@
#ifndef COMMON_DWARF_DWARF2READER_H__
#define COMMON_DWARF_DWARF2READER_H__
+#include <assert.h>
#include <stdint.h>
#include <list>
@@ -55,7 +56,7 @@
#include "common/using_std_string.h"
#include "common/dwarf/elf_reader.h"
-namespace dwarf2reader {
+namespace google_breakpad {
struct LineStateMachine;
class Dwarf2Handler;
class LineInfoHandler;
@@ -63,9 +64,27 @@ class DwpReader;
// This maps from a string naming a section to a pair containing a
// the data for the section, and the size of the section.
-typedef std::map<string, std::pair<const uint8_t *, uint64_t> > SectionMap;
-typedef std::list<std::pair<enum DwarfAttribute, enum DwarfForm> >
- AttributeList;
+typedef std::map<string, std::pair<const uint8_t*, uint64_t> > SectionMap;
+
+// Abstract away the difference between elf and mach-o section names.
+// Elf-names use ".section_name, mach-o uses "__section_name". Pass "name" in
+// the elf form, ".section_name".
+const SectionMap::const_iterator GetSectionByName(const SectionMap&
+ sections, const char* name);
+
+// Most of the time, this struct functions as a simple attribute and form pair.
+// However, Dwarf5 DW_FORM_implicit_const means that a form may have its value
+// in line in the abbrev table, and that value must be associated with the
+// pair until the attr's value is needed.
+struct AttrForm {
+ AttrForm(enum DwarfAttribute attr, enum DwarfForm form, uint64_t value) :
+ attr_(attr), form_(form), value_(value) { }
+
+ enum DwarfAttribute attr_;
+ enum DwarfForm form_;
+ uint64_t value_;
+};
+typedef std::list<AttrForm> AttributeList;
typedef AttributeList::iterator AttributeIterator;
typedef AttributeList::const_iterator ConstAttributeIterator;
@@ -80,7 +99,7 @@ struct LineInfoHeader {
uint8_t opcode_base;
// Use a pointer so that signalsafe_addr2line is able to use this structure
// without heap allocation problem.
- std::vector<unsigned char> *std_opcode_lengths;
+ std::vector<unsigned char>* std_opcode_lengths;
};
class LineInfo {
@@ -90,8 +109,10 @@ class LineInfo {
// to the beginning and length of the line information to read.
// Reader is a ByteReader class that has the endianness set
// properly.
- LineInfo(const uint8_t *buffer_, uint64_t buffer_length,
- ByteReader* reader, LineInfoHandler* handler);
+ LineInfo(const uint8_t* buffer, uint64_t buffer_length,
+ ByteReader* reader, const uint8_t* string_buffer,
+ size_t string_buffer_length, const uint8_t* line_string_buffer,
+ size_t line_string_buffer_length, LineInfoHandler* handler);
virtual ~LineInfo() {
if (header_.std_opcode_lengths) {
@@ -115,12 +136,12 @@ class LineInfo {
// lsm's old address < PC <= lsm's new address
static bool ProcessOneOpcode(ByteReader* reader,
LineInfoHandler* handler,
- const struct LineInfoHeader &header,
- const uint8_t *start,
+ const struct LineInfoHeader& header,
+ const uint8_t* start,
struct LineStateMachine* lsm,
size_t* len,
uintptr pc,
- bool *lsm_passes_pc);
+ bool* lsm_passes_pc);
private:
// Reads the DWARF2/3 header for this line info.
@@ -129,26 +150,54 @@ class LineInfo {
// Reads the DWARF2/3 line information
void ReadLines();
+ // Read the DWARF5 types and forms for the file and directory tables.
+ void ReadTypesAndForms(const uint8_t** lineptr, uint32_t* content_types,
+ uint32_t* content_forms, uint32_t max_types,
+ uint32_t* format_count);
+
+ // Read a row from the dwarf5 LineInfo file table.
+ void ReadFileRow(const uint8_t** lineptr, const uint32_t* content_types,
+ const uint32_t* content_forms, uint32_t row,
+ uint32_t format_count);
+
+ // Read and return the data at *lineptr according to form. Advance
+ // *lineptr appropriately.
+ uint64_t ReadUnsignedData(uint32_t form, const uint8_t** lineptr);
+
+ // Read and return the data at *lineptr according to form. Advance
+ // *lineptr appropriately.
+ const char* ReadStringForm(uint32_t form, const uint8_t** lineptr);
+
// The associated handler to call processing functions in
LineInfoHandler* handler_;
// The associated ByteReader that handles endianness issues for us
ByteReader* reader_;
- // A DWARF2/3 line info header. This is not the same size as
- // in the actual file, as the one in the file may have a 32 bit or
- // 64 bit lengths
+ // A DWARF line info header. This is not the same size as in the actual file,
+ // as the one in the file may have a 32 bit or 64 bit lengths
struct LineInfoHeader header_;
// buffer is the buffer for our line info, starting at exactly where
// the line info to read is. after_header is the place right after
// the end of the line information header.
- const uint8_t *buffer_;
+ const uint8_t* buffer_;
#ifndef NDEBUG
uint64_t buffer_length_;
#endif
- const uint8_t *after_header_;
+ // Convenience pointers into .debug_str and .debug_line_str. These exactly
+ // correspond to those in the compilation unit.
+ const uint8_t* string_buffer_;
+#ifndef NDEBUG
+ uint64_t string_buffer_length_;
+#endif
+ const uint8_t* line_string_buffer_;
+#ifndef NDEBUG
+ uint64_t line_string_buffer_length_;
+#endif
+
+ const uint8_t* after_header_;
};
// This class is the main interface between the line info reader and
@@ -196,25 +245,75 @@ class RangeListHandler {
// Add a range.
virtual void AddRange(uint64_t begin, uint64_t end) { };
- // A new base address must be set for computing the ranges' addresses.
- virtual void SetBaseAddress(uint64_t base_address) { };
-
// Finish processing the range list.
virtual void Finish() { };
};
class RangeListReader {
public:
- RangeListReader(const uint8_t *buffer, uint64_t size, ByteReader *reader,
- RangeListHandler *handler);
+ // Reading a range list requires quite a bit of information
+ // from the compilation unit. Package it conveniently.
+ struct CURangesInfo {
+ CURangesInfo() :
+ version_(0), base_address_(0), ranges_base_(0),
+ buffer_(nullptr), size_(0), addr_buffer_(nullptr),
+ addr_buffer_size_(0), addr_base_(0) { }
+
+ uint16_t version_;
+ // Ranges base address. Ordinarily the CU's low_pc.
+ uint64_t base_address_;
+ // Offset into .debug_rnglists for this CU's rangelists.
+ uint64_t ranges_base_;
+ // Contents of either .debug_ranges or .debug_rnglists.
+ const uint8_t* buffer_;
+ uint64_t size_;
+ // Contents of .debug_addr. This cu's contribution starts at
+ // addr_base_
+ const uint8_t* addr_buffer_;
+ uint64_t addr_buffer_size_;
+ uint64_t addr_base_;
+ };
+
+ RangeListReader(ByteReader* reader, CURangesInfo* cu_info,
+ RangeListHandler* handler) :
+ reader_(reader), cu_info_(cu_info), handler_(handler),
+ offset_array_(0) { }
- bool ReadRangeList(uint64_t offset);
+ // Read ranges from cu_info as specified by form and data.
+ bool ReadRanges(enum DwarfForm form, uint64_t data);
private:
- const uint8_t *buffer_;
- uint64_t size_;
+ // Read dwarf4 .debug_ranges at offset.
+ bool ReadDebugRanges(uint64_t offset);
+ // Read dwarf5 .debug_rngslist at offset.
+ bool ReadDebugRngList(uint64_t offset);
+
+ // Convenience functions to handle the mechanics of reading entries in the
+ // ranges section.
+ uint64_t ReadULEB(uint64_t offset, uint64_t* value) {
+ size_t len;
+ *value = reader_->ReadUnsignedLEB128(cu_info_->buffer_ + offset, &len);
+ return len;
+ }
+
+ uint64_t ReadAddress(uint64_t offset, uint64_t* value) {
+ *value = reader_->ReadAddress(cu_info_->buffer_ + offset);
+ return reader_->AddressSize();
+ }
+
+ // Read the address at this CU's addr_index in the .debug_addr section.
+ uint64_t GetAddressAtIndex(uint64_t addr_index) {
+ assert(cu_info_->addr_buffer_ != nullptr);
+ uint64_t offset =
+ cu_info_->addr_base_ + addr_index * reader_->AddressSize();
+ assert(offset < cu_info_->addr_buffer_size_);
+ return reader_->ReadAddress(cu_info_->addr_buffer_ + offset);
+ }
+
ByteReader* reader_;
- RangeListHandler *handler_;
+ CURangesInfo* cu_info_;
+ RangeListHandler* handler_;
+ uint64_t offset_array_;
};
// This class is the main interface between the reader and the
@@ -288,7 +387,7 @@ class Dwarf2Handler {
virtual void ProcessAttributeBuffer(uint64_t offset,
enum DwarfAttribute attr,
enum DwarfForm form,
- const uint8_t *data,
+ const uint8_t* data,
uint64_t len) { }
// Called when we have an attribute with string data to give to our handler.
@@ -410,18 +509,42 @@ class CompilationUnit {
// Reads the DWARF2/3 abbreviations for this compilation unit
void ReadAbbrevs();
+ // Read the abbreviation offset for this compilation unit
+ size_t ReadAbbrevOffset(const uint8_t* headerptr);
+
+ // Read the address size for this compilation unit
+ size_t ReadAddressSize(const uint8_t* headerptr);
+
+ // Read the DWO id from a split or skeleton compilation unit header
+ size_t ReadDwoId(const uint8_t* headerptr);
+
+ // Read the type signature from a type or split type compilation unit header
+ size_t ReadTypeSignature(const uint8_t* headerptr);
+
+ // Read the DWO id from a split or skeleton compilation unit header
+ size_t ReadTypeOffset(const uint8_t* headerptr);
+
// Processes a single DIE for this compilation unit and return a new
// pointer just past the end of it
- const uint8_t *ProcessDIE(uint64_t dieoffset,
- const uint8_t *start,
+ const uint8_t* ProcessDIE(uint64_t dieoffset,
+ const uint8_t* start,
const Abbrev& abbrev);
// Processes a single attribute and return a new pointer just past the
// end of it
- const uint8_t *ProcessAttribute(uint64_t dieoffset,
- const uint8_t *start,
+ const uint8_t* ProcessAttribute(uint64_t dieoffset,
+ const uint8_t* start,
enum DwarfAttribute attr,
- enum DwarfForm form);
+ enum DwarfForm form,
+ uint64_t implicit_const);
+
+ // Special version of ProcessAttribute, for finding str_offsets_base and
+ // DW_AT_addr_base in DW_TAG_compile_unit, for DWARF v5.
+ const uint8_t* ProcessOffsetBaseAttribute(uint64_t dieoffset,
+ const uint8_t* start,
+ enum DwarfAttribute attr,
+ enum DwarfForm form,
+ uint64_t implicit_const);
// Called when we have an attribute with unsigned data to give to
// our handler. The attribute is for the DIE at OFFSET from the
@@ -436,10 +559,13 @@ class CompilationUnit {
if (attr == DW_AT_GNU_dwo_id) {
dwo_id_ = data;
}
- else if (attr == DW_AT_GNU_addr_base) {
+ else if (attr == DW_AT_GNU_addr_base || attr == DW_AT_addr_base) {
addr_base_ = data;
}
- else if (attr == DW_AT_GNU_ranges_base) {
+ else if (attr == DW_AT_str_offsets_base) {
+ str_offsets_base_ = data;
+ }
+ else if (attr == DW_AT_GNU_ranges_base || attr == DW_AT_rnglists_base) {
ranges_base_ = data;
}
// TODO(yunlian): When we add DW_AT_ranges_base from DWARF-5,
@@ -475,6 +601,14 @@ class CompilationUnit {
handler_->ProcessAttributeBuffer(offset, attr, form, data, len);
}
+ // Handles the common parts of DW_FORM_GNU_str_index, DW_FORM_strx,
+ // DW_FORM_strx1, DW_FORM_strx2, DW_FORM_strx3, and DW_FORM_strx4.
+ // Retrieves the data and calls through to ProcessAttributeString.
+ void ProcessFormStringIndex(uint64_t offset,
+ enum DwarfAttribute attr,
+ enum DwarfForm form,
+ uint64_t str_index);
+
// Called when we have an attribute with string data to give to
// our handler. The attribute is for the DIE at OFFSET from the
// beginning of compilation unit, has a name of ATTR, a form of
@@ -485,21 +619,33 @@ class CompilationUnit {
enum DwarfAttribute attr,
enum DwarfForm form,
const char* data) {
- if (attr == DW_AT_GNU_dwo_name)
+ if (attr == DW_AT_GNU_dwo_name || attr == DW_AT_dwo_name)
dwo_name_ = data;
handler_->ProcessAttributeString(offset, attr, form, data);
}
+ // Called to handle common portions of DW_FORM_addrx and variations, as well
+ // as DW_FORM_GNU_addr_index.
+ void ProcessAttributeAddrIndex(uint64_t offset,
+ enum DwarfAttribute attr,
+ enum DwarfForm form,
+ uint64_t addr_index) {
+ const uint8_t* addr_ptr =
+ addr_buffer_ + addr_base_ + addr_index * reader_->AddressSize();
+ ProcessAttributeUnsigned(
+ offset, attr, form, reader_->ReadAddress(addr_ptr));
+ }
+
// Processes all DIEs for this compilation unit
void ProcessDIEs();
// Skips the die with attributes specified in ABBREV starting at
// START, and return the new place to position the stream to.
- const uint8_t *SkipDIE(const uint8_t *start, const Abbrev& abbrev);
+ const uint8_t* SkipDIE(const uint8_t* start, const Abbrev& abbrev);
// Skips the attribute starting at START, with FORM, and return the
// new place to position the stream to.
- const uint8_t *SkipAttribute(const uint8_t *start, enum DwarfForm form);
+ const uint8_t* SkipAttribute(const uint8_t* start, enum DwarfForm form);
// Process the actual debug information in a split DWARF file.
void ProcessSplitDwarf();
@@ -518,9 +664,9 @@ class CompilationUnit {
// buffer is the buffer for our CU, starting at .debug_info + offset
// passed in from constructor.
// after_header points to right after the compilation unit header.
- const uint8_t *buffer_;
+ const uint8_t* buffer_;
uint64_t buffer_length_;
- const uint8_t *after_header_;
+ const uint8_t* after_header_;
// The associated ByteReader that handles endianness issues for us
ByteReader* reader_;
@@ -539,9 +685,13 @@ class CompilationUnit {
// String section buffer and length, if we have a string section.
// This is here to avoid doing a section lookup for strings in
// ProcessAttribute, which is in the hot path for DWARF2 reading.
- const uint8_t *string_buffer_;
+ const uint8_t* string_buffer_;
uint64_t string_buffer_length_;
+ // Similarly for .debug_line_string.
+ const uint8_t* line_string_buffer_;
+ uint64_t line_string_buffer_length_;
+
// String offsets section buffer and length, if we have a string offsets
// section (.debug_str_offsets or .debug_str_offsets.dwo).
const uint8_t* str_offsets_buffer_;
@@ -561,9 +711,18 @@ class CompilationUnit {
// associated with the skeleton compilation unit.
bool is_split_dwarf_;
+ // Flag indicating if it's a Type Unit (only applicable to DWARF v5).
+ bool is_type_unit_;
+
// The value of the DW_AT_GNU_dwo_id attribute, if any.
uint64_t dwo_id_;
+ // The value of the DW_AT_GNU_type_signature attribute, if any.
+ uint64_t type_signature_;
+
+ // The value of the DW_AT_GNU_type_offset attribute, if any.
+ size_t type_offset_;
+
// The value of the DW_AT_GNU_dwo_name attribute, if any.
const char* dwo_name_;
@@ -571,12 +730,16 @@ class CompilationUnit {
// from the skeleton CU.
uint64_t skeleton_dwo_id_;
- // The value of the DW_AT_GNU_ranges_base attribute, if any.
+ // The value of the DW_AT_GNU_ranges_base or DW_AT_rnglists_base attribute,
+ // if any.
uint64_t ranges_base_;
// The value of the DW_AT_GNU_addr_base attribute, if any.
uint64_t addr_base_;
+ // The value of DW_AT_str_offsets_base attribute, if any.
+ uint64_t str_offsets_base_;
+
// True if we have already looked for a .dwp file.
bool have_checked_for_dwp_;
@@ -905,8 +1068,8 @@ class CallFrameInfo {
// The mechanics of C++ exception handling, personality routines,
// and language-specific data areas are described here, rather nicely:
// http://www.codesourcery.com/public/cxx-abi/abi-eh.html
- CallFrameInfo(const uint8_t *buffer, size_t buffer_length,
- ByteReader *reader, Handler *handler, Reporter *reporter,
+ CallFrameInfo(const uint8_t* buffer, size_t buffer_length,
+ ByteReader* reader, Handler* handler, Reporter* reporter,
bool eh_frame = false)
: buffer_(buffer), buffer_length_(buffer_length),
reader_(reader), handler_(handler), reporter_(reporter),
@@ -920,7 +1083,7 @@ class CallFrameInfo {
bool Start();
// Return the textual name of KIND. For error reporting.
- static const char *KindName(EntryKind kind);
+ static const char* KindName(EntryKind kind);
private:
@@ -933,7 +1096,7 @@ class CallFrameInfo {
size_t offset;
// The start of this entry in the buffer.
- const uint8_t *start;
+ const uint8_t* start;
// Which kind of entry this is.
//
@@ -944,16 +1107,16 @@ class CallFrameInfo {
// The end of this entry's common prologue (initial length and id), and
// the start of this entry's kind-specific fields.
- const uint8_t *fields;
+ const uint8_t* fields;
// The start of this entry's instructions.
- const uint8_t *instructions;
+ const uint8_t* instructions;
// The address past the entry's last byte in the buffer. (Note that
// since offset points to the entry's initial length field, and the
// length field is the number of bytes after that field, this is not
// simply buffer_ + offset + length.)
- const uint8_t *end;
+ const uint8_t* end;
// For both DWARF CFI and .eh_frame sections, this is the CIE id in a
// CIE, and the offset of the associated CIE in an FDE.
@@ -961,7 +1124,7 @@ class CallFrameInfo {
// The CIE that applies to this entry, if we've parsed it. If this is a
// CIE, then this field points to this structure.
- CIE *cie;
+ CIE* cie;
};
// A common information entry (CIE).
@@ -1035,14 +1198,14 @@ class CallFrameInfo {
// true. On failure, report the problem, and return false. Even if we
// return false, set ENTRY->end to the first byte after the entry if we
// were able to figure that out, or NULL if we weren't.
- bool ReadEntryPrologue(const uint8_t *cursor, Entry *entry);
+ bool ReadEntryPrologue(const uint8_t* cursor, Entry* entry);
// Parse the fields of a CIE after the entry prologue, including any 'z'
// augmentation data. Assume that the 'Entry' fields of CIE are
// populated; use CIE->fields and CIE->end as the start and limit for
// parsing. On success, populate the rest of *CIE, and return true; on
// failure, report the problem and return false.
- bool ReadCIEFields(CIE *cie);
+ bool ReadCIEFields(CIE* cie);
// Parse the fields of an FDE after the entry prologue, including any 'z'
// augmentation data. Assume that the 'Entry' fields of *FDE are
@@ -1050,12 +1213,12 @@ class CallFrameInfo {
// parsing. Assume that FDE->cie is fully initialized. On success,
// populate the rest of *FDE, and return true; on failure, report the
// problem and return false.
- bool ReadFDEFields(FDE *fde);
+ bool ReadFDEFields(FDE* fde);
// Report that ENTRY is incomplete, and return false. This is just a
// trivial wrapper for invoking reporter_->Incomplete; it provides a
// little brevity.
- bool ReportIncomplete(Entry *entry);
+ bool ReportIncomplete(Entry* entry);
// Return true if ENCODING has the DW_EH_PE_indirect bit set.
static bool IsIndirectEncoding(DwarfPointerEncoding encoding) {
@@ -1063,17 +1226,17 @@ class CallFrameInfo {
}
// The contents of the DWARF .debug_info section we're parsing.
- const uint8_t *buffer_;
+ const uint8_t* buffer_;
size_t buffer_length_;
// For reading multi-byte values with the appropriate endianness.
- ByteReader *reader_;
+ ByteReader* reader_;
// The handler to which we should report the data we find.
- Handler *handler_;
+ Handler* handler_;
// For reporting problems in the info we're parsing.
- Reporter *reporter_;
+ Reporter* reporter_;
// True if we are processing .eh_frame-format data.
bool eh_frame_;
@@ -1106,7 +1269,7 @@ class CallFrameInfo::Handler {
// process a given FDE, the parser reiterates the appropriate CIE's
// contents at the beginning of the FDE's rules.
virtual bool Entry(size_t offset, uint64_t address, uint64_t length,
- uint8_t version, const string &augmentation,
+ uint8_t version, const string& augmentation,
unsigned return_address) = 0;
// When the Entry function returns true, the parser calls these
@@ -1155,13 +1318,13 @@ class CallFrameInfo::Handler {
// At ADDRESS, the DWARF expression EXPRESSION yields the address at
// which REG was saved.
virtual bool ExpressionRule(uint64_t address, int reg,
- const string &expression) = 0;
+ const string& expression) = 0;
// At ADDRESS, the DWARF expression EXPRESSION yields the caller's
// value for REG. (This rule doesn't provide an address at which the
// register's value is saved.)
virtual bool ValExpressionRule(uint64_t address, int reg,
- const string &expression) = 0;
+ const string& expression) = 0;
// Indicate that the rules for the address range reported by the
// last call to Entry are complete. End should return true if
@@ -1169,6 +1332,9 @@ class CallFrameInfo::Handler {
// should stop.
virtual bool End() = 0;
+ // The target architecture for the data.
+ virtual string Architecture() = 0;
+
// Handler functions for Linux C++ exception handling data. These are
// only called if the data includes 'z' augmentation strings.
@@ -1238,8 +1404,8 @@ class CallFrameInfo::Reporter {
// in a Mach-O section named __debug_frame. If we support
// Linux-style exception handling data, we could be reading an
// .eh_frame section.
- Reporter(const string &filename,
- const string &section = ".debug_frame")
+ Reporter(const string& filename,
+ const string& section = ".debug_frame")
: filename_(filename), section_(section) { }
virtual ~Reporter() { }
@@ -1279,7 +1445,7 @@ class CallFrameInfo::Reporter {
// which we don't recognize. We cannot parse DWARF CFI if it uses
// augmentations we don't recognize.
virtual void UnrecognizedAugmentation(uint64_t offset,
- const string &augmentation);
+ const string& augmentation);
// The pointer encoding ENCODING, specified by the CIE at OFFSET, is not
// a valid encoding.
@@ -1326,6 +1492,6 @@ class CallFrameInfo::Reporter {
string section_;
};
-} // namespace dwarf2reader
+} // namespace google_breakpad
#endif // UTIL_DEBUGINFO_DWARF2READER_H__
diff --git a/src/common/dwarf/dwarf2reader_cfi_unittest.cc b/src/common/dwarf/dwarf2reader_cfi_unittest.cc
index ebe612e1..dc4418c7 100644
--- a/src/common/dwarf/dwarf2reader_cfi_unittest.cc
+++ b/src/common/dwarf/dwarf2reader_cfi_unittest.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2010, Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -29,7 +28,7 @@
// Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com>
-// dwarf2reader_cfi_unittest.cc: Unit tests for dwarf2reader::CallFrameInfo
+// dwarf2reader_cfi_unittest.cc: Unit tests for google_breakpad::CallFrameInfo
#include <stdint.h>
#include <stdlib.h>
@@ -72,11 +71,11 @@ using google_breakpad::test_assembler::kBigEndian;
using google_breakpad::test_assembler::kLittleEndian;
using google_breakpad::test_assembler::Section;
-using dwarf2reader::DwarfPointerEncoding;
-using dwarf2reader::ENDIANNESS_BIG;
-using dwarf2reader::ENDIANNESS_LITTLE;
-using dwarf2reader::ByteReader;
-using dwarf2reader::CallFrameInfo;
+using google_breakpad::DwarfPointerEncoding;
+using google_breakpad::ENDIANNESS_BIG;
+using google_breakpad::ENDIANNESS_LITTLE;
+using google_breakpad::ByteReader;
+using google_breakpad::CallFrameInfo;
using std::vector;
using testing::InSequence;
@@ -87,7 +86,7 @@ using testing::_;
#ifdef WRITE_ELF
void WriteELFFrameSection(const char *filename, const char *section_name,
- const CFISection &section);
+ const CFISection& section);
#define PERHAPS_WRITE_DEBUG_FRAME_FILE(name, section) \
WriteELFFrameSection("cfitest-" name, ".debug_frame", section);
#define PERHAPS_WRITE_EH_FRAME_FILE(name, section) \
@@ -100,7 +99,7 @@ void WriteELFFrameSection(const char *filename, const char *section_name,
class MockCallFrameInfoHandler: public CallFrameInfo::Handler {
public:
MOCK_METHOD6(Entry, bool(size_t offset, uint64_t address, uint64_t length,
- uint8_t version, const string &augmentation,
+ uint8_t version, const string& augmentation,
unsigned return_address));
MOCK_METHOD2(UndefinedRule, bool(uint64_t address, int reg));
MOCK_METHOD2(SameValueRule, bool(uint64_t address, int reg));
@@ -110,10 +109,11 @@ class MockCallFrameInfoHandler: public CallFrameInfo::Handler {
long offset));
MOCK_METHOD3(RegisterRule, bool(uint64_t address, int reg, int base_register));
MOCK_METHOD3(ExpressionRule, bool(uint64_t address, int reg,
- const string &expression));
+ const string& expression));
MOCK_METHOD3(ValExpressionRule, bool(uint64_t address, int reg,
- const string &expression));
+ const string& expression));
MOCK_METHOD0(End, bool());
+ MOCK_METHOD0(Architecture, string());
MOCK_METHOD2(PersonalityRoutine, bool(uint64_t address, bool indirect));
MOCK_METHOD2(LanguageSpecificDataArea, bool(uint64_t address, bool indirect));
MOCK_METHOD0(SignalHandler, bool());
@@ -129,7 +129,7 @@ class MockCallFrameErrorReporter: public CallFrameInfo::Reporter {
MOCK_METHOD2(UnexpectedAddressSize, void(uint64_t, uint8_t));
MOCK_METHOD2(UnexpectedSegmentSize, void(uint64_t, uint8_t));
MOCK_METHOD2(UnrecognizedVersion, void(uint64_t, int version));
- MOCK_METHOD2(UnrecognizedAugmentation, void(uint64_t, const string &));
+ MOCK_METHOD2(UnrecognizedAugmentation, void(uint64_t, const string&));
MOCK_METHOD2(InvalidPointerEncoding, void(uint64_t, uint8_t));
MOCK_METHOD2(UnusablePointerEncoding, void(uint64_t, uint8_t));
MOCK_METHOD2(RestoreInCIE, void(uint64_t, uint64_t));
@@ -218,7 +218,7 @@ TEST_F(CFI, IncompleteLength32) {
ByteReader byte_reader(ENDIANNESS_BIG);
byte_reader.SetAddressSize(8);
- CallFrameInfo parser(reinterpret_cast<const uint8_t *>(contents.data()),
+ CallFrameInfo parser(reinterpret_cast<const uint8_t*>(contents.data()),
contents.size() - 2,
&byte_reader, &handler, &reporter);
EXPECT_FALSE(parser.Start());
@@ -244,7 +244,7 @@ TEST_F(CFI, IncompleteLength64) {
ByteReader byte_reader(ENDIANNESS_LITTLE);
byte_reader.SetAddressSize(4);
- CallFrameInfo parser(reinterpret_cast<const uint8_t *>(contents.data()),
+ CallFrameInfo parser(reinterpret_cast<const uint8_t*>(contents.data()),
contents.size() - 4,
&byte_reader, &handler, &reporter);
EXPECT_FALSE(parser.Start());
@@ -269,7 +269,7 @@ TEST_F(CFI, IncompleteId32) {
ByteReader byte_reader(ENDIANNESS_BIG);
byte_reader.SetAddressSize(8);
- CallFrameInfo parser(reinterpret_cast<const uint8_t *>(contents.data()),
+ CallFrameInfo parser(reinterpret_cast<const uint8_t*>(contents.data()),
contents.size(),
&byte_reader, &handler, &reporter);
EXPECT_FALSE(parser.Start());
@@ -296,7 +296,7 @@ TEST_F(CFI, BadId32) {
ByteReader byte_reader(ENDIANNESS_BIG);
byte_reader.SetAddressSize(8);
- CallFrameInfo parser(reinterpret_cast<const uint8_t *>(contents.data()),
+ CallFrameInfo parser(reinterpret_cast<const uint8_t*>(contents.data()),
contents.size(),
&byte_reader, &handler, &reporter);
EXPECT_FALSE(parser.Start());
@@ -306,7 +306,7 @@ TEST_F(CFI, BadId32) {
TEST_F(CFI, SingleCIE) {
CFISection section(kLittleEndian, 4);
section.CIEHeader(0xffe799a8, 0x3398dcdd, 0x6e9683de, 3, "");
- section.Append(10, dwarf2reader::DW_CFA_nop);
+ section.Append(10, google_breakpad::DW_CFA_nop);
section.FinishEntry();
PERHAPS_WRITE_DEBUG_FRAME_FILE("SingleCIE", section);
@@ -318,7 +318,7 @@ TEST_F(CFI, SingleCIE) {
EXPECT_TRUE(section.GetContents(&contents));
ByteReader byte_reader(ENDIANNESS_LITTLE);
byte_reader.SetAddressSize(4);
- CallFrameInfo parser(reinterpret_cast<const uint8_t *>(contents.data()),
+ CallFrameInfo parser(reinterpret_cast<const uint8_t*>(contents.data()),
contents.size(),
&byte_reader, &handler, &reporter);
EXPECT_TRUE(parser.Start());
@@ -349,7 +349,7 @@ TEST_F(CFI, OneFDE) {
EXPECT_TRUE(section.GetContents(&contents));
ByteReader byte_reader(ENDIANNESS_BIG);
byte_reader.SetAddressSize(4);
- CallFrameInfo parser(reinterpret_cast<const uint8_t *>(contents.data()),
+ CallFrameInfo parser(reinterpret_cast<const uint8_t*>(contents.data()),
contents.size(),
&byte_reader, &handler, &reporter);
EXPECT_TRUE(parser.Start());
@@ -393,7 +393,7 @@ TEST_F(CFI, TwoFDEsOneCIE) {
EXPECT_TRUE(section.GetContents(&contents));
ByteReader byte_reader(ENDIANNESS_BIG);
byte_reader.SetAddressSize(4);
- CallFrameInfo parser(reinterpret_cast<const uint8_t *>(contents.data()),
+ CallFrameInfo parser(reinterpret_cast<const uint8_t*>(contents.data()),
contents.size(),
&byte_reader, &handler, &reporter);
EXPECT_TRUE(parser.Start());
@@ -443,7 +443,7 @@ TEST_F(CFI, TwoFDEsTwoCIEs) {
EXPECT_TRUE(section.GetContents(&contents));
ByteReader byte_reader(ENDIANNESS_LITTLE);
byte_reader.SetAddressSize(8);
- CallFrameInfo parser(reinterpret_cast<const uint8_t *>(contents.data()),
+ CallFrameInfo parser(reinterpret_cast<const uint8_t*>(contents.data()),
contents.size(),
&byte_reader, &handler, &reporter);
EXPECT_TRUE(parser.Start());
@@ -488,7 +488,7 @@ TEST_F(CFI, BadVersion) {
EXPECT_TRUE(section.GetContents(&contents));
ByteReader byte_reader(ENDIANNESS_BIG);
byte_reader.SetAddressSize(4);
- CallFrameInfo parser(reinterpret_cast<const uint8_t *>(contents.data()),
+ CallFrameInfo parser(reinterpret_cast<const uint8_t*>(contents.data()),
contents.size(),
&byte_reader, &handler, &reporter);
EXPECT_FALSE(parser.Start());
@@ -533,7 +533,7 @@ TEST_F(CFI, BadAugmentation) {
EXPECT_TRUE(section.GetContents(&contents));
ByteReader byte_reader(ENDIANNESS_BIG);
byte_reader.SetAddressSize(4);
- CallFrameInfo parser(reinterpret_cast<const uint8_t *>(contents.data()),
+ CallFrameInfo parser(reinterpret_cast<const uint8_t*>(contents.data()),
contents.size(),
&byte_reader, &handler, &reporter);
EXPECT_FALSE(parser.Start());
@@ -568,7 +568,7 @@ TEST_F(CFI, CIEVersion1ReturnColumn) {
EXPECT_TRUE(section.GetContents(&contents));
ByteReader byte_reader(ENDIANNESS_BIG);
byte_reader.SetAddressSize(4);
- CallFrameInfo parser(reinterpret_cast<const uint8_t *>(contents.data()),
+ CallFrameInfo parser(reinterpret_cast<const uint8_t*>(contents.data()),
contents.size(),
&byte_reader, &handler, &reporter);
EXPECT_TRUE(parser.Start());
@@ -603,7 +603,7 @@ TEST_F(CFI, CIEVersion3ReturnColumn) {
EXPECT_TRUE(section.GetContents(&contents));
ByteReader byte_reader(ENDIANNESS_BIG);
byte_reader.SetAddressSize(4);
- CallFrameInfo parser(reinterpret_cast<const uint8_t *>(contents.data()),
+ CallFrameInfo parser(reinterpret_cast<const uint8_t*>(contents.data()),
contents.size(),
&byte_reader, &handler, &reporter);
EXPECT_TRUE(parser.Start());
@@ -633,7 +633,7 @@ TEST_F(CFI, CIEVersion4AdditionalFields) {
string contents;
EXPECT_TRUE(section.GetContents(&contents));
ByteReader byte_reader(ENDIANNESS_BIG);
- CallFrameInfo parser(reinterpret_cast<const uint8_t *>(contents.data()),
+ CallFrameInfo parser(reinterpret_cast<const uint8_t*>(contents.data()),
contents.size(),
&byte_reader, &handler, &reporter);
EXPECT_TRUE(parser.Start());
@@ -663,7 +663,7 @@ TEST_F(CFI, CIEVersion4AdditionalFields32BitAddress) {
string contents;
EXPECT_TRUE(section.GetContents(&contents));
ByteReader byte_reader(ENDIANNESS_BIG);
- CallFrameInfo parser(reinterpret_cast<const uint8_t *>(contents.data()),
+ CallFrameInfo parser(reinterpret_cast<const uint8_t*>(contents.data()),
contents.size(),
&byte_reader, &handler, &reporter);
EXPECT_TRUE(parser.Start());
@@ -690,7 +690,7 @@ TEST_F(CFI, CIEVersion4AdditionalFieldsUnexpectedAddressSize) {
string contents;
EXPECT_TRUE(section.GetContents(&contents));
ByteReader byte_reader(ENDIANNESS_BIG);
- CallFrameInfo parser(reinterpret_cast<const uint8_t *>(contents.data()),
+ CallFrameInfo parser(reinterpret_cast<const uint8_t*>(contents.data()),
contents.size(),
&byte_reader, &handler, &reporter);
EXPECT_FALSE(parser.Start());
@@ -715,7 +715,7 @@ TEST_F(CFI, CIEVersion4AdditionalFieldsUnexpectedSegmentSize) {
string contents;
EXPECT_TRUE(section.GetContents(&contents));
ByteReader byte_reader(ENDIANNESS_BIG);
- CallFrameInfo parser(reinterpret_cast<const uint8_t *>(contents.data()),
+ CallFrameInfo parser(reinterpret_cast<const uint8_t*>(contents.data()),
contents.size(),
&byte_reader, &handler, &reporter);
EXPECT_FALSE(parser.Start());
@@ -763,7 +763,7 @@ struct CFIInsnFixture: public CFIFixture {
.Mark(&cie_label)
.CIEHeader(code_factor, data_factor, return_register, version,
"")
- .D8(dwarf2reader::DW_CFA_def_cfa)
+ .D8(google_breakpad::DW_CFA_def_cfa)
.ULEB128(cfa_base_register)
.ULEB128(cfa_offset)
.FinishEntry();
@@ -788,7 +788,7 @@ struct CFIInsnFixture: public CFIFixture {
void ParseSection(CFISection *section, bool succeeds = true) {
string contents;
EXPECT_TRUE(section->GetContents(&contents));
- dwarf2reader::Endianness endianness;
+ google_breakpad::Endianness endianness;
if (section->endianness() == kBigEndian)
endianness = ENDIANNESS_BIG;
else {
@@ -797,7 +797,7 @@ struct CFIInsnFixture: public CFIFixture {
}
ByteReader byte_reader(endianness);
byte_reader.SetAddressSize(section->AddressSize());
- CallFrameInfo parser(reinterpret_cast<const uint8_t *>(contents.data()),
+ CallFrameInfo parser(reinterpret_cast<const uint8_t*>(contents.data()),
contents.size(),
&byte_reader, &handler, &reporter);
if (succeeds)
@@ -823,10 +823,10 @@ TEST_F(CFIInsn, DW_CFA_set_loc) {
CFISection section(kBigEndian, 4);
StockCIEAndFDE(&section);
section
- .D8(dwarf2reader::DW_CFA_set_loc).D32(0xb1ee3e7a)
+ .D8(google_breakpad::DW_CFA_set_loc).D32(0xb1ee3e7a)
// Use DW_CFA_def_cfa to force a handler call that we can use to
// check the effect of the DW_CFA_set_loc.
- .D8(dwarf2reader::DW_CFA_def_cfa).ULEB128(0x4defb431).ULEB128(0x6d17b0ee)
+ .D8(google_breakpad::DW_CFA_def_cfa).ULEB128(0x4defb431).ULEB128(0x6d17b0ee)
.FinishEntry();
PERHAPS_WRITE_DEBUG_FRAME_FILE("DW_CFA_set_loc", section);
@@ -844,10 +844,10 @@ TEST_F(CFIInsn, DW_CFA_advance_loc) {
CFISection section(kBigEndian, 8);
StockCIEAndFDE(&section);
section
- .D8(dwarf2reader::DW_CFA_advance_loc | 0x2a)
+ .D8(google_breakpad::DW_CFA_advance_loc | 0x2a)
// Use DW_CFA_def_cfa to force a handler call that we can use to
// check the effect of the DW_CFA_advance_loc.
- .D8(dwarf2reader::DW_CFA_def_cfa).ULEB128(0x5bbb3715).ULEB128(0x0186c7bf)
+ .D8(google_breakpad::DW_CFA_def_cfa).ULEB128(0x5bbb3715).ULEB128(0x0186c7bf)
.FinishEntry();
PERHAPS_WRITE_DEBUG_FRAME_FILE("DW_CFA_advance_loc", section);
@@ -866,8 +866,8 @@ TEST_F(CFIInsn, DW_CFA_advance_loc1) {
CFISection section(kLittleEndian, 8);
StockCIEAndFDE(&section);
section
- .D8(dwarf2reader::DW_CFA_advance_loc1).D8(0xd8)
- .D8(dwarf2reader::DW_CFA_def_cfa).ULEB128(0x69d5696a).ULEB128(0x1eb7fc93)
+ .D8(google_breakpad::DW_CFA_advance_loc1).D8(0xd8)
+ .D8(google_breakpad::DW_CFA_def_cfa).ULEB128(0x69d5696a).ULEB128(0x1eb7fc93)
.FinishEntry();
PERHAPS_WRITE_DEBUG_FRAME_FILE("DW_CFA_advance_loc1", section);
@@ -886,8 +886,8 @@ TEST_F(CFIInsn, DW_CFA_advance_loc2) {
CFISection section(kLittleEndian, 4);
StockCIEAndFDE(&section);
section
- .D8(dwarf2reader::DW_CFA_advance_loc2).D16(0x3adb)
- .D8(dwarf2reader::DW_CFA_def_cfa).ULEB128(0x3a368bed).ULEB128(0x3194ee37)
+ .D8(google_breakpad::DW_CFA_advance_loc2).D16(0x3adb)
+ .D8(google_breakpad::DW_CFA_def_cfa).ULEB128(0x3a368bed).ULEB128(0x3194ee37)
.FinishEntry();
PERHAPS_WRITE_DEBUG_FRAME_FILE("DW_CFA_advance_loc2", section);
@@ -906,8 +906,8 @@ TEST_F(CFIInsn, DW_CFA_advance_loc4) {
CFISection section(kBigEndian, 8);
StockCIEAndFDE(&section);
section
- .D8(dwarf2reader::DW_CFA_advance_loc4).D32(0x15813c88)
- .D8(dwarf2reader::DW_CFA_def_cfa).ULEB128(0x135270c5).ULEB128(0x24bad7cb)
+ .D8(google_breakpad::DW_CFA_advance_loc4).D32(0x15813c88)
+ .D8(google_breakpad::DW_CFA_def_cfa).ULEB128(0x135270c5).ULEB128(0x24bad7cb)
.FinishEntry();
PERHAPS_WRITE_DEBUG_FRAME_FILE("DW_CFA_advance_loc4", section);
@@ -927,8 +927,8 @@ TEST_F(CFIInsn, DW_CFA_MIPS_advance_loc8) {
CFISection section(kBigEndian, 8);
StockCIEAndFDE(&section);
section
- .D8(dwarf2reader::DW_CFA_MIPS_advance_loc8).D64(0x3c4f3945b92c14ULL)
- .D8(dwarf2reader::DW_CFA_def_cfa).ULEB128(0xe17ed602).ULEB128(0x3d162e7f)
+ .D8(google_breakpad::DW_CFA_MIPS_advance_loc8).D64(0x3c4f3945b92c14ULL)
+ .D8(google_breakpad::DW_CFA_def_cfa).ULEB128(0xe17ed602).ULEB128(0x3d162e7f)
.FinishEntry();
PERHAPS_WRITE_DEBUG_FRAME_FILE("DW_CFA_advance_loc8", section);
@@ -947,7 +947,7 @@ TEST_F(CFIInsn, DW_CFA_def_cfa) {
CFISection section(kLittleEndian, 4);
StockCIEAndFDE(&section);
section
- .D8(dwarf2reader::DW_CFA_def_cfa).ULEB128(0x4e363a85).ULEB128(0x815f9aa7)
+ .D8(google_breakpad::DW_CFA_def_cfa).ULEB128(0x4e363a85).ULEB128(0x815f9aa7)
.FinishEntry();
PERHAPS_WRITE_DEBUG_FRAME_FILE("DW_CFA_def_cfa", section);
@@ -964,8 +964,8 @@ TEST_F(CFIInsn, DW_CFA_def_cfa_sf) {
CFISection section(kBigEndian, 4);
StockCIEAndFDE(&section);
section
- .D8(dwarf2reader::DW_CFA_def_cfa_sf).ULEB128(0x8ccb32b7).LEB128(0x9ea)
- .D8(dwarf2reader::DW_CFA_def_cfa_sf).ULEB128(0x9b40f5da).LEB128(-0x40a2)
+ .D8(google_breakpad::DW_CFA_def_cfa_sf).ULEB128(0x8ccb32b7).LEB128(0x9ea)
+ .D8(google_breakpad::DW_CFA_def_cfa_sf).ULEB128(0x9b40f5da).LEB128(-0x40a2)
.FinishEntry();
EXPECT_CALL(handler,
@@ -985,7 +985,7 @@ TEST_F(CFIInsn, DW_CFA_def_cfa_register) {
CFISection section(kLittleEndian, 8);
StockCIEAndFDE(&section);
section
- .D8(dwarf2reader::DW_CFA_def_cfa_register).ULEB128(0x3e7e9363)
+ .D8(google_breakpad::DW_CFA_def_cfa_register).ULEB128(0x3e7e9363)
.FinishEntry();
EXPECT_CALL(handler,
@@ -1002,8 +1002,8 @@ TEST_F(CFIInsn, DW_CFA_def_cfa_registerBadRule) {
CFISection section(kBigEndian, 4);
StockCIEAndFDE(&section);
section
- .D8(dwarf2reader::DW_CFA_def_cfa_expression).Block("needle in a haystack")
- .D8(dwarf2reader::DW_CFA_def_cfa_register).ULEB128(0xf1b49e49)
+ .D8(google_breakpad::DW_CFA_def_cfa_expression).Block("needle in a haystack")
+ .D8(google_breakpad::DW_CFA_def_cfa_register).ULEB128(0xf1b49e49)
.FinishEntry();
EXPECT_CALL(handler,
@@ -1019,7 +1019,7 @@ TEST_F(CFIInsn, DW_CFA_def_cfa_offset) {
CFISection section(kBigEndian, 4);
StockCIEAndFDE(&section);
section
- .D8(dwarf2reader::DW_CFA_def_cfa_offset).ULEB128(0x1e8e3b9b)
+ .D8(google_breakpad::DW_CFA_def_cfa_offset).ULEB128(0x1e8e3b9b)
.FinishEntry();
EXPECT_CALL(handler,
@@ -1035,8 +1035,8 @@ TEST_F(CFIInsn, DW_CFA_def_cfa_offset_sf) {
CFISection section(kLittleEndian, 4);
StockCIEAndFDE(&section);
section
- .D8(dwarf2reader::DW_CFA_def_cfa_offset_sf).LEB128(0x970)
- .D8(dwarf2reader::DW_CFA_def_cfa_offset_sf).LEB128(-0x2cd)
+ .D8(google_breakpad::DW_CFA_def_cfa_offset_sf).LEB128(0x970)
+ .D8(google_breakpad::DW_CFA_def_cfa_offset_sf).LEB128(-0x2cd)
.FinishEntry();
EXPECT_CALL(handler,
@@ -1058,8 +1058,8 @@ TEST_F(CFIInsn, DW_CFA_def_cfa_offsetBadRule) {
CFISection section(kBigEndian, 4);
StockCIEAndFDE(&section);
section
- .D8(dwarf2reader::DW_CFA_def_cfa_expression).Block("six ways to Sunday")
- .D8(dwarf2reader::DW_CFA_def_cfa_offset).ULEB128(0x1e8e3b9b)
+ .D8(google_breakpad::DW_CFA_def_cfa_expression).Block("six ways to Sunday")
+ .D8(google_breakpad::DW_CFA_def_cfa_offset).ULEB128(0x1e8e3b9b)
.FinishEntry();
EXPECT_CALL(handler,
@@ -1074,7 +1074,7 @@ TEST_F(CFIInsn, DW_CFA_def_cfa_expression) {
CFISection section(kLittleEndian, 8);
StockCIEAndFDE(&section);
section
- .D8(dwarf2reader::DW_CFA_def_cfa_expression).Block("eating crow")
+ .D8(google_breakpad::DW_CFA_def_cfa_expression).Block("eating crow")
.FinishEntry();
EXPECT_CALL(handler, ValExpressionRule(fde_start, kCFARegister,
@@ -1089,7 +1089,7 @@ TEST_F(CFIInsn, DW_CFA_undefined) {
CFISection section(kLittleEndian, 4);
StockCIEAndFDE(&section);
section
- .D8(dwarf2reader::DW_CFA_undefined).ULEB128(0x300ce45d)
+ .D8(google_breakpad::DW_CFA_undefined).ULEB128(0x300ce45d)
.FinishEntry();
EXPECT_CALL(handler, UndefinedRule(fde_start, 0x300ce45d))
@@ -1103,7 +1103,7 @@ TEST_F(CFIInsn, DW_CFA_same_value) {
CFISection section(kLittleEndian, 4);
StockCIEAndFDE(&section);
section
- .D8(dwarf2reader::DW_CFA_same_value).ULEB128(0x3865a760)
+ .D8(google_breakpad::DW_CFA_same_value).ULEB128(0x3865a760)
.FinishEntry();
EXPECT_CALL(handler, SameValueRule(fde_start, 0x3865a760))
@@ -1117,7 +1117,7 @@ TEST_F(CFIInsn, DW_CFA_offset) {
CFISection section(kBigEndian, 4);
StockCIEAndFDE(&section);
section
- .D8(dwarf2reader::DW_CFA_offset | 0x2c).ULEB128(0x9f6)
+ .D8(google_breakpad::DW_CFA_offset | 0x2c).ULEB128(0x9f6)
.FinishEntry();
EXPECT_CALL(handler,
@@ -1132,7 +1132,7 @@ TEST_F(CFIInsn, DW_CFA_offset_extended) {
CFISection section(kBigEndian, 4);
StockCIEAndFDE(&section);
section
- .D8(dwarf2reader::DW_CFA_offset_extended).ULEB128(0x402b).ULEB128(0xb48)
+ .D8(google_breakpad::DW_CFA_offset_extended).ULEB128(0x402b).ULEB128(0xb48)
.FinishEntry();
EXPECT_CALL(handler,
@@ -1147,9 +1147,9 @@ TEST_F(CFIInsn, DW_CFA_offset_extended_sf) {
CFISection section(kBigEndian, 8);
StockCIEAndFDE(&section);
section
- .D8(dwarf2reader::DW_CFA_offset_extended_sf)
+ .D8(google_breakpad::DW_CFA_offset_extended_sf)
.ULEB128(0x997c23ee).LEB128(0x2d00)
- .D8(dwarf2reader::DW_CFA_offset_extended_sf)
+ .D8(google_breakpad::DW_CFA_offset_extended_sf)
.ULEB128(0x9519eb82).LEB128(-0xa77)
.FinishEntry();
@@ -1170,7 +1170,7 @@ TEST_F(CFIInsn, DW_CFA_val_offset) {
CFISection section(kBigEndian, 4);
StockCIEAndFDE(&section);
section
- .D8(dwarf2reader::DW_CFA_val_offset).ULEB128(0x623562fe).ULEB128(0x673)
+ .D8(google_breakpad::DW_CFA_val_offset).ULEB128(0x623562fe).ULEB128(0x673)
.FinishEntry();
EXPECT_CALL(handler,
@@ -1186,8 +1186,8 @@ TEST_F(CFIInsn, DW_CFA_val_offset_sf) {
CFISection section(kBigEndian, 4);
StockCIEAndFDE(&section);
section
- .D8(dwarf2reader::DW_CFA_val_offset_sf).ULEB128(0x6f4f).LEB128(0xaab)
- .D8(dwarf2reader::DW_CFA_val_offset_sf).ULEB128(0x2483).LEB128(-0x8a2)
+ .D8(google_breakpad::DW_CFA_val_offset_sf).ULEB128(0x6f4f).LEB128(0xaab)
+ .D8(google_breakpad::DW_CFA_val_offset_sf).ULEB128(0x2483).LEB128(-0x8a2)
.FinishEntry();
EXPECT_CALL(handler,
@@ -1207,7 +1207,7 @@ TEST_F(CFIInsn, DW_CFA_register) {
CFISection section(kLittleEndian, 8);
StockCIEAndFDE(&section);
section
- .D8(dwarf2reader::DW_CFA_register).ULEB128(0x278d18f9).ULEB128(0x1a684414)
+ .D8(google_breakpad::DW_CFA_register).ULEB128(0x278d18f9).ULEB128(0x1a684414)
.FinishEntry();
EXPECT_CALL(handler, RegisterRule(fde_start, 0x278d18f9, 0x1a684414))
@@ -1221,7 +1221,7 @@ TEST_F(CFIInsn, DW_CFA_expression) {
CFISection section(kBigEndian, 8);
StockCIEAndFDE(&section);
section
- .D8(dwarf2reader::DW_CFA_expression).ULEB128(0xa1619fb2)
+ .D8(google_breakpad::DW_CFA_expression).ULEB128(0xa1619fb2)
.Block("plus ça change, plus c'est la même chose")
.FinishEntry();
@@ -1238,7 +1238,7 @@ TEST_F(CFIInsn, DW_CFA_val_expression) {
CFISection section(kBigEndian, 4);
StockCIEAndFDE(&section);
section
- .D8(dwarf2reader::DW_CFA_val_expression).ULEB128(0xc5e4a9e3)
+ .D8(google_breakpad::DW_CFA_val_expression).ULEB128(0xc5e4a9e3)
.Block("he who has the gold makes the rules")
.FinishEntry();
@@ -1265,18 +1265,18 @@ TEST_F(CFIInsn, DW_CFA_restore) {
.CIEHeader(code_factor, data_factor, return_register, version,
"")
// Provide a CFA rule, because register rules require them.
- .D8(dwarf2reader::DW_CFA_def_cfa).ULEB128(0x6ca1d50e).ULEB128(0x372e38e8)
+ .D8(google_breakpad::DW_CFA_def_cfa).ULEB128(0x6ca1d50e).ULEB128(0x372e38e8)
// Provide an offset(N) rule for register 0x3c.
- .D8(dwarf2reader::DW_CFA_offset | 0x3c).ULEB128(0xb348)
+ .D8(google_breakpad::DW_CFA_offset | 0x3c).ULEB128(0xb348)
.FinishEntry()
// In the FDE...
.FDEHeader(cie, fde_start, fde_size)
// At a second address, provide a new offset(N) rule for register 0x3c.
- .D8(dwarf2reader::DW_CFA_advance_loc | 0x13)
- .D8(dwarf2reader::DW_CFA_offset | 0x3c).ULEB128(0x9a50)
+ .D8(google_breakpad::DW_CFA_advance_loc | 0x13)
+ .D8(google_breakpad::DW_CFA_offset | 0x3c).ULEB128(0x9a50)
// At a third address, restore the original rule for register 0x3c.
- .D8(dwarf2reader::DW_CFA_advance_loc | 0x01)
- .D8(dwarf2reader::DW_CFA_restore | 0x3c)
+ .D8(google_breakpad::DW_CFA_advance_loc | 0x01)
+ .D8(google_breakpad::DW_CFA_restore | 0x3c)
.FinishEntry();
{
@@ -1321,16 +1321,16 @@ TEST_F(CFIInsn, DW_CFA_restoreNoRule) {
.Mark(&cie)
.CIEHeader(code_factor, data_factor, return_register, version, "")
// Provide a CFA rule, because register rules require them.
- .D8(dwarf2reader::DW_CFA_def_cfa).ULEB128(0x470aa334).ULEB128(0x099ef127)
+ .D8(google_breakpad::DW_CFA_def_cfa).ULEB128(0x470aa334).ULEB128(0x099ef127)
.FinishEntry()
// In the FDE...
.FDEHeader(cie, fde_start, fde_size)
// At a second address, provide an offset(N) rule for register 0x2c.
- .D8(dwarf2reader::DW_CFA_advance_loc | 0x7)
- .D8(dwarf2reader::DW_CFA_offset | 0x2c).ULEB128(0x1f47)
+ .D8(google_breakpad::DW_CFA_advance_loc | 0x7)
+ .D8(google_breakpad::DW_CFA_offset | 0x2c).ULEB128(0x1f47)
// At a third address, restore the (missing) CIE rule for register 0x2c.
- .D8(dwarf2reader::DW_CFA_advance_loc | 0xb)
- .D8(dwarf2reader::DW_CFA_restore | 0x2c)
+ .D8(google_breakpad::DW_CFA_advance_loc | 0xb)
+ .D8(google_breakpad::DW_CFA_restore | 0x2c)
.FinishEntry();
{
@@ -1371,20 +1371,20 @@ TEST_F(CFIInsn, DW_CFA_restore_extended) {
.CIEHeader(code_factor, data_factor, return_register, version,
"", true /* dwarf64 */ )
// Provide a CFA rule, because register rules require them.
- .D8(dwarf2reader::DW_CFA_def_cfa).ULEB128(0x56fa0edd).ULEB128(0x097f78a5)
+ .D8(google_breakpad::DW_CFA_def_cfa).ULEB128(0x56fa0edd).ULEB128(0x097f78a5)
// Provide an offset(N) rule for register 0x0f9b8a1c.
- .D8(dwarf2reader::DW_CFA_offset_extended)
+ .D8(google_breakpad::DW_CFA_offset_extended)
.ULEB128(0x0f9b8a1c).ULEB128(0xc979)
.FinishEntry()
// In the FDE...
.FDEHeader(cie, fde_start, fde_size)
// At a second address, provide a new offset(N) rule for reg 0x0f9b8a1c.
- .D8(dwarf2reader::DW_CFA_advance_loc | 0x3)
- .D8(dwarf2reader::DW_CFA_offset_extended)
+ .D8(google_breakpad::DW_CFA_advance_loc | 0x3)
+ .D8(google_breakpad::DW_CFA_offset_extended)
.ULEB128(0x0f9b8a1c).ULEB128(0x3b7b)
// At a third address, restore the original rule for register 0x0f9b8a1c.
- .D8(dwarf2reader::DW_CFA_advance_loc | 0x04)
- .D8(dwarf2reader::DW_CFA_restore_extended).ULEB128(0x0f9b8a1c)
+ .D8(google_breakpad::DW_CFA_advance_loc | 0x04)
+ .D8(google_breakpad::DW_CFA_restore_extended).ULEB128(0x0f9b8a1c)
.FinishEntry();
{
@@ -1433,21 +1433,21 @@ TEST_F(CFIInsn, DW_CFA_remember_and_restore_state) {
// 5 offset(N) no rule new "same value" rule
section
// Create the "incoming" state, which we will save and later restore.
- .D8(dwarf2reader::DW_CFA_offset | 2).ULEB128(0x9806)
- .D8(dwarf2reader::DW_CFA_offset | 3).ULEB128(0x995d)
- .D8(dwarf2reader::DW_CFA_offset | 4).ULEB128(0x7055)
- .D8(dwarf2reader::DW_CFA_remember_state)
+ .D8(google_breakpad::DW_CFA_offset | 2).ULEB128(0x9806)
+ .D8(google_breakpad::DW_CFA_offset | 3).ULEB128(0x995d)
+ .D8(google_breakpad::DW_CFA_offset | 4).ULEB128(0x7055)
+ .D8(google_breakpad::DW_CFA_remember_state)
// Advance to a new instruction; an implementation could legitimately
// ignore all but the final rule for a given register at a given address.
- .D8(dwarf2reader::DW_CFA_advance_loc | 1)
+ .D8(google_breakpad::DW_CFA_advance_loc | 1)
// Create the "outgoing" state, which we will discard.
- .D8(dwarf2reader::DW_CFA_offset | 1).ULEB128(0xea1a)
- .D8(dwarf2reader::DW_CFA_register).ULEB128(2).ULEB128(0x1d2a3767)
- .D8(dwarf2reader::DW_CFA_offset | 3).ULEB128(0xdd29)
- .D8(dwarf2reader::DW_CFA_offset | 5).ULEB128(0xf1ce)
+ .D8(google_breakpad::DW_CFA_offset | 1).ULEB128(0xea1a)
+ .D8(google_breakpad::DW_CFA_register).ULEB128(2).ULEB128(0x1d2a3767)
+ .D8(google_breakpad::DW_CFA_offset | 3).ULEB128(0xdd29)
+ .D8(google_breakpad::DW_CFA_offset | 5).ULEB128(0xf1ce)
// At a third address, restore the incoming state.
- .D8(dwarf2reader::DW_CFA_advance_loc | 1)
- .D8(dwarf2reader::DW_CFA_restore_state)
+ .D8(google_breakpad::DW_CFA_advance_loc | 1)
+ .D8(google_breakpad::DW_CFA_restore_state)
.FinishEntry();
uint64_t addr = fde_start;
@@ -1496,11 +1496,11 @@ TEST_F(CFIInsn, DW_CFA_remember_and_restore_stateCFA) {
StockCIEAndFDE(&section);
section
- .D8(dwarf2reader::DW_CFA_remember_state)
- .D8(dwarf2reader::DW_CFA_advance_loc | 1)
- .D8(dwarf2reader::DW_CFA_def_cfa_offset).ULEB128(0x90481102)
- .D8(dwarf2reader::DW_CFA_advance_loc | 1)
- .D8(dwarf2reader::DW_CFA_restore_state)
+ .D8(google_breakpad::DW_CFA_remember_state)
+ .D8(google_breakpad::DW_CFA_advance_loc | 1)
+ .D8(google_breakpad::DW_CFA_def_cfa_offset).ULEB128(0x90481102)
+ .D8(google_breakpad::DW_CFA_advance_loc | 1)
+ .D8(google_breakpad::DW_CFA_restore_state)
.FinishEntry();
EXPECT_CALL(handler, ValOffsetRule(fde_start + code_factor, kCFARegister,
@@ -1519,9 +1519,9 @@ TEST_F(CFIInsn, DW_CFA_nop) {
CFISection section(kLittleEndian, 4);
StockCIEAndFDE(&section);
section
- .D8(dwarf2reader::DW_CFA_nop)
- .D8(dwarf2reader::DW_CFA_def_cfa).ULEB128(0x3fb8d4f1).ULEB128(0x078dc67b)
- .D8(dwarf2reader::DW_CFA_nop)
+ .D8(google_breakpad::DW_CFA_nop)
+ .D8(google_breakpad::DW_CFA_def_cfa).ULEB128(0x3fb8d4f1).ULEB128(0x078dc67b)
+ .D8(google_breakpad::DW_CFA_nop)
.FinishEntry();
EXPECT_CALL(handler,
@@ -1536,9 +1536,11 @@ TEST_F(CFIInsn, DW_CFA_GNU_window_save) {
CFISection section(kBigEndian, 4);
StockCIEAndFDE(&section);
section
- .D8(dwarf2reader::DW_CFA_GNU_window_save)
+ .D8(google_breakpad::DW_CFA_GNU_window_save)
.FinishEntry();
+ EXPECT_CALL(handler, Architecture()).WillRepeatedly(Return("sparc"));
+
// Don't include all the rules in any particular sequence.
// The caller's %o0-%o7 have become the callee's %i0-%i7. This is
@@ -1561,9 +1563,9 @@ TEST_F(CFIInsn, DW_CFA_GNU_args_size) {
CFISection section(kLittleEndian, 8);
StockCIEAndFDE(&section);
section
- .D8(dwarf2reader::DW_CFA_GNU_args_size).ULEB128(0xeddfa520)
+ .D8(google_breakpad::DW_CFA_GNU_args_size).ULEB128(0xeddfa520)
// Verify that we see this, meaning we parsed the above properly.
- .D8(dwarf2reader::DW_CFA_offset | 0x23).ULEB128(0x269)
+ .D8(google_breakpad::DW_CFA_offset | 0x23).ULEB128(0x269)
.FinishEntry();
EXPECT_CALL(handler,
@@ -1578,7 +1580,7 @@ TEST_F(CFIInsn, DW_CFA_GNU_negative_offset_extended) {
CFISection section(kLittleEndian, 4);
StockCIEAndFDE(&section);
section
- .D8(dwarf2reader::DW_CFA_GNU_negative_offset_extended)
+ .D8(google_breakpad::DW_CFA_GNU_negative_offset_extended)
.ULEB128(0x430cc87a).ULEB128(0x613)
.FinishEntry();
@@ -1599,19 +1601,19 @@ TEST_F(CFIInsn, SkipFDE) {
// CIE, used by all FDEs.
.Mark(&cie)
.CIEHeader(0x010269f2, 0x9177, 0xedca5849, 2, "")
- .D8(dwarf2reader::DW_CFA_def_cfa).ULEB128(0x42ed390b).ULEB128(0x98f43aad)
+ .D8(google_breakpad::DW_CFA_def_cfa).ULEB128(0x42ed390b).ULEB128(0x98f43aad)
.FinishEntry()
// First FDE.
.FDEHeader(cie, 0xa870ebdd, 0x60f6aa4)
- .D8(dwarf2reader::DW_CFA_register).ULEB128(0x3a860351).ULEB128(0x6c9a6bcf)
+ .D8(google_breakpad::DW_CFA_register).ULEB128(0x3a860351).ULEB128(0x6c9a6bcf)
.FinishEntry()
// Second FDE.
.FDEHeader(cie, 0xc534f7c0, 0xf6552e9, true /* dwarf64 */)
- .D8(dwarf2reader::DW_CFA_register).ULEB128(0x1b62c234).ULEB128(0x26586b18)
+ .D8(google_breakpad::DW_CFA_register).ULEB128(0x1b62c234).ULEB128(0x26586b18)
.FinishEntry()
// Third FDE.
.FDEHeader(cie, 0xf681cfc8, 0x7e4594e)
- .D8(dwarf2reader::DW_CFA_register).ULEB128(0x26c53934).ULEB128(0x18eeb8a4)
+ .D8(google_breakpad::DW_CFA_register).ULEB128(0x26c53934).ULEB128(0x18eeb8a4)
.FinishEntry();
{
@@ -1652,8 +1654,8 @@ TEST_F(CFIInsn, QuitMidentry) {
CFISection section(kLittleEndian, 8);
StockCIEAndFDE(&section);
section
- .D8(dwarf2reader::DW_CFA_register).ULEB128(0xe0cf850d).ULEB128(0x15aab431)
- .D8(dwarf2reader::DW_CFA_expression).ULEB128(0x46750aa5).Block("meat")
+ .D8(google_breakpad::DW_CFA_register).ULEB128(0xe0cf850d).ULEB128(0x15aab431)
+ .D8(google_breakpad::DW_CFA_expression).ULEB128(0x46750aa5).Block("meat")
.FinishEntry();
EXPECT_CALL(handler, RegisterRule(fde_start, 0xe0cf850d, 0x15aab431))
@@ -1670,10 +1672,10 @@ TEST_F(CFIRestore, RestoreUndefinedRuleUnchanged) {
CFISection section(kLittleEndian, 4);
StockCIEAndFDE(&section);
section
- .D8(dwarf2reader::DW_CFA_undefined).ULEB128(0x0bac878e)
- .D8(dwarf2reader::DW_CFA_remember_state)
- .D8(dwarf2reader::DW_CFA_advance_loc | 1)
- .D8(dwarf2reader::DW_CFA_restore_state)
+ .D8(google_breakpad::DW_CFA_undefined).ULEB128(0x0bac878e)
+ .D8(google_breakpad::DW_CFA_remember_state)
+ .D8(google_breakpad::DW_CFA_advance_loc | 1)
+ .D8(google_breakpad::DW_CFA_restore_state)
.FinishEntry();
EXPECT_CALL(handler, UndefinedRule(fde_start, 0x0bac878e))
@@ -1687,12 +1689,12 @@ TEST_F(CFIRestore, RestoreUndefinedRuleChanged) {
CFISection section(kLittleEndian, 4);
StockCIEAndFDE(&section);
section
- .D8(dwarf2reader::DW_CFA_undefined).ULEB128(0x7dedff5f)
- .D8(dwarf2reader::DW_CFA_remember_state)
- .D8(dwarf2reader::DW_CFA_advance_loc | 1)
- .D8(dwarf2reader::DW_CFA_same_value).ULEB128(0x7dedff5f)
- .D8(dwarf2reader::DW_CFA_advance_loc | 1)
- .D8(dwarf2reader::DW_CFA_restore_state)
+ .D8(google_breakpad::DW_CFA_undefined).ULEB128(0x7dedff5f)
+ .D8(google_breakpad::DW_CFA_remember_state)
+ .D8(google_breakpad::DW_CFA_advance_loc | 1)
+ .D8(google_breakpad::DW_CFA_same_value).ULEB128(0x7dedff5f)
+ .D8(google_breakpad::DW_CFA_advance_loc | 1)
+ .D8(google_breakpad::DW_CFA_restore_state)
.FinishEntry();
EXPECT_CALL(handler, UndefinedRule(fde_start, 0x7dedff5f))
@@ -1710,10 +1712,10 @@ TEST_F(CFIRestore, RestoreSameValueRuleUnchanged) {
CFISection section(kLittleEndian, 4);
StockCIEAndFDE(&section);
section
- .D8(dwarf2reader::DW_CFA_same_value).ULEB128(0xadbc9b3a)
- .D8(dwarf2reader::DW_CFA_remember_state)
- .D8(dwarf2reader::DW_CFA_advance_loc | 1)
- .D8(dwarf2reader::DW_CFA_restore_state)
+ .D8(google_breakpad::DW_CFA_same_value).ULEB128(0xadbc9b3a)
+ .D8(google_breakpad::DW_CFA_remember_state)
+ .D8(google_breakpad::DW_CFA_advance_loc | 1)
+ .D8(google_breakpad::DW_CFA_restore_state)
.FinishEntry();
EXPECT_CALL(handler, SameValueRule(fde_start, 0xadbc9b3a))
@@ -1727,12 +1729,12 @@ TEST_F(CFIRestore, RestoreSameValueRuleChanged) {
CFISection section(kLittleEndian, 4);
StockCIEAndFDE(&section);
section
- .D8(dwarf2reader::DW_CFA_same_value).ULEB128(0x3d90dcb5)
- .D8(dwarf2reader::DW_CFA_remember_state)
- .D8(dwarf2reader::DW_CFA_advance_loc | 1)
- .D8(dwarf2reader::DW_CFA_undefined).ULEB128(0x3d90dcb5)
- .D8(dwarf2reader::DW_CFA_advance_loc | 1)
- .D8(dwarf2reader::DW_CFA_restore_state)
+ .D8(google_breakpad::DW_CFA_same_value).ULEB128(0x3d90dcb5)
+ .D8(google_breakpad::DW_CFA_remember_state)
+ .D8(google_breakpad::DW_CFA_advance_loc | 1)
+ .D8(google_breakpad::DW_CFA_undefined).ULEB128(0x3d90dcb5)
+ .D8(google_breakpad::DW_CFA_advance_loc | 1)
+ .D8(google_breakpad::DW_CFA_restore_state)
.FinishEntry();
EXPECT_CALL(handler, SameValueRule(fde_start, 0x3d90dcb5))
@@ -1750,10 +1752,10 @@ TEST_F(CFIRestore, RestoreOffsetRuleUnchanged) {
CFISection section(kLittleEndian, 4);
StockCIEAndFDE(&section);
section
- .D8(dwarf2reader::DW_CFA_offset | 0x14).ULEB128(0xb6f)
- .D8(dwarf2reader::DW_CFA_remember_state)
- .D8(dwarf2reader::DW_CFA_advance_loc | 1)
- .D8(dwarf2reader::DW_CFA_restore_state)
+ .D8(google_breakpad::DW_CFA_offset | 0x14).ULEB128(0xb6f)
+ .D8(google_breakpad::DW_CFA_remember_state)
+ .D8(google_breakpad::DW_CFA_advance_loc | 1)
+ .D8(google_breakpad::DW_CFA_restore_state)
.FinishEntry();
EXPECT_CALL(handler, OffsetRule(fde_start, 0x14,
@@ -1768,12 +1770,12 @@ TEST_F(CFIRestore, RestoreOffsetRuleChanged) {
CFISection section(kLittleEndian, 4);
StockCIEAndFDE(&section);
section
- .D8(dwarf2reader::DW_CFA_offset | 0x21).ULEB128(0xeb7)
- .D8(dwarf2reader::DW_CFA_remember_state)
- .D8(dwarf2reader::DW_CFA_advance_loc | 1)
- .D8(dwarf2reader::DW_CFA_undefined).ULEB128(0x21)
- .D8(dwarf2reader::DW_CFA_advance_loc | 1)
- .D8(dwarf2reader::DW_CFA_restore_state)
+ .D8(google_breakpad::DW_CFA_offset | 0x21).ULEB128(0xeb7)
+ .D8(google_breakpad::DW_CFA_remember_state)
+ .D8(google_breakpad::DW_CFA_advance_loc | 1)
+ .D8(google_breakpad::DW_CFA_undefined).ULEB128(0x21)
+ .D8(google_breakpad::DW_CFA_advance_loc | 1)
+ .D8(google_breakpad::DW_CFA_restore_state)
.FinishEntry();
EXPECT_CALL(handler, OffsetRule(fde_start, 0x21,
@@ -1793,12 +1795,12 @@ TEST_F(CFIRestore, RestoreOffsetRuleChangedOffset) {
CFISection section(kLittleEndian, 4);
StockCIEAndFDE(&section);
section
- .D8(dwarf2reader::DW_CFA_offset | 0x21).ULEB128(0x134)
- .D8(dwarf2reader::DW_CFA_remember_state)
- .D8(dwarf2reader::DW_CFA_advance_loc | 1)
- .D8(dwarf2reader::DW_CFA_offset | 0x21).ULEB128(0xf4f)
- .D8(dwarf2reader::DW_CFA_advance_loc | 1)
- .D8(dwarf2reader::DW_CFA_restore_state)
+ .D8(google_breakpad::DW_CFA_offset | 0x21).ULEB128(0x134)
+ .D8(google_breakpad::DW_CFA_remember_state)
+ .D8(google_breakpad::DW_CFA_advance_loc | 1)
+ .D8(google_breakpad::DW_CFA_offset | 0x21).ULEB128(0xf4f)
+ .D8(google_breakpad::DW_CFA_advance_loc | 1)
+ .D8(google_breakpad::DW_CFA_restore_state)
.FinishEntry();
EXPECT_CALL(handler, OffsetRule(fde_start, 0x21,
@@ -1819,10 +1821,10 @@ TEST_F(CFIRestore, RestoreValOffsetRuleUnchanged) {
CFISection section(kLittleEndian, 4);
StockCIEAndFDE(&section);
section
- .D8(dwarf2reader::DW_CFA_val_offset).ULEB128(0x829caee6).ULEB128(0xe4c)
- .D8(dwarf2reader::DW_CFA_remember_state)
- .D8(dwarf2reader::DW_CFA_advance_loc | 1)
- .D8(dwarf2reader::DW_CFA_restore_state)
+ .D8(google_breakpad::DW_CFA_val_offset).ULEB128(0x829caee6).ULEB128(0xe4c)
+ .D8(google_breakpad::DW_CFA_remember_state)
+ .D8(google_breakpad::DW_CFA_advance_loc | 1)
+ .D8(google_breakpad::DW_CFA_restore_state)
.FinishEntry();
EXPECT_CALL(handler, ValOffsetRule(fde_start, 0x829caee6,
@@ -1837,12 +1839,12 @@ TEST_F(CFIRestore, RestoreValOffsetRuleChanged) {
CFISection section(kLittleEndian, 4);
StockCIEAndFDE(&section);
section
- .D8(dwarf2reader::DW_CFA_val_offset).ULEB128(0xf17c36d6).ULEB128(0xeb7)
- .D8(dwarf2reader::DW_CFA_remember_state)
- .D8(dwarf2reader::DW_CFA_advance_loc | 1)
- .D8(dwarf2reader::DW_CFA_undefined).ULEB128(0xf17c36d6)
- .D8(dwarf2reader::DW_CFA_advance_loc | 1)
- .D8(dwarf2reader::DW_CFA_restore_state)
+ .D8(google_breakpad::DW_CFA_val_offset).ULEB128(0xf17c36d6).ULEB128(0xeb7)
+ .D8(google_breakpad::DW_CFA_remember_state)
+ .D8(google_breakpad::DW_CFA_advance_loc | 1)
+ .D8(google_breakpad::DW_CFA_undefined).ULEB128(0xf17c36d6)
+ .D8(google_breakpad::DW_CFA_advance_loc | 1)
+ .D8(google_breakpad::DW_CFA_restore_state)
.FinishEntry();
EXPECT_CALL(handler, ValOffsetRule(fde_start, 0xf17c36d6,
@@ -1862,12 +1864,12 @@ TEST_F(CFIRestore, RestoreValOffsetRuleChangedValOffset) {
CFISection section(kLittleEndian, 4);
StockCIEAndFDE(&section);
section
- .D8(dwarf2reader::DW_CFA_val_offset).ULEB128(0x2cf0ab1b).ULEB128(0x562)
- .D8(dwarf2reader::DW_CFA_remember_state)
- .D8(dwarf2reader::DW_CFA_advance_loc | 1)
- .D8(dwarf2reader::DW_CFA_val_offset).ULEB128(0x2cf0ab1b).ULEB128(0xe88)
- .D8(dwarf2reader::DW_CFA_advance_loc | 1)
- .D8(dwarf2reader::DW_CFA_restore_state)
+ .D8(google_breakpad::DW_CFA_val_offset).ULEB128(0x2cf0ab1b).ULEB128(0x562)
+ .D8(google_breakpad::DW_CFA_remember_state)
+ .D8(google_breakpad::DW_CFA_advance_loc | 1)
+ .D8(google_breakpad::DW_CFA_val_offset).ULEB128(0x2cf0ab1b).ULEB128(0xe88)
+ .D8(google_breakpad::DW_CFA_advance_loc | 1)
+ .D8(google_breakpad::DW_CFA_restore_state)
.FinishEntry();
EXPECT_CALL(handler, ValOffsetRule(fde_start, 0x2cf0ab1b,
@@ -1888,10 +1890,10 @@ TEST_F(CFIRestore, RestoreRegisterRuleUnchanged) {
CFISection section(kLittleEndian, 4);
StockCIEAndFDE(&section);
section
- .D8(dwarf2reader::DW_CFA_register).ULEB128(0x77514acc).ULEB128(0x464de4ce)
- .D8(dwarf2reader::DW_CFA_remember_state)
- .D8(dwarf2reader::DW_CFA_advance_loc | 1)
- .D8(dwarf2reader::DW_CFA_restore_state)
+ .D8(google_breakpad::DW_CFA_register).ULEB128(0x77514acc).ULEB128(0x464de4ce)
+ .D8(google_breakpad::DW_CFA_remember_state)
+ .D8(google_breakpad::DW_CFA_advance_loc | 1)
+ .D8(google_breakpad::DW_CFA_restore_state)
.FinishEntry();
EXPECT_CALL(handler, RegisterRule(fde_start, 0x77514acc, 0x464de4ce))
@@ -1905,12 +1907,12 @@ TEST_F(CFIRestore, RestoreRegisterRuleChanged) {
CFISection section(kLittleEndian, 4);
StockCIEAndFDE(&section);
section
- .D8(dwarf2reader::DW_CFA_register).ULEB128(0xe39acce5).ULEB128(0x095f1559)
- .D8(dwarf2reader::DW_CFA_remember_state)
- .D8(dwarf2reader::DW_CFA_advance_loc | 1)
- .D8(dwarf2reader::DW_CFA_undefined).ULEB128(0xe39acce5)
- .D8(dwarf2reader::DW_CFA_advance_loc | 1)
- .D8(dwarf2reader::DW_CFA_restore_state)
+ .D8(google_breakpad::DW_CFA_register).ULEB128(0xe39acce5).ULEB128(0x095f1559)
+ .D8(google_breakpad::DW_CFA_remember_state)
+ .D8(google_breakpad::DW_CFA_advance_loc | 1)
+ .D8(google_breakpad::DW_CFA_undefined).ULEB128(0xe39acce5)
+ .D8(google_breakpad::DW_CFA_advance_loc | 1)
+ .D8(google_breakpad::DW_CFA_restore_state)
.FinishEntry();
EXPECT_CALL(handler, RegisterRule(fde_start, 0xe39acce5, 0x095f1559))
@@ -1929,12 +1931,12 @@ TEST_F(CFIRestore, RestoreRegisterRuleChangedRegister) {
CFISection section(kLittleEndian, 4);
StockCIEAndFDE(&section);
section
- .D8(dwarf2reader::DW_CFA_register).ULEB128(0xd40e21b1).ULEB128(0x16607d6a)
- .D8(dwarf2reader::DW_CFA_remember_state)
- .D8(dwarf2reader::DW_CFA_advance_loc | 1)
- .D8(dwarf2reader::DW_CFA_register).ULEB128(0xd40e21b1).ULEB128(0xbabb4742)
- .D8(dwarf2reader::DW_CFA_advance_loc | 1)
- .D8(dwarf2reader::DW_CFA_restore_state)
+ .D8(google_breakpad::DW_CFA_register).ULEB128(0xd40e21b1).ULEB128(0x16607d6a)
+ .D8(google_breakpad::DW_CFA_remember_state)
+ .D8(google_breakpad::DW_CFA_advance_loc | 1)
+ .D8(google_breakpad::DW_CFA_register).ULEB128(0xd40e21b1).ULEB128(0xbabb4742)
+ .D8(google_breakpad::DW_CFA_advance_loc | 1)
+ .D8(google_breakpad::DW_CFA_restore_state)
.FinishEntry();
EXPECT_CALL(handler, RegisterRule(fde_start, 0xd40e21b1, 0x16607d6a))
@@ -1954,10 +1956,10 @@ TEST_F(CFIRestore, RestoreExpressionRuleUnchanged) {
CFISection section(kLittleEndian, 4);
StockCIEAndFDE(&section);
section
- .D8(dwarf2reader::DW_CFA_expression).ULEB128(0x666ae152).Block("dwarf")
- .D8(dwarf2reader::DW_CFA_remember_state)
- .D8(dwarf2reader::DW_CFA_advance_loc | 1)
- .D8(dwarf2reader::DW_CFA_restore_state)
+ .D8(google_breakpad::DW_CFA_expression).ULEB128(0x666ae152).Block("dwarf")
+ .D8(google_breakpad::DW_CFA_remember_state)
+ .D8(google_breakpad::DW_CFA_advance_loc | 1)
+ .D8(google_breakpad::DW_CFA_restore_state)
.FinishEntry();
EXPECT_CALL(handler, ExpressionRule(fde_start, 0x666ae152, "dwarf"))
@@ -1971,12 +1973,12 @@ TEST_F(CFIRestore, RestoreExpressionRuleChanged) {
CFISection section(kLittleEndian, 4);
StockCIEAndFDE(&section);
section
- .D8(dwarf2reader::DW_CFA_expression).ULEB128(0xb5ca5c46).Block("elf")
- .D8(dwarf2reader::DW_CFA_remember_state)
- .D8(dwarf2reader::DW_CFA_advance_loc | 1)
- .D8(dwarf2reader::DW_CFA_undefined).ULEB128(0xb5ca5c46)
- .D8(dwarf2reader::DW_CFA_advance_loc | 1)
- .D8(dwarf2reader::DW_CFA_restore_state)
+ .D8(google_breakpad::DW_CFA_expression).ULEB128(0xb5ca5c46).Block("elf")
+ .D8(google_breakpad::DW_CFA_remember_state)
+ .D8(google_breakpad::DW_CFA_advance_loc | 1)
+ .D8(google_breakpad::DW_CFA_undefined).ULEB128(0xb5ca5c46)
+ .D8(google_breakpad::DW_CFA_advance_loc | 1)
+ .D8(google_breakpad::DW_CFA_restore_state)
.FinishEntry();
EXPECT_CALL(handler, ExpressionRule(fde_start, 0xb5ca5c46, "elf"))
@@ -1995,12 +1997,12 @@ TEST_F(CFIRestore, RestoreExpressionRuleChangedExpression) {
CFISection section(kLittleEndian, 4);
StockCIEAndFDE(&section);
section
- .D8(dwarf2reader::DW_CFA_expression).ULEB128(0x500f5739).Block("smurf")
- .D8(dwarf2reader::DW_CFA_remember_state)
- .D8(dwarf2reader::DW_CFA_advance_loc | 1)
- .D8(dwarf2reader::DW_CFA_expression).ULEB128(0x500f5739).Block("orc")
- .D8(dwarf2reader::DW_CFA_advance_loc | 1)
- .D8(dwarf2reader::DW_CFA_restore_state)
+ .D8(google_breakpad::DW_CFA_expression).ULEB128(0x500f5739).Block("smurf")
+ .D8(google_breakpad::DW_CFA_remember_state)
+ .D8(google_breakpad::DW_CFA_advance_loc | 1)
+ .D8(google_breakpad::DW_CFA_expression).ULEB128(0x500f5739).Block("orc")
+ .D8(google_breakpad::DW_CFA_advance_loc | 1)
+ .D8(google_breakpad::DW_CFA_restore_state)
.FinishEntry();
EXPECT_CALL(handler, ExpressionRule(fde_start, 0x500f5739, "smurf"))
@@ -2021,11 +2023,11 @@ TEST_F(CFIRestore, RestoreValExpressionRuleUnchanged) {
CFISection section(kLittleEndian, 4);
StockCIEAndFDE(&section);
section
- .D8(dwarf2reader::DW_CFA_val_expression).ULEB128(0x666ae152)
+ .D8(google_breakpad::DW_CFA_val_expression).ULEB128(0x666ae152)
.Block("hideous")
- .D8(dwarf2reader::DW_CFA_remember_state)
- .D8(dwarf2reader::DW_CFA_advance_loc | 1)
- .D8(dwarf2reader::DW_CFA_restore_state)
+ .D8(google_breakpad::DW_CFA_remember_state)
+ .D8(google_breakpad::DW_CFA_advance_loc | 1)
+ .D8(google_breakpad::DW_CFA_restore_state)
.FinishEntry();
EXPECT_CALL(handler, ValExpressionRule(fde_start, 0x666ae152, "hideous"))
@@ -2039,13 +2041,13 @@ TEST_F(CFIRestore, RestoreValExpressionRuleChanged) {
CFISection section(kLittleEndian, 4);
StockCIEAndFDE(&section);
section
- .D8(dwarf2reader::DW_CFA_val_expression).ULEB128(0xb5ca5c46)
+ .D8(google_breakpad::DW_CFA_val_expression).ULEB128(0xb5ca5c46)
.Block("revolting")
- .D8(dwarf2reader::DW_CFA_remember_state)
- .D8(dwarf2reader::DW_CFA_advance_loc | 1)
- .D8(dwarf2reader::DW_CFA_undefined).ULEB128(0xb5ca5c46)
- .D8(dwarf2reader::DW_CFA_advance_loc | 1)
- .D8(dwarf2reader::DW_CFA_restore_state)
+ .D8(google_breakpad::DW_CFA_remember_state)
+ .D8(google_breakpad::DW_CFA_advance_loc | 1)
+ .D8(google_breakpad::DW_CFA_undefined).ULEB128(0xb5ca5c46)
+ .D8(google_breakpad::DW_CFA_advance_loc | 1)
+ .D8(google_breakpad::DW_CFA_restore_state)
.FinishEntry();
PERHAPS_WRITE_DEBUG_FRAME_FILE("RestoreValExpressionRuleChanged", section);
@@ -2066,14 +2068,14 @@ TEST_F(CFIRestore, RestoreValExpressionRuleChangedValExpression) {
CFISection section(kLittleEndian, 4);
StockCIEAndFDE(&section);
section
- .D8(dwarf2reader::DW_CFA_val_expression).ULEB128(0x500f5739)
+ .D8(google_breakpad::DW_CFA_val_expression).ULEB128(0x500f5739)
.Block("repulsive")
- .D8(dwarf2reader::DW_CFA_remember_state)
- .D8(dwarf2reader::DW_CFA_advance_loc | 1)
- .D8(dwarf2reader::DW_CFA_val_expression).ULEB128(0x500f5739)
+ .D8(google_breakpad::DW_CFA_remember_state)
+ .D8(google_breakpad::DW_CFA_advance_loc | 1)
+ .D8(google_breakpad::DW_CFA_val_expression).ULEB128(0x500f5739)
.Block("nauseous")
- .D8(dwarf2reader::DW_CFA_advance_loc | 1)
- .D8(dwarf2reader::DW_CFA_restore_state)
+ .D8(google_breakpad::DW_CFA_advance_loc | 1)
+ .D8(google_breakpad::DW_CFA_restore_state)
.FinishEntry();
PERHAPS_WRITE_DEBUG_FRAME_FILE("RestoreValExpressionRuleChangedValExpression",
@@ -2110,7 +2112,7 @@ struct EHFrameFixture: public CFIInsnFixture {
EXPECT_TRUE(section->ContainsEHFrame());
string contents;
EXPECT_TRUE(section->GetContents(&contents));
- dwarf2reader::Endianness endianness;
+ google_breakpad::Endianness endianness;
if (section->endianness() == kBigEndian)
endianness = ENDIANNESS_BIG;
else {
@@ -2120,10 +2122,10 @@ struct EHFrameFixture: public CFIInsnFixture {
ByteReader byte_reader(endianness);
byte_reader.SetAddressSize(section->AddressSize());
byte_reader.SetCFIDataBase(encoded_pointer_bases.cfi,
- reinterpret_cast<const uint8_t *>(contents.data()));
+ reinterpret_cast<const uint8_t*>(contents.data()));
byte_reader.SetTextBase(encoded_pointer_bases.text);
byte_reader.SetDataBase(encoded_pointer_bases.data);
- CallFrameInfo parser(reinterpret_cast<const uint8_t *>(contents.data()),
+ CallFrameInfo parser(reinterpret_cast<const uint8_t*>(contents.data()),
contents.size(),
&byte_reader, &handler, &reporter, true);
if (succeeds)
@@ -2142,11 +2144,11 @@ TEST_F(EHFrame, Terminator) {
section
.Mark(&cie)
.CIEHeader(9968, 2466, 67, 1, "")
- .D8(dwarf2reader::DW_CFA_def_cfa).ULEB128(3772).ULEB128(1372)
+ .D8(google_breakpad::DW_CFA_def_cfa).ULEB128(3772).ULEB128(1372)
.FinishEntry()
.FDEHeader(cie, 0x848037a1, 0x7b30475e)
- .D8(dwarf2reader::DW_CFA_set_loc).D32(0x17713850)
- .D8(dwarf2reader::DW_CFA_undefined).ULEB128(5721)
+ .D8(google_breakpad::DW_CFA_set_loc).D32(0x17713850)
+ .D8(google_breakpad::DW_CFA_undefined).ULEB128(5721)
.FinishEntry()
.D32(0) // Terminate the sequence.
// This FDE should be ignored.
@@ -2172,12 +2174,12 @@ TEST_F(EHFrame, Terminator) {
// The parser should recognize the Linux Standards Base 'z' augmentations.
TEST_F(EHFrame, SimpleFDE) {
DwarfPointerEncoding lsda_encoding =
- DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect
- | dwarf2reader::DW_EH_PE_datarel
- | dwarf2reader::DW_EH_PE_sdata2);
+ DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect
+ | google_breakpad::DW_EH_PE_datarel
+ | google_breakpad::DW_EH_PE_sdata2);
DwarfPointerEncoding fde_encoding =
- DwarfPointerEncoding(dwarf2reader::DW_EH_PE_textrel
- | dwarf2reader::DW_EH_PE_udata2);
+ DwarfPointerEncoding(google_breakpad::DW_EH_PE_textrel
+ | google_breakpad::DW_EH_PE_udata2);
section.SetPointerEncoding(fde_encoding);
section.SetEncodedPointerBases(encoded_pointer_bases);
@@ -2187,17 +2189,17 @@ TEST_F(EHFrame, SimpleFDE) {
.CIEHeader(4873, 7012, 100, 1, "zSLPR")
.ULEB128(7) // Augmentation data length
.D8(lsda_encoding) // LSDA pointer format
- .D8(dwarf2reader::DW_EH_PE_pcrel) // personality pointer format
- .EncodedPointer(0x97baa00, dwarf2reader::DW_EH_PE_pcrel) // and value
+ .D8(google_breakpad::DW_EH_PE_pcrel) // personality pointer format
+ .EncodedPointer(0x97baa00, google_breakpad::DW_EH_PE_pcrel) // and value
.D8(fde_encoding) // FDE pointer format
- .D8(dwarf2reader::DW_CFA_def_cfa).ULEB128(6706).ULEB128(31)
+ .D8(google_breakpad::DW_CFA_def_cfa).ULEB128(6706).ULEB128(31)
.FinishEntry()
.FDEHeader(cie, 0x540f6b56, 0xf686)
.ULEB128(2) // Augmentation data length
.EncodedPointer(0xe3eab475, lsda_encoding) // LSDA pointer, signed
- .D8(dwarf2reader::DW_CFA_set_loc)
+ .D8(google_breakpad::DW_CFA_set_loc)
.EncodedPointer(0x540fa4ce, fde_encoding)
- .D8(dwarf2reader::DW_CFA_undefined).ULEB128(0x675e)
+ .D8(google_breakpad::DW_CFA_undefined).ULEB128(0x675e)
.FinishEntry()
.D32(0); // terminator
@@ -2228,12 +2230,12 @@ TEST_F(EHFrame, EmptyZ) {
.Mark(&cie)
.CIEHeader(5955, 5805, 228, 1, "z")
.ULEB128(0) // Augmentation data length
- .D8(dwarf2reader::DW_CFA_def_cfa).ULEB128(3629).ULEB128(247)
+ .D8(google_breakpad::DW_CFA_def_cfa).ULEB128(3629).ULEB128(247)
.FinishEntry()
.FDEHeader(cie, 0xda007738, 0xfb55c641)
.ULEB128(0) // Augmentation data length
- .D8(dwarf2reader::DW_CFA_advance_loc1).D8(11)
- .D8(dwarf2reader::DW_CFA_undefined).ULEB128(3769)
+ .D8(google_breakpad::DW_CFA_advance_loc1).D8(11)
+ .D8(google_breakpad::DW_CFA_undefined).ULEB128(3769)
.FinishEntry();
PERHAPS_WRITE_EH_FRAME_FILE("EHFrame.EmptyZ", section);
@@ -2257,12 +2259,12 @@ TEST_F(EHFrame, BadZ) {
.Mark(&cie)
.CIEHeader(6937, 1045, 142, 1, "zQ")
.ULEB128(0) // Augmentation data length
- .D8(dwarf2reader::DW_CFA_def_cfa).ULEB128(9006).ULEB128(7725)
+ .D8(google_breakpad::DW_CFA_def_cfa).ULEB128(9006).ULEB128(7725)
.FinishEntry()
.FDEHeader(cie, 0x1293efa8, 0x236f53f2)
.ULEB128(0) // Augmentation data length
- .D8(dwarf2reader::DW_CFA_advance_loc | 12)
- .D8(dwarf2reader::DW_CFA_register).ULEB128(5667).ULEB128(3462)
+ .D8(google_breakpad::DW_CFA_advance_loc | 12)
+ .D8(google_breakpad::DW_CFA_register).ULEB128(5667).ULEB128(3462)
.FinishEntry();
PERHAPS_WRITE_EH_FRAME_FILE("EHFrame.BadZ", section);
@@ -2276,8 +2278,8 @@ TEST_F(EHFrame, BadZ) {
TEST_F(EHFrame, zL) {
Label cie;
DwarfPointerEncoding lsda_encoding =
- DwarfPointerEncoding(dwarf2reader::DW_EH_PE_funcrel
- | dwarf2reader::DW_EH_PE_udata2);
+ DwarfPointerEncoding(google_breakpad::DW_EH_PE_funcrel
+ | google_breakpad::DW_EH_PE_udata2);
section
.Mark(&cie)
.CIEHeader(9285, 9959, 54, 1, "zL")
@@ -2306,8 +2308,8 @@ TEST_F(EHFrame, zL) {
TEST_F(EHFrame, zP) {
Label cie;
DwarfPointerEncoding personality_encoding =
- DwarfPointerEncoding(dwarf2reader::DW_EH_PE_datarel
- | dwarf2reader::DW_EH_PE_udata2);
+ DwarfPointerEncoding(google_breakpad::DW_EH_PE_datarel
+ | google_breakpad::DW_EH_PE_udata2);
section
.Mark(&cie)
.CIEHeader(1097, 6313, 17, 1, "zP")
@@ -2335,8 +2337,8 @@ TEST_F(EHFrame, zP) {
TEST_F(EHFrame, zR) {
Label cie;
DwarfPointerEncoding pointer_encoding =
- DwarfPointerEncoding(dwarf2reader::DW_EH_PE_textrel
- | dwarf2reader::DW_EH_PE_sdata2);
+ DwarfPointerEncoding(google_breakpad::DW_EH_PE_textrel
+ | google_breakpad::DW_EH_PE_sdata2);
section.SetPointerEncoding(pointer_encoding);
section
.Mark(&cie)
@@ -2468,7 +2470,7 @@ struct ELFSectionHeader {
uint64_t entry_size;
};
-void AppendSectionHeader(CFISection *table, const ELFSectionHeader &header) {
+void AppendSectionHeader(CFISection* table, const ELFSectionHeader& header) {
(*table)
.D32(header.name) // name, index in string tbl
.D32(header.type) // type
@@ -2483,7 +2485,7 @@ void AppendSectionHeader(CFISection *table, const ELFSectionHeader &header) {
}
void WriteELFFrameSection(const char *filename, const char *cfi_name,
- const CFISection &cfi) {
+ const CFISection& cfi) {
int elf_class = cfi.AddressSize() == 4 ? ELFCLASS32 : ELFCLASS64;
int elf_data = (cfi.endianness() == kBigEndian
? ELFDATA2MSB : ELFDATA2LSB);
diff --git a/src/common/dwarf/dwarf2reader_die_unittest.cc b/src/common/dwarf/dwarf2reader_die_unittest.cc
index ca44cad0..fc639a64 100644
--- a/src/common/dwarf/dwarf2reader_die_unittest.cc
+++ b/src/common/dwarf/dwarf2reader_die_unittest.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2012, Google Inc.
-// All rights reserved.
+// Copyright 2012 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -29,7 +28,7 @@
// Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com>
-// dwarf2reader_die_unittest.cc: Unit tests for dwarf2reader::CompilationUnit
+// dwarf2reader_die_unittest.cc: Unit tests for google_breakpad::CompilationUnit
#include <stdint.h>
#include <stdlib.h>
@@ -51,16 +50,16 @@ using google_breakpad::test_assembler::Section;
using google_breakpad::test_assembler::kBigEndian;
using google_breakpad::test_assembler::kLittleEndian;
-using dwarf2reader::ByteReader;
-using dwarf2reader::CompilationUnit;
-using dwarf2reader::Dwarf2Handler;
-using dwarf2reader::DwarfAttribute;
-using dwarf2reader::DwarfForm;
-using dwarf2reader::DwarfHasChild;
-using dwarf2reader::DwarfTag;
-using dwarf2reader::ENDIANNESS_BIG;
-using dwarf2reader::ENDIANNESS_LITTLE;
-using dwarf2reader::SectionMap;
+using google_breakpad::ByteReader;
+using google_breakpad::CompilationUnit;
+using google_breakpad::Dwarf2Handler;
+using google_breakpad::DwarfAttribute;
+using google_breakpad::DwarfForm;
+using google_breakpad::DwarfHasChild;
+using google_breakpad::DwarfTag;
+using google_breakpad::ENDIANNESS_BIG;
+using google_breakpad::ENDIANNESS_LITTLE;
+using google_breakpad::SectionMap;
using std::vector;
using testing::InSequence;
@@ -93,7 +92,7 @@ class MockDwarf2Handler: public Dwarf2Handler {
MOCK_METHOD5(ProcessAttributeBuffer, void(uint64_t offset,
enum DwarfAttribute attr,
enum DwarfForm form,
- const uint8_t *data,
+ const uint8_t* data,
uint64_t len));
MOCK_METHOD4(ProcessAttributeString, void(uint64_t offset,
enum DwarfAttribute attr,
@@ -128,17 +127,17 @@ struct DIEFixture {
// to |info|, and whose .debug_abbrev section refers to |abbrevs|. This
// function returns a reference to the same SectionMap each time; new
// calls wipe out maps established by earlier calls.
- const SectionMap &MakeSectionMap() {
+ const SectionMap& MakeSectionMap() {
// Copy the sections' contents into strings that will live as long as
// the map itself.
assert(info.GetContents(&info_contents));
assert(abbrevs.GetContents(&abbrevs_contents));
section_map.clear();
section_map[".debug_info"].first
- = reinterpret_cast<const uint8_t *>(info_contents.data());
+ = reinterpret_cast<const uint8_t*>(info_contents.data());
section_map[".debug_info"].second = info_contents.size();
section_map[".debug_abbrev"].first
- = reinterpret_cast<const uint8_t *>(abbrevs_contents.data());
+ = reinterpret_cast<const uint8_t*>(abbrevs_contents.data());
section_map[".debug_abbrev"].second = abbrevs_contents.size();
return section_map;
}
@@ -152,13 +151,15 @@ struct DIEFixture {
struct DwarfHeaderParams {
DwarfHeaderParams(Endianness endianness, size_t format_size,
- int version, size_t address_size)
+ int version, size_t address_size, int header_type)
: endianness(endianness), format_size(format_size),
- version(version), address_size(address_size) { }
+ version(version), address_size(address_size), header_type(header_type)
+ { }
Endianness endianness;
size_t format_size; // 4-byte or 8-byte DWARF offsets
int version;
size_t address_size;
+ int header_type; // DW_UT_{compile, type, partial, skeleton, etc}
};
class DwarfHeader: public DIEFixture,
@@ -166,16 +167,17 @@ class DwarfHeader: public DIEFixture,
TEST_P(DwarfHeader, Header) {
Label abbrev_table = abbrevs.Here();
- abbrevs.Abbrev(1, dwarf2reader::DW_TAG_compile_unit,
- dwarf2reader::DW_children_yes)
- .Attribute(dwarf2reader::DW_AT_name, dwarf2reader::DW_FORM_string)
+ abbrevs.Abbrev(1, google_breakpad::DW_TAG_compile_unit,
+ google_breakpad::DW_children_yes)
+ .Attribute(google_breakpad::DW_AT_name, google_breakpad::DW_FORM_string)
.EndAbbrev()
.EndTable();
info.set_format_size(GetParam().format_size);
info.set_endianness(GetParam().endianness);
- info.Header(GetParam().version, abbrev_table, GetParam().address_size)
+ info.Header(GetParam().version, abbrev_table, GetParam().address_size,
+ google_breakpad::DW_UT_compile)
.ULEB128(1) // DW_TAG_compile_unit, with children
.AppendCString("sam") // DW_AT_name, DW_FORM_string
.D8(0); // end of children
@@ -188,10 +190,10 @@ TEST_P(DwarfHeader, Header) {
GetParam().format_size, _,
GetParam().version))
.WillOnce(Return(true));
- EXPECT_CALL(handler, StartDIE(_, dwarf2reader::DW_TAG_compile_unit))
+ EXPECT_CALL(handler, StartDIE(_, google_breakpad::DW_TAG_compile_unit))
.WillOnce(Return(true));
- EXPECT_CALL(handler, ProcessAttributeString(_, dwarf2reader::DW_AT_name,
- dwarf2reader::DW_FORM_string,
+ EXPECT_CALL(handler, ProcessAttributeString(_, google_breakpad::DW_AT_name,
+ google_breakpad::DW_FORM_string,
"sam"))
.WillOnce(Return());
EXPECT_CALL(handler, EndDIE(_))
@@ -204,44 +206,91 @@ TEST_P(DwarfHeader, Header) {
EXPECT_EQ(parser.Start(), info_contents.size());
}
-INSTANTIATE_TEST_CASE_P(
+TEST_P(DwarfHeader, TypeUnitHeader) {
+ Label abbrev_table = abbrevs.Here();
+ int version = 5;
+ abbrevs.Abbrev(1, google_breakpad::DW_TAG_type_unit,
+ google_breakpad::DW_children_yes)
+ .Attribute(google_breakpad::DW_AT_name, google_breakpad::DW_FORM_string)
+ .EndAbbrev()
+ .EndTable();
+
+ info.set_format_size(GetParam().format_size);
+ info.set_endianness(GetParam().endianness);
+
+ info.Header(version, abbrev_table, GetParam().address_size,
+ google_breakpad::DW_UT_type)
+ .ULEB128(0x41) // DW_TAG_type_unit, with children
+ .AppendCString("sam") // DW_AT_name, DW_FORM_string
+ .D8(0); // end of children
+ info.Finish();
+
+ {
+ InSequence s;
+ EXPECT_CALL(handler,
+ StartCompilationUnit(0, GetParam().address_size,
+ GetParam().format_size, _,
+ version))
+ .WillOnce(Return(true));
+ // If the type unit is handled properly, these calls will be skipped.
+ EXPECT_CALL(handler, StartDIE(_, google_breakpad::DW_TAG_type_unit))
+ .Times(0);
+ EXPECT_CALL(handler, ProcessAttributeString(_, google_breakpad::DW_AT_name,
+ google_breakpad::DW_FORM_string,
+ "sam"))
+ .Times(0);
+ EXPECT_CALL(handler, EndDIE(_))
+ .Times(0);
+ }
+
+ ByteReader byte_reader(GetParam().endianness == kLittleEndian ?
+ ENDIANNESS_LITTLE : ENDIANNESS_BIG);
+ CompilationUnit parser("", MakeSectionMap(), 0, &byte_reader, &handler);
+ EXPECT_EQ(parser.Start(), info_contents.size());
+}
+
+INSTANTIATE_TEST_SUITE_P(
HeaderVariants, DwarfHeader,
- ::testing::Values(DwarfHeaderParams(kLittleEndian, 4, 2, 4),
- DwarfHeaderParams(kLittleEndian, 4, 2, 8),
- DwarfHeaderParams(kLittleEndian, 4, 3, 4),
- DwarfHeaderParams(kLittleEndian, 4, 3, 8),
- DwarfHeaderParams(kLittleEndian, 4, 4, 4),
- DwarfHeaderParams(kLittleEndian, 4, 4, 8),
- DwarfHeaderParams(kLittleEndian, 8, 2, 4),
- DwarfHeaderParams(kLittleEndian, 8, 2, 8),
- DwarfHeaderParams(kLittleEndian, 8, 3, 4),
- DwarfHeaderParams(kLittleEndian, 8, 3, 8),
- DwarfHeaderParams(kLittleEndian, 8, 4, 4),
- DwarfHeaderParams(kLittleEndian, 8, 4, 8),
- DwarfHeaderParams(kBigEndian, 4, 2, 4),
- DwarfHeaderParams(kBigEndian, 4, 2, 8),
- DwarfHeaderParams(kBigEndian, 4, 3, 4),
- DwarfHeaderParams(kBigEndian, 4, 3, 8),
- DwarfHeaderParams(kBigEndian, 4, 4, 4),
- DwarfHeaderParams(kBigEndian, 4, 4, 8),
- DwarfHeaderParams(kBigEndian, 8, 2, 4),
- DwarfHeaderParams(kBigEndian, 8, 2, 8),
- DwarfHeaderParams(kBigEndian, 8, 3, 4),
- DwarfHeaderParams(kBigEndian, 8, 3, 8),
- DwarfHeaderParams(kBigEndian, 8, 4, 4),
- DwarfHeaderParams(kBigEndian, 8, 4, 8)));
+ ::testing::Values(DwarfHeaderParams(kLittleEndian, 4, 2, 4, 1),
+ DwarfHeaderParams(kLittleEndian, 4, 2, 8, 1),
+ DwarfHeaderParams(kLittleEndian, 4, 3, 4, 1),
+ DwarfHeaderParams(kLittleEndian, 4, 3, 8, 1),
+ DwarfHeaderParams(kLittleEndian, 4, 4, 4, 1),
+ DwarfHeaderParams(kLittleEndian, 4, 4, 8, 1),
+ DwarfHeaderParams(kLittleEndian, 8, 2, 4, 1),
+ DwarfHeaderParams(kLittleEndian, 8, 2, 8, 1),
+ DwarfHeaderParams(kLittleEndian, 8, 3, 4, 1),
+ DwarfHeaderParams(kLittleEndian, 8, 3, 8, 1),
+ DwarfHeaderParams(kLittleEndian, 8, 4, 4, 1),
+ DwarfHeaderParams(kLittleEndian, 8, 4, 8, 1),
+ DwarfHeaderParams(kLittleEndian, 8, 5, 4, 1),
+ DwarfHeaderParams(kLittleEndian, 8, 5, 8, 1),
+ DwarfHeaderParams(kBigEndian, 4, 2, 4, 1),
+ DwarfHeaderParams(kBigEndian, 4, 2, 8, 1),
+ DwarfHeaderParams(kBigEndian, 4, 3, 4, 1),
+ DwarfHeaderParams(kBigEndian, 4, 3, 8, 1),
+ DwarfHeaderParams(kBigEndian, 4, 4, 4, 1),
+ DwarfHeaderParams(kBigEndian, 4, 4, 8, 1),
+ DwarfHeaderParams(kBigEndian, 8, 2, 4, 1),
+ DwarfHeaderParams(kBigEndian, 8, 2, 8, 1),
+ DwarfHeaderParams(kBigEndian, 8, 3, 4, 1),
+ DwarfHeaderParams(kBigEndian, 8, 3, 8, 1),
+ DwarfHeaderParams(kBigEndian, 8, 4, 4, 1),
+ DwarfHeaderParams(kBigEndian, 8, 4, 8, 1),
+ DwarfHeaderParams(kBigEndian, 8, 5, 4, 1),
+ DwarfHeaderParams(kBigEndian, 8, 5, 8, 1)));
struct DwarfFormsFixture: public DIEFixture {
// Start a compilation unit, as directed by |params|, containing one
// childless DIE of the given tag, with one attribute of the given name
// and form. The 'info' fixture member is left just after the abbrev
// code, waiting for the attribute value to be appended.
- void StartSingleAttributeDIE(const DwarfHeaderParams &params,
+ void StartSingleAttributeDIE(const DwarfHeaderParams& params,
DwarfTag tag, DwarfAttribute name,
DwarfForm form) {
// Create the abbreviation table.
Label abbrev_table = abbrevs.Here();
- abbrevs.Abbrev(1, tag, dwarf2reader::DW_children_no)
+ abbrevs.Abbrev(1, tag, google_breakpad::DW_children_no)
.Attribute(name, form)
.EndAbbrev()
.EndTable();
@@ -249,14 +298,15 @@ struct DwarfFormsFixture: public DIEFixture {
// Create the compilation unit, up to the attribute value.
info.set_format_size(params.format_size);
info.set_endianness(params.endianness);
- info.Header(params.version, abbrev_table, params.address_size)
+ info.Header(params.version, abbrev_table, params.address_size,
+ google_breakpad::DW_UT_compile)
.ULEB128(1); // abbrev code
}
// Set up handler to expect a compilation unit matching |params|,
// containing one childless DIE of the given tag, in the sequence s. Stop
// just before the expectations.
- void ExpectBeginCompilationUnit(const DwarfHeaderParams &params,
+ void ExpectBeginCompilationUnit(const DwarfHeaderParams& params,
DwarfTag tag, uint64_t offset=0) {
EXPECT_CALL(handler,
StartCompilationUnit(offset, params.address_size,
@@ -275,7 +325,7 @@ struct DwarfFormsFixture: public DIEFixture {
.WillOnce(Return());
}
- void ParseCompilationUnit(const DwarfHeaderParams &params,
+ void ParseCompilationUnit(const DwarfHeaderParams& params,
uint64_t offset=0) {
ByteReader byte_reader(params.endianness == kLittleEndian ?
ENDIANNESS_LITTLE : ENDIANNESS_BIG);
@@ -291,9 +341,9 @@ struct DwarfForms: public DwarfFormsFixture,
public TestWithParam<DwarfHeaderParams> { };
TEST_P(DwarfForms, addr) {
- StartSingleAttributeDIE(GetParam(), dwarf2reader::DW_TAG_compile_unit,
- dwarf2reader::DW_AT_low_pc,
- dwarf2reader::DW_FORM_addr);
+ StartSingleAttributeDIE(GetParam(), google_breakpad::DW_TAG_compile_unit,
+ google_breakpad::DW_AT_low_pc,
+ google_breakpad::DW_FORM_addr);
uint64_t value;
if (GetParam().address_size == 4) {
value = 0xc8e9ffcc;
@@ -304,9 +354,93 @@ TEST_P(DwarfForms, addr) {
}
info.Finish();
- ExpectBeginCompilationUnit(GetParam(), dwarf2reader::DW_TAG_compile_unit);
- EXPECT_CALL(handler, ProcessAttributeUnsigned(_, dwarf2reader::DW_AT_low_pc,
- dwarf2reader::DW_FORM_addr,
+ ExpectBeginCompilationUnit(GetParam(), google_breakpad::DW_TAG_compile_unit);
+ EXPECT_CALL(handler, ProcessAttributeUnsigned(_, google_breakpad::DW_AT_low_pc,
+ google_breakpad::DW_FORM_addr,
+ value))
+ .InSequence(s)
+ .WillOnce(Return());
+ ExpectEndCompilationUnit();
+
+ ParseCompilationUnit(GetParam());
+}
+
+TEST_P(DwarfForms, strx1) {
+ if (GetParam().version != 5) {
+ return;
+ }
+ Label abbrev_table = abbrevs.Here();
+ abbrevs.Abbrev(1, google_breakpad::DW_TAG_compile_unit,
+ google_breakpad::DW_children_no)
+ .Attribute(google_breakpad::DW_AT_name, google_breakpad::DW_FORM_strx1)
+ .Attribute(google_breakpad::DW_AT_low_pc, google_breakpad::DW_FORM_addr)
+ .Attribute(google_breakpad::DW_AT_str_offsets_base,
+ google_breakpad::DW_FORM_sec_offset)
+ .EndAbbrev()
+ .EndTable();
+
+ info.set_format_size(GetParam().format_size);
+ info.set_endianness(GetParam().endianness);
+ info.Header(GetParam().version, abbrev_table, GetParam().address_size,
+ google_breakpad::DW_UT_compile)
+ .ULEB128(1) // abbrev index
+ .D8(2); // string index
+
+ uint64_t value;
+ uint64_t offsets_base;
+ if (GetParam().address_size == 4) {
+ value = 0xc8e9ffcc;
+ offsets_base = 8;
+ info.D32(value); // low pc
+ info.D32(offsets_base); // str_offsets_base
+ } else {
+ value = 0xe942517fc2768564ULL;
+ offsets_base = 16;
+ info.D64(value); // low_pc
+ info.D64(offsets_base); // str_offsets_base
+ }
+ info.Finish();
+
+ Section debug_strings;
+ // no header, just a series of null-terminated strings.
+ debug_strings.AppendCString("apple"); // offset = 0
+ debug_strings.AppendCString("bird"); // offset = 6
+ debug_strings.AppendCString("canary"); // offset = 11
+ debug_strings.AppendCString("dinosaur"); // offset = 18
+
+ Section str_offsets;
+ str_offsets.set_endianness(GetParam().endianness);
+ // Header for .debug_str_offsets
+ if (GetParam().address_size == 4) {
+ str_offsets.D32(24); // section length (4 bytes)
+ } else {
+ str_offsets.D32(0xffffffff);
+ str_offsets.D64(48); // section length (12 bytes)
+ }
+ str_offsets.D16(GetParam().version); // version (2 bytes)
+ str_offsets.D16(0); // padding (2 bytes)
+
+ // .debug_str_offsets data (the offsets)
+ if (GetParam().address_size == 4) {
+ str_offsets.D32(0);
+ str_offsets.D32(6);
+ str_offsets.D32(11);
+ str_offsets.D32(18);
+ } else {
+ str_offsets.D64(0);
+ str_offsets.D64(6);
+ str_offsets.D64(11);
+ str_offsets.D64(18);
+ }
+
+
+ ExpectBeginCompilationUnit(GetParam(), google_breakpad::DW_TAG_compile_unit);
+ EXPECT_CALL(handler, ProcessAttributeString(_, google_breakpad::DW_AT_name,
+ google_breakpad::DW_FORM_strx1,
+ "bird"))
+ .WillOnce(Return());
+ EXPECT_CALL(handler, ProcessAttributeUnsigned(_, google_breakpad::DW_AT_low_pc,
+ google_breakpad::DW_FORM_addr,
value))
.InSequence(s)
.WillOnce(Return());
@@ -318,13 +452,13 @@ TEST_P(DwarfForms, addr) {
TEST_P(DwarfForms, block2_empty) {
StartSingleAttributeDIE(GetParam(), (DwarfTag) 0x16e4d2f7,
(DwarfAttribute) 0xe52c4463,
- dwarf2reader::DW_FORM_block2);
+ google_breakpad::DW_FORM_block2);
info.D16(0);
info.Finish();
ExpectBeginCompilationUnit(GetParam(), (DwarfTag) 0x16e4d2f7);
EXPECT_CALL(handler, ProcessAttributeBuffer(_, (DwarfAttribute) 0xe52c4463,
- dwarf2reader::DW_FORM_block2,
+ google_breakpad::DW_FORM_block2,
_, 0))
.InSequence(s)
.WillOnce(Return());
@@ -336,7 +470,7 @@ TEST_P(DwarfForms, block2_empty) {
TEST_P(DwarfForms, block2) {
StartSingleAttributeDIE(GetParam(), (DwarfTag) 0x16e4d2f7,
(DwarfAttribute) 0xe52c4463,
- dwarf2reader::DW_FORM_block2);
+ google_breakpad::DW_FORM_block2);
unsigned char data[258];
memset(data, '*', sizeof(data));
info.D16(sizeof(data))
@@ -345,7 +479,7 @@ TEST_P(DwarfForms, block2) {
ExpectBeginCompilationUnit(GetParam(), (DwarfTag) 0x16e4d2f7);
EXPECT_CALL(handler, ProcessAttributeBuffer(_, (DwarfAttribute) 0xe52c4463,
- dwarf2reader::DW_FORM_block2,
+ google_breakpad::DW_FORM_block2,
Pointee('*'), 258))
.InSequence(s)
.WillOnce(Return());
@@ -357,14 +491,14 @@ TEST_P(DwarfForms, block2) {
TEST_P(DwarfForms, flag_present) {
StartSingleAttributeDIE(GetParam(), (DwarfTag) 0x3e449ac2,
(DwarfAttribute) 0x359d1972,
- dwarf2reader::DW_FORM_flag_present);
+ google_breakpad::DW_FORM_flag_present);
// DW_FORM_flag_present occupies no space in the DIE.
info.Finish();
ExpectBeginCompilationUnit(GetParam(), (DwarfTag) 0x3e449ac2);
EXPECT_CALL(handler,
ProcessAttributeUnsigned(_, (DwarfAttribute) 0x359d1972,
- dwarf2reader::DW_FORM_flag_present,
+ google_breakpad::DW_FORM_flag_present,
1))
.InSequence(s)
.WillOnce(Return());
@@ -376,7 +510,7 @@ TEST_P(DwarfForms, flag_present) {
TEST_P(DwarfForms, sec_offset) {
StartSingleAttributeDIE(GetParam(), (DwarfTag) 0x1d971689,
(DwarfAttribute) 0xa060bfd1,
- dwarf2reader::DW_FORM_sec_offset);
+ google_breakpad::DW_FORM_sec_offset);
uint64_t value;
if (GetParam().format_size == 4) {
value = 0xacc9c388;
@@ -389,7 +523,7 @@ TEST_P(DwarfForms, sec_offset) {
ExpectBeginCompilationUnit(GetParam(), (DwarfTag) 0x1d971689);
EXPECT_CALL(handler, ProcessAttributeUnsigned(_, (DwarfAttribute) 0xa060bfd1,
- dwarf2reader::DW_FORM_sec_offset,
+ google_breakpad::DW_FORM_sec_offset,
value))
.InSequence(s)
.WillOnce(Return());
@@ -401,14 +535,14 @@ TEST_P(DwarfForms, sec_offset) {
TEST_P(DwarfForms, exprloc) {
StartSingleAttributeDIE(GetParam(), (DwarfTag) 0xb6d167bb,
(DwarfAttribute) 0xba3ae5cb,
- dwarf2reader::DW_FORM_exprloc);
+ google_breakpad::DW_FORM_exprloc);
info.ULEB128(29)
.Append(29, 173);
info.Finish();
ExpectBeginCompilationUnit(GetParam(), (DwarfTag) 0xb6d167bb);
EXPECT_CALL(handler, ProcessAttributeBuffer(_, (DwarfAttribute) 0xba3ae5cb,
- dwarf2reader::DW_FORM_exprloc,
+ google_breakpad::DW_FORM_exprloc,
Pointee(173), 29))
.InSequence(s)
.WillOnce(Return());
@@ -420,13 +554,13 @@ TEST_P(DwarfForms, exprloc) {
TEST_P(DwarfForms, ref_sig8) {
StartSingleAttributeDIE(GetParam(), (DwarfTag) 0x253e7b2b,
(DwarfAttribute) 0xd708d908,
- dwarf2reader::DW_FORM_ref_sig8);
+ google_breakpad::DW_FORM_ref_sig8);
info.D64(0xf72fa0cb6ddcf9d6ULL);
info.Finish();
ExpectBeginCompilationUnit(GetParam(), (DwarfTag) 0x253e7b2b);
EXPECT_CALL(handler, ProcessAttributeSignature(_, (DwarfAttribute) 0xd708d908,
- dwarf2reader::DW_FORM_ref_sig8,
+ google_breakpad::DW_FORM_ref_sig8,
0xf72fa0cb6ddcf9d6ULL))
.InSequence(s)
.WillOnce(Return());
@@ -444,13 +578,13 @@ TEST_P(DwarfForms, ref_sig8_not_first) {
info.Append(98, '*');
StartSingleAttributeDIE(GetParam(), (DwarfTag) 0x253e7b2b,
(DwarfAttribute) 0xd708d908,
- dwarf2reader::DW_FORM_ref_sig8);
+ google_breakpad::DW_FORM_ref_sig8);
info.D64(0xf72fa0cb6ddcf9d6ULL);
info.Finish();
ExpectBeginCompilationUnit(GetParam(), (DwarfTag) 0x253e7b2b, 98);
EXPECT_CALL(handler, ProcessAttributeSignature(_, (DwarfAttribute) 0xd708d908,
- dwarf2reader::DW_FORM_ref_sig8,
+ google_breakpad::DW_FORM_ref_sig8,
0xf72fa0cb6ddcf9d6ULL))
.InSequence(s)
.WillOnce(Return());
@@ -459,31 +593,371 @@ TEST_P(DwarfForms, ref_sig8_not_first) {
ParseCompilationUnit(GetParam(), 98);
}
+TEST_P(DwarfForms, implicit_const) {
+ const DwarfHeaderParams& params = GetParam();
+ const uint64_t implicit_constant_value = 0x1234;
+ // Create the abbreviation table.
+ Label abbrev_table = abbrevs.Here();
+ abbrevs.Abbrev(1, (DwarfTag) 0x253e7b2b, google_breakpad::DW_children_no)
+ .Attribute((DwarfAttribute) 0xd708d908,
+ google_breakpad::DW_FORM_implicit_const)
+ .ULEB128(implicit_constant_value);
+ abbrevs.EndAbbrev().EndTable();
+
+ info.set_format_size(params.format_size);
+ info.set_endianness(params.endianness);
+ info.Header(params.version, abbrev_table, params.address_size,
+ google_breakpad::DW_UT_compile)
+ .ULEB128(1); // abbrev code
+ info.Finish();
+
+ ExpectBeginCompilationUnit(GetParam(), (DwarfTag) 0x253e7b2b);
+ EXPECT_CALL(handler,
+ ProcessAttributeUnsigned(_, (DwarfAttribute) 0xd708d908,
+ google_breakpad::DW_FORM_implicit_const,
+ implicit_constant_value))
+ .InSequence(s)
+ .WillOnce(Return());
+ ExpectEndCompilationUnit();
+
+ ParseCompilationUnit(GetParam());
+}
+
// Tests for the other attribute forms could go here.
-INSTANTIATE_TEST_CASE_P(
+INSTANTIATE_TEST_SUITE_P(
HeaderVariants, DwarfForms,
- ::testing::Values(DwarfHeaderParams(kLittleEndian, 4, 2, 4),
- DwarfHeaderParams(kLittleEndian, 4, 2, 8),
- DwarfHeaderParams(kLittleEndian, 4, 3, 4),
- DwarfHeaderParams(kLittleEndian, 4, 3, 8),
- DwarfHeaderParams(kLittleEndian, 4, 4, 4),
- DwarfHeaderParams(kLittleEndian, 4, 4, 8),
- DwarfHeaderParams(kLittleEndian, 8, 2, 4),
- DwarfHeaderParams(kLittleEndian, 8, 2, 8),
- DwarfHeaderParams(kLittleEndian, 8, 3, 4),
- DwarfHeaderParams(kLittleEndian, 8, 3, 8),
- DwarfHeaderParams(kLittleEndian, 8, 4, 4),
- DwarfHeaderParams(kLittleEndian, 8, 4, 8),
- DwarfHeaderParams(kBigEndian, 4, 2, 4),
- DwarfHeaderParams(kBigEndian, 4, 2, 8),
- DwarfHeaderParams(kBigEndian, 4, 3, 4),
- DwarfHeaderParams(kBigEndian, 4, 3, 8),
- DwarfHeaderParams(kBigEndian, 4, 4, 4),
- DwarfHeaderParams(kBigEndian, 4, 4, 8),
- DwarfHeaderParams(kBigEndian, 8, 2, 4),
- DwarfHeaderParams(kBigEndian, 8, 2, 8),
- DwarfHeaderParams(kBigEndian, 8, 3, 4),
- DwarfHeaderParams(kBigEndian, 8, 3, 8),
- DwarfHeaderParams(kBigEndian, 8, 4, 4),
- DwarfHeaderParams(kBigEndian, 8, 4, 8)));
+ ::testing::Values(DwarfHeaderParams(kLittleEndian, 4, 2, 4, 1),
+ DwarfHeaderParams(kLittleEndian, 4, 2, 8, 1),
+ DwarfHeaderParams(kLittleEndian, 4, 3, 4, 1),
+ DwarfHeaderParams(kLittleEndian, 4, 3, 8, 1),
+ DwarfHeaderParams(kLittleEndian, 4, 4, 4, 1),
+ DwarfHeaderParams(kLittleEndian, 4, 4, 8, 1),
+ DwarfHeaderParams(kLittleEndian, 8, 2, 4, 1),
+ DwarfHeaderParams(kLittleEndian, 8, 2, 8, 1),
+ DwarfHeaderParams(kLittleEndian, 8, 3, 4, 1),
+ DwarfHeaderParams(kLittleEndian, 8, 3, 8, 1),
+ DwarfHeaderParams(kLittleEndian, 8, 4, 4, 1),
+ DwarfHeaderParams(kLittleEndian, 8, 4, 8, 1),
+ DwarfHeaderParams(kBigEndian, 4, 2, 4, 1),
+ DwarfHeaderParams(kBigEndian, 4, 2, 8, 1),
+ DwarfHeaderParams(kBigEndian, 4, 3, 4, 1),
+ DwarfHeaderParams(kBigEndian, 4, 3, 8, 1),
+ DwarfHeaderParams(kBigEndian, 4, 4, 4, 1),
+ DwarfHeaderParams(kBigEndian, 4, 4, 8, 1),
+ DwarfHeaderParams(kBigEndian, 8, 2, 4, 1),
+ DwarfHeaderParams(kBigEndian, 8, 2, 8, 1),
+ DwarfHeaderParams(kBigEndian, 8, 3, 4, 1),
+ DwarfHeaderParams(kBigEndian, 8, 3, 8, 1),
+ DwarfHeaderParams(kBigEndian, 8, 4, 4, 1),
+ DwarfHeaderParams(kBigEndian, 8, 4, 8, 1)));
+
+class MockRangeListHandler: public google_breakpad::RangeListHandler {
+ public:
+ MOCK_METHOD(void, AddRange, (uint64_t begin, uint64_t end));
+ MOCK_METHOD(void, Finish, ());
+};
+
+TEST(RangeList, Dwarf4ReadRangeList) {
+ using google_breakpad::RangeListReader;
+ using google_breakpad::DW_FORM_sec_offset;
+
+ // Create a dwarf4 .debug_ranges section.
+ google_breakpad::test_assembler::Section ranges(kBigEndian);
+ std::string padding_offset = "padding offset";
+ ranges.Append(padding_offset);
+ const uint64_t section_offset = ranges.Size();
+ ranges.D32(1).D32(2); // (2, 3)
+ ranges.D32(0xFFFFFFFF).D32(3); // base_address = 3.
+ ranges.D32(1).D32(2); // (4, 5)
+ ranges.D32(0).D32(1); // (3, 4) An out of order entry is legal.
+ ranges.D32(0).D32(0); // End of range.
+
+ std::string section_contents;
+ ranges.GetContents(&section_contents);
+
+ ByteReader byte_reader(ENDIANNESS_BIG);
+ byte_reader.SetAddressSize(4);
+
+ RangeListReader::CURangesInfo cu_info;
+ // Only set the fields that matter for dwarf 4.
+ cu_info.version_ = 4;
+ cu_info.base_address_ = 1;
+ cu_info.buffer_ = reinterpret_cast<const uint8_t*>(section_contents.data());
+ cu_info.size_ = section_contents.size();
+
+ MockRangeListHandler handler;
+ google_breakpad::RangeListReader range_list_reader(&byte_reader, &cu_info,
+ &handler);
+ EXPECT_CALL(handler, AddRange(2, 3));
+ EXPECT_CALL(handler, AddRange(4, 5));
+ EXPECT_CALL(handler, AddRange(3, 4));
+ EXPECT_CALL(handler, Finish());
+ EXPECT_TRUE(range_list_reader.ReadRanges(DW_FORM_sec_offset,
+ section_offset));
+}
+
+TEST(RangeList, Dwarf5ReadRangeList_rnglists) {
+ using google_breakpad::RangeListReader;
+ using google_breakpad::DW_RLE_base_addressx;
+ using google_breakpad::DW_RLE_startx_endx;
+ using google_breakpad::DW_RLE_startx_length;
+ using google_breakpad::DW_RLE_offset_pair;
+ using google_breakpad::DW_RLE_end_of_list;
+ using google_breakpad::DW_RLE_base_address;
+ using google_breakpad::DW_RLE_start_end;
+ using google_breakpad::DW_RLE_start_length;
+ using google_breakpad::DW_FORM_sec_offset;
+ using google_breakpad::DW_FORM_rnglistx;
+
+ // Size of header
+ const uint64_t header_size = 12;
+ // Size of length field in header
+ const uint64_t length_size = 4;
+
+ // .debug_addr for the indexed entries like startx.
+ Section addr;
+ addr.set_endianness(kBigEndian);
+ // Test addr_base handling with a padding address at 0.
+ addr.D32(0).D32(1).D32(2).D32(3).D32(4);
+ std::string addr_contents;
+ assert(addr.GetContents(&addr_contents));
+
+ // .debug_rnglists is the dwarf 5 section.
+ Section rnglists1(kBigEndian);
+ Section rnglists2(kBigEndian);
+
+ // First header and body.
+ Label section_size1;
+ rnglists1.Append(kBigEndian, length_size, section_size1);
+ rnglists1.D16(5); // Version
+ rnglists1.D8(4); // Address size
+ rnglists1.D8(0); // Segment selector size
+ rnglists1.D32(2); // Offset entry count
+ const uint64_t ranges_base_1 = rnglists1.Size();
+
+ // Offset entries.
+ Label range0;
+ rnglists1.Append(kBigEndian, 4, range0);
+ Label range1;
+ rnglists1.Append(kBigEndian, 4, range1);
+
+ // Range 0 (will be read via DW_AT_ranges, DW_FORM_rnglistx).
+ range0 = rnglists1.Size() - header_size;
+ rnglists1.D8(DW_RLE_base_addressx).ULEB128(0); // base_addr = 1
+ rnglists1.D8(DW_RLE_startx_endx).ULEB128(1).ULEB128(2); // [2, 3)
+ rnglists1.D8(DW_RLE_startx_length).ULEB128(3).ULEB128(1); // [4, 5)
+ rnglists1.D8(DW_RLE_offset_pair).ULEB128(5).ULEB128(6); // [6, 7)
+ rnglists1.D8(DW_RLE_end_of_list);
+
+ // Range 1 (will be read via DW_AT_ranges, DW_FORM_rnglistx).
+ range1 = rnglists1.Size() - header_size;
+ rnglists1.D8(DW_RLE_base_address).D32(8); // base_addr = 8
+ rnglists1.D8(DW_RLE_offset_pair).ULEB128(1).ULEB128(2); // [9, 10)
+ rnglists1.D8(DW_RLE_start_end).D32(10).D32(11); // [10, 11)
+ rnglists1.D8(DW_RLE_start_length).D32(12).ULEB128(1); // [12, 13)
+ rnglists1.D8(DW_RLE_end_of_list);
+ // The size doesn't include the size of length field itself.
+ section_size1 = rnglists1.Size() - length_size;
+
+ // Second header and body.
+ Label section_size2;
+ rnglists2.Append(kBigEndian, length_size, section_size2);
+ rnglists2.D16(5); // Version
+ rnglists2.D8(4); // Address size
+ rnglists2.D8(0); // Segment selector size
+ rnglists2.D32(2); // Offset entry count
+ const uint64_t ranges_base_2 = rnglists1.Size() + rnglists2.Size();
+
+ // Offset entries.
+ Label range2;
+ rnglists2.Append(kBigEndian, 4, range2);
+ Label range3;
+ rnglists2.Append(kBigEndian, 4, range3);
+
+ // Range 2 (will be read via DW_AT_ranges, DW_FORM_sec_offset).
+ range2 = rnglists2.Size() - header_size;
+ rnglists2.D8(DW_RLE_base_addressx).ULEB128(0); // base_addr = 1
+ rnglists2.D8(DW_RLE_startx_endx).ULEB128(1).ULEB128(2); // [2, 3)
+ rnglists2.D8(DW_RLE_startx_length).ULEB128(3).ULEB128(1); // [4, 5)
+ rnglists2.D8(DW_RLE_offset_pair).ULEB128(5).ULEB128(6); // [6, 7)
+ rnglists2.D8(DW_RLE_end_of_list);
+
+ // Range 3 (will be read via DW_AT_ranges, DW_FORM_rnglistx).
+ range3 = rnglists2.Size() - header_size;
+ rnglists2.D8(DW_RLE_base_address).D32(15); // base_addr = 15
+ rnglists2.D8(DW_RLE_offset_pair).ULEB128(1).ULEB128(2); // [16, 17)
+ rnglists2.D8(DW_RLE_start_end).D32(17).D32(18); // [17, 18)
+ rnglists2.D8(DW_RLE_start_length).D32(19).ULEB128(1); // [19, 20)
+ rnglists2.D8(DW_RLE_end_of_list);
+ // The size doesn't include the size of length field itself.
+ section_size2 = rnglists2.Size() - length_size;
+
+ rnglists1.Append(rnglists2);
+ string rnglists_contents;
+ assert(rnglists1.GetContents(&rnglists_contents));
+
+ RangeListReader::CURangesInfo cu_info;
+ cu_info.version_ = 5;
+ cu_info.base_address_ = 1;
+ cu_info.ranges_base_ = ranges_base_1;
+ cu_info.buffer_ =
+ reinterpret_cast<const uint8_t*>(rnglists_contents.data());
+ cu_info.size_ = rnglists_contents.size();
+ cu_info.addr_buffer_ =
+ reinterpret_cast<const uint8_t*>(addr_contents.data());
+ cu_info.addr_buffer_size_ = addr_contents.size();
+ cu_info.addr_base_ = 4;
+
+ ByteReader byte_reader(ENDIANNESS_BIG);
+ byte_reader.SetOffsetSize(4);
+ byte_reader.SetAddressSize(4);
+ MockRangeListHandler handler;
+ google_breakpad::RangeListReader range_list_reader1(&byte_reader, &cu_info,
+ &handler);
+ EXPECT_CALL(handler, AddRange(2, 3));
+ EXPECT_CALL(handler, AddRange(4, 5));
+ EXPECT_CALL(handler, AddRange(6, 7));
+ EXPECT_CALL(handler, AddRange(9, 10));
+ EXPECT_CALL(handler, AddRange(10, 11));
+ EXPECT_CALL(handler, AddRange(12, 13));
+ EXPECT_CALL(handler, Finish()).Times(2);
+ EXPECT_TRUE(range_list_reader1.ReadRanges(DW_FORM_rnglistx, 0));
+ EXPECT_TRUE(range_list_reader1.ReadRanges(DW_FORM_rnglistx, 1));
+ // Out of range index, should result in no calls.
+ EXPECT_FALSE(range_list_reader1.ReadRanges(DW_FORM_rnglistx, 2));
+
+ // Set to new ranges_base
+ cu_info.ranges_base_ = ranges_base_2;
+ google_breakpad::RangeListReader range_list_reader2(&byte_reader, &cu_info,
+ &handler);
+ EXPECT_CALL(handler, AddRange(2, 3));
+ EXPECT_CALL(handler, AddRange(4, 5));
+ EXPECT_CALL(handler, AddRange(6, 7));
+ EXPECT_CALL(handler, AddRange(16, 17));
+ EXPECT_CALL(handler, AddRange(17, 18));
+ EXPECT_CALL(handler, AddRange(19, 20));
+ EXPECT_CALL(handler, Finish()).Times(2);
+ EXPECT_TRUE(range_list_reader2.ReadRanges(DW_FORM_rnglistx, 0));
+ EXPECT_TRUE(range_list_reader2.ReadRanges(DW_FORM_rnglistx, 1));
+ // Out of range index, should result in no calls.
+ EXPECT_FALSE(range_list_reader2.ReadRanges(DW_FORM_rnglistx, 2));
+}
+
+TEST(RangeList, Dwarf5ReadRangeList_sec_offset) {
+ using google_breakpad::RangeListReader;
+ using google_breakpad::DW_RLE_base_addressx;
+ using google_breakpad::DW_RLE_startx_endx;
+ using google_breakpad::DW_RLE_startx_length;
+ using google_breakpad::DW_RLE_offset_pair;
+ using google_breakpad::DW_RLE_end_of_list;
+ using google_breakpad::DW_RLE_base_address;
+ using google_breakpad::DW_RLE_start_end;
+ using google_breakpad::DW_RLE_start_length;
+ using google_breakpad::DW_FORM_sec_offset;
+ using google_breakpad::DW_FORM_rnglistx;
+
+ // Size of length field in header
+ const uint64_t length_size = 4;
+
+ // .debug_addr for the indexed entries like startx.
+ Section addr;
+ addr.set_endianness(kBigEndian);
+ // Test addr_base handling with a padding address at 0.
+ addr.D32(0).D32(1).D32(2).D32(3).D32(4).D32(21).D32(22);
+ std::string addr_contents;
+ assert(addr.GetContents(&addr_contents));
+
+ // .debug_rnglists is the dwarf 5 section.
+ Section rnglists1(kBigEndian);
+ Section rnglists2(kBigEndian);
+
+ // First header and body.
+ Label section_size1;
+ rnglists1.Append(kBigEndian, length_size, section_size1);
+ rnglists1.D16(5); // Version
+ rnglists1.D8(4); // Address size
+ rnglists1.D8(0); // Segment selector size
+ rnglists1.D32(0); // Offset entry count
+
+ const uint64_t offset1 = rnglists1.Size();
+
+ rnglists1.D8(DW_RLE_base_addressx).ULEB128(0); // base_addr = 1
+ rnglists1.D8(DW_RLE_startx_endx).ULEB128(1).ULEB128(2); // [2, 3)
+ rnglists1.D8(DW_RLE_startx_length).ULEB128(3).ULEB128(1); // [4, 5)
+ rnglists1.D8(DW_RLE_offset_pair).ULEB128(5).ULEB128(6); // [6, 7)
+ rnglists1.D8(DW_RLE_base_address).D32(8); // base_addr = 8
+ rnglists1.D8(DW_RLE_offset_pair).ULEB128(1).ULEB128(2); // [9, 10)
+ rnglists1.D8(DW_RLE_start_end).D32(10).D32(11); // [10, 11)
+ rnglists1.D8(DW_RLE_start_length).D32(12).ULEB128(1); // [12, 13)
+ rnglists1.D8(DW_RLE_end_of_list);
+ // The size doesn't include the size of length field itself.
+ section_size1 = rnglists1.Size() - length_size;
+
+ // Second header and body.
+ Label section_size2;
+ rnglists2.Append(kBigEndian, length_size, section_size2);
+ rnglists2.D16(5); // Version
+ rnglists2.D8(4); // Address size
+ rnglists2.D8(0); // Segment selector size
+ rnglists2.D32(0); // Offset entry count
+
+ const uint64_t offset2 = rnglists1.Size() + rnglists2.Size();
+
+ rnglists2.D8(DW_RLE_base_addressx).ULEB128(0); // base_addr = 1
+ rnglists2.D8(DW_RLE_startx_endx).ULEB128(1).ULEB128(2); // [2, 3)
+ rnglists2.D8(DW_RLE_startx_length).ULEB128(3).ULEB128(1); // [4, 5)
+ rnglists2.D8(DW_RLE_offset_pair).ULEB128(5).ULEB128(6); // [6, 7)
+ rnglists2.D8(DW_RLE_base_address).D32(15); // base_addr = 15
+ rnglists2.D8(DW_RLE_offset_pair).ULEB128(1).ULEB128(2); // [16, 17)
+ rnglists2.D8(DW_RLE_start_end).D32(17).D32(18); // [17, 18)
+ rnglists2.D8(DW_RLE_start_length).D32(19).ULEB128(1); // [19, 20)
+ rnglists2.D8(DW_RLE_end_of_list);
+ // The size doesn't include the size of length field itself.
+ section_size2 = rnglists2.Size() - length_size;
+
+ rnglists1.Append(rnglists2);
+ string rnglists_contents;
+ assert(rnglists1.GetContents(&rnglists_contents));
+
+ RangeListReader::CURangesInfo cu_info;
+ cu_info.version_ = 5;
+ cu_info.base_address_ = 1;
+ cu_info.buffer_ =
+ reinterpret_cast<const uint8_t*>(rnglists_contents.data());
+ cu_info.size_ = rnglists_contents.size();
+ cu_info.addr_buffer_ =
+ reinterpret_cast<const uint8_t*>(addr_contents.data());
+ cu_info.addr_buffer_size_ = addr_contents.size();
+ cu_info.addr_base_ = 4;
+
+ ByteReader byte_reader(ENDIANNESS_BIG);
+ byte_reader.SetOffsetSize(4);
+ byte_reader.SetAddressSize(4);
+ MockRangeListHandler handler;
+ google_breakpad::RangeListReader range_list_reader(&byte_reader, &cu_info,
+ &handler);
+ EXPECT_CALL(handler, AddRange(2, 3));
+ EXPECT_CALL(handler, AddRange(4, 5));
+ EXPECT_CALL(handler, AddRange(6, 7));
+ EXPECT_CALL(handler, AddRange(9, 10));
+ EXPECT_CALL(handler, AddRange(10, 11));
+ EXPECT_CALL(handler, AddRange(12, 13));
+ EXPECT_CALL(handler, Finish()).Times(1);
+ EXPECT_TRUE(range_list_reader.ReadRanges(DW_FORM_sec_offset, offset1));
+ // Out of range index, should result in no calls.
+ EXPECT_FALSE(range_list_reader.ReadRanges(DW_FORM_sec_offset,
+ rnglists_contents.size()));
+
+ EXPECT_CALL(handler, AddRange(2, 3));
+ EXPECT_CALL(handler, AddRange(4, 5));
+ EXPECT_CALL(handler, AddRange(6, 7));
+ EXPECT_CALL(handler, AddRange(16, 17));
+ EXPECT_CALL(handler, AddRange(17, 18));
+ EXPECT_CALL(handler, AddRange(19, 20));
+ EXPECT_CALL(handler, Finish()).Times(1);
+ EXPECT_TRUE(range_list_reader.ReadRanges(DW_FORM_sec_offset, offset2));
+ // Out of range index, should result in no calls.
+ EXPECT_FALSE(range_list_reader.ReadRanges(DW_FORM_sec_offset,
+ rnglists_contents.size()));
+}
diff --git a/src/common/dwarf/dwarf2reader_lineinfo_unittest.cc b/src/common/dwarf/dwarf2reader_lineinfo_unittest.cc
new file mode 100644
index 00000000..033c6333
--- /dev/null
+++ b/src/common/dwarf/dwarf2reader_lineinfo_unittest.cc
@@ -0,0 +1,186 @@
+// Copyright 2020 Google LLC
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google LLC nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Original author: Sterling Augustine <saugustine@google.com>
+
+// dwarf2reader_lineinfo_unittest.cc: Unit tests for google_breakpad::LineInfo
+
+#include <stdint.h>
+#include <stdlib.h>
+
+#include <string>
+#include <vector>
+
+#include "breakpad_googletest_includes.h"
+#include "common/dwarf/bytereader.h"
+#include "common/dwarf/dwarf2reader.h"
+#include "google_breakpad/common/breakpad_types.h"
+
+using std::vector;
+using testing::InSequence;
+using testing::Return;
+using testing::Sequence;
+using testing::Test;
+using testing::_;
+
+using namespace google_breakpad;
+
+namespace {
+
+const uint8_t dwarf5_line_program[] = {
+ 0x40, 0x0, 0x0, 0x0, // unit_length (end - begin)
+ // begin
+ 0x05, 0x0, // version
+ 0x8, // address_size
+ 0x0, // segment_selector_size
+ 0x26, 0x0, 0x0, 0x0, // header_length (end_header_end - begin_header)
+ // begin_header:
+ 0x1, // minimum_instruction_length
+ 0x1, // maximum_operations_per_instruction
+ 0x1, // default_is_stmt
+ 0xfb, // line_base
+ 0xe, // line_range
+ 0xd, // opcode_base and lengths
+ 0x0, 0x1, 0x1, 0x1, 0x1, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x1,
+ 0x1, // directory entry format count
+ DW_LNCT_path, DW_FORM_strp,
+ 0x1, // directories count
+ 0x1, 0x0, 0x0, 0x0, // offset into .debug_line_str
+ 0x2, // file_name_entry_format_count
+ DW_LNCT_directory_index, DW_FORM_data1,
+ DW_LNCT_path, DW_FORM_line_strp,
+ 0x1, // filename count
+ 0x0, // directory index
+ 0x1, 0x0, 0x0, 0x0, // offset into .debug_str
+ // end_header
+ DW_LNS_set_file, 0x0,
+ // set address to 0x0
+ 0x0, 0x9, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ // Advance Address by 0 and line by 3
+ 0x15,
+ // Advance PC by 1
+ 0x2, 0x1,
+ 0x0,
+ DW_LNE_end_sequence,
+ DW_LNE_end_sequence,
+ // end
+};
+
+const uint8_t dwarf4_line_program[] = {
+ 0x37, 0x0, 0x0, 0x0, // unit_length (end - begin)
+ // begin
+ 0x04, 0x0, // version
+ 0x1d, 0x0, 0x0, 0x0, // header_length (end_header - begin_header)
+ // begin_header:
+ 0x1, // minimum_instruction_length
+ 0x1, // maximum_operations_per_instruction
+ 0x1, // default_is_stmt
+ 0xfb, // line_base
+ 0xe, // line_range
+ 0xd, // opcode_base and lengths
+ 0x0, 0x1, 0x1, 0x1, 0x1, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x1,
+ '/', 'a', '\0', // directory entry 1 (zeroth entry implied)
+ '\0', // end of directory table
+ 'b', '/', 'c', '\0', // file entry 1 (zeroth entry implied)
+ 0, // file 1 directory
+ 0, // file 1 modification time
+ 0, // file 1 length
+ '\0', // end of file table
+ // end_header
+ DW_LNS_set_file, 0x0,
+ // set address to 0x0
+ 0x0, 0x9, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ // Advance Address by 0 and line by 3
+ 0x15,
+ // Advance PC by 1
+ 0x2, 0x1,
+ 0x0,
+ DW_LNE_end_sequence,
+ DW_LNE_end_sequence,
+ // end
+};
+
+class MockLineInfoHandler: public LineInfoHandler {
+ public:
+ MOCK_METHOD(void, DefineDir, (const string&, uint32_t dir_num), (override));
+ MOCK_METHOD(void, DefineFile, (const string& name, int32_t file_num,
+ uint32_t dir_num, uint64_t mod_time,
+ uint64_t length), (override));
+ MOCK_METHOD(void, AddLine, (uint64_t address, uint64_t length,
+ uint32_t file_num, uint32_t line_num,
+ uint32_t column_num), (override));
+};
+
+const uint8_t string_section[] = {'x', '/', 'a', '\0'};
+const uint8_t line_string_section[] = {'x', 'b', '/', 'c', '\0' };
+
+struct LineProgram: public Test {
+ MockLineInfoHandler handler_;
+};
+
+TEST_F(LineProgram, ReadLinesDwarf5) {
+ ByteReader byte_reader(ENDIANNESS_LITTLE);
+ // LineTables don't specify the offset size like Compilation Units do.
+ byte_reader.SetOffsetSize(4);
+ LineInfo line_reader(dwarf5_line_program,
+ sizeof(dwarf5_line_program),
+ &byte_reader,
+ string_section,
+ sizeof(string_section),
+ line_string_section,
+ sizeof(line_string_section),
+ &handler_);
+ EXPECT_CALL(handler_, DefineDir("/a", 0)).Times(1);
+ EXPECT_CALL(handler_, DefineFile("b/c", 0, 0, 0, 0)).Times(1);
+ EXPECT_CALL(handler_, AddLine(0, 1, 0, 4, 0)).Times(1);
+ EXPECT_EQ(line_reader.Start(), sizeof(dwarf5_line_program));
+}
+
+TEST_F(LineProgram, ReadLinesDwarf4) {
+ ByteReader byte_reader(ENDIANNESS_LITTLE);
+ // LineTables don't specify the offset size like Compilation Units do.
+ byte_reader.SetOffsetSize(4);
+ // dwarf4 line info headers don't encode the address size.
+ byte_reader.SetAddressSize(8);
+ LineInfo line_reader(dwarf4_line_program,
+ sizeof(dwarf4_line_program),
+ &byte_reader,
+ // dwarf4 line tables can't access the string sections
+ // so pass values likely to make assertions fail if
+ // the code uses them improperly.
+ nullptr, 0, nullptr, 0,
+ &handler_);
+ EXPECT_CALL(handler_, DefineDir("", 0)).Times(1);
+ EXPECT_CALL(handler_, DefineDir("/a", 1)).Times(1);
+ EXPECT_CALL(handler_, DefineFile("", 0, 0, 0, 0)).Times(1);
+ EXPECT_CALL(handler_, DefineFile("b/c", 1, 0, 0, 0)).Times(1);
+ EXPECT_CALL(handler_, AddLine(0, 1, 0, 4, 0)).Times(1);
+ EXPECT_EQ(line_reader.Start(), sizeof(dwarf4_line_program));
+}
+
+} // anonymous namespace
diff --git a/src/common/dwarf/dwarf2reader_splitfunctions_unittest.cc b/src/common/dwarf/dwarf2reader_splitfunctions_unittest.cc
new file mode 100644
index 00000000..9ceea109
--- /dev/null
+++ b/src/common/dwarf/dwarf2reader_splitfunctions_unittest.cc
@@ -0,0 +1,125 @@
+// Copyright 2020 Google LLC
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google LLC nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Original author: Snehasish Kumar <snehasishk@google.com>
+
+// dwarf2reader_splitfunctions_unittest.cc: Unit tests for with a focus on debug
+// information generated when with splitting optimizations such as
+// -fsplit-machine-functions (clang) -freorder-blocks-and-partition (gcc).
+
+#include <stdint.h>
+#include <stdlib.h>
+
+#include <string>
+
+#include "breakpad_googletest_includes.h"
+#include "common/dwarf/bytereader.h"
+#include "common/dwarf/dwarf2reader.h"
+#include "google_breakpad/common/breakpad_types.h"
+
+using testing::_;
+using namespace google_breakpad;
+
+namespace {
+
+class MockLineInfoHandler: public LineInfoHandler {
+ public:
+ MOCK_METHOD(void, DefineFile, (const string& name, int32_t file_num,
+ uint32_t dir_num, uint64_t mod_time,
+ uint64_t length), (override));
+ MOCK_METHOD(void, AddLine, (uint64_t address, uint64_t length,
+ uint32_t file_num, uint32_t line_num,
+ uint32_t column_num), (override));
+};
+
+struct LineProgram: public testing::Test {
+ MockLineInfoHandler handler_;
+};
+
+// The debug information is generated from the following program --
+// $ cat -n split_functions.c
+// 1 #include <stdio.h>
+// 2
+// 3 __attribute__((noinline)) int foo(int i) {
+// 4 if (i % 100) {
+// 5 return i + 1;
+// 6 } else {
+// 7 return i * 10 % 3;
+// 8 }
+// 9 }
+// 10
+// 11
+// 12 int main(int argc, char *argv[]) {
+// 13 int total = 0;
+// 14 for (int i = 0; i < 1000; ++i) {
+// 15 total += foo(i);
+// 16 }
+// 17 printf("%d\n", total);
+// 18 }
+//
+// $ bin/clang -fprofile-generate -O2 split_functions.c
+// $ ./a.out > /dev/null
+// $ bin/llvm-profdata merge -o default.profdata default_*.profraw
+// $ bin/clang -fprofile-use -O2 -gmlt -gdwarf-5 -fsplit-machine-functions \
+// split_functions.c -o split.out
+//
+// For the test we pick the first instruction in foo.cold which should be the
+// else part of the function foo above.
+
+const uint8_t debug_line[] = {
+ 0xb0,0x0,0x0,0x0,0x5,0x0,0x8,0x0,0x37,0x0,0x0,0x0,0x1,0x1,0x1,0xfb,0xe,0xd,0x0,0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x1,0x1,0x1f,0x1,0x0,0x0,0x0,0x0,0x3,0x1,0x1f,0x2,0xf,0x5,0x1e,0x1,0x3d,0x0,0x0,0x0,0x0,0x24,0xb2,0xb6,0xb5,0xbb,0xf,0xf7,0x6d,0x27,0x92,0xab,0x55,0x3a,0x29,0x48,0x81,0x4,0x0,0x0,0x9,0x2,0x40,0x10,0x40,0x0,0x0,0x0,0x0,0x0,0x14,0x5,0x9,0xa,0x2f,0x5,0x7,0x6,0x8,0x4a,0x5,0xe,0x6,0x67,0x5,0x1,0x40,0x5,0x0,0xf5,0x5,0xe,0xa,0xf5,0x5,0xb,0x6,0x74,0x5,0x1d,0x6,0x2d,0x5,0x15,0x6,0x3c,0x5,0x3,0x66,0x2,0x7,0x0,0x1,0x1,0x4,0x0,0x5,0xe,0x0,0x9,0x2,0x84,0x11,0x40,0x0,0x0,0x0,0x0,0x0,0x18,0x5,0x13,0x6,0x58,0x5,0x1,0x6,0x8,0xa0,0x2,0x1,0x0,0x1,0x1,0x4,0x0,0x5,0x3,0x0,0x9,0x2,0xa5,0x11,0x40,0x0,0x0,0x0,0x0,0x0,0x3,0x10,0x1,0x5,0x1,0xd7,0x2,0x9,0x0,0x1,0x1
+};
+
+const uint8_t debug_str[] = {
+ 0x63,0x6c,0x61,0x6e,0x67,0x20,0x76,0x65,0x72,0x73,0x69,0x6f,0x6e,0x20,0x31,0x32,0x2e,0x30,0x2e,0x30,0x20,0x28,0x67,0x69,0x74,0x40,0x67,0x69,0x74,0x68,0x75,0x62,0x2e,0x63,0x6f,0x6d,0x3a,0x6c,0x6c,0x76,0x6d,0x2f,0x6c,0x6c,0x76,0x6d,0x2d,0x70,0x72,0x6f,0x6a,0x65,0x63,0x74,0x2e,0x67,0x69,0x74,0x20,0x63,0x37,0x35,0x61,0x30,0x61,0x31,0x65,0x39,0x64,0x63,0x32,0x39,0x62,0x65,0x34,0x65,0x30,0x30,0x64,0x33,0x37,0x64,0x30,0x64,0x30,0x30,0x32,0x38,0x38,0x61,0x66,0x63,0x31,0x61,0x36,0x31,0x35,0x33,0x66,0x29,0x0,0x73,0x70,0x6c,0x69,0x74,0x5f,0x66,0x75,0x6e,0x63,0x74,0x69,0x6f,0x6e,0x73,0x2e,0x63,0x0,0x2f,0x75,0x73,0x72,0x2f,0x6c,0x6f,0x63,0x61,0x6c,0x2f,0x67,0x6f,0x6f,0x67,0x6c,0x65,0x2f,0x68,0x6f,0x6d,0x65,0x2f,0x73,0x6e,0x65,0x68,0x61,0x73,0x69,0x73,0x68,0x6b,0x2f,0x77,0x6f,0x72,0x6b,0x69,0x6e,0x67,0x2f,0x6c,0x6c,0x76,0x6d,0x2d,0x70,0x72,0x6f,0x6a,0x65,0x63,0x74,0x2f,0x62,0x75,0x69,0x6c,0x64,0x0,0x66,0x6f,0x6f,0x0,0x69,0x6e,0x74,0x0,0x6d,0x61,0x69,0x6e,0x0,0x69,0x0,0x61,0x72,0x67,0x63,0x0,0x61,0x72,0x67,0x76,0x0,0x63,0x68,0x61,0x72,0x0,0x74,0x6f,0x74,0x61,0x6c,0x0
+};
+
+const uint8_t debug_line_str[] = {
+ 0x2f,0x75,0x73,0x72,0x2f,0x6c,0x6f,0x63,0x61,0x6c,0x2f,0x67,0x6f,0x6f,0x67,0x6c,0x65,0x2f,0x68,0x6f,0x6d,0x65,0x2f,0x73,0x6e,0x65,0x68,0x61,0x73,0x69,0x73,0x68,0x6b,0x2f,0x77,0x6f,0x72,0x6b,0x69,0x6e,0x67,0x2f,0x6c,0x6c,0x76,0x6d,0x2d,0x70,0x72,0x6f,0x6a,0x65,0x63,0x74,0x2f,0x62,0x75,0x69,0x6c,0x64,0x0,0x73,0x70,0x6c,0x69,0x74,0x5f,0x66,0x75,0x6e,0x63,0x74,0x69,0x6f,0x6e,0x73,0x2e,0x63,0x0
+};
+
+TEST_F(LineProgram, ReadLinesSplitFunctions) {
+ ByteReader byte_reader(ENDIANNESS_LITTLE);
+ // LineTables don't specify the offset size like Compilation Units do.
+ byte_reader.SetOffsetSize(4);
+ LineInfo line_reader(debug_line,
+ sizeof(debug_line),
+ &byte_reader,
+ debug_str,
+ sizeof(debug_str),
+ debug_line_str,
+ sizeof(debug_line_str),
+ &handler_);
+ EXPECT_CALL(handler_, DefineFile("split_functions.c", 0, 0, 0, 0)).Times(1);
+ EXPECT_CALL(handler_, AddLine(_, _, _, _, _)).Times(testing::AtLeast(1));
+ // Pick the first address from the foo.cold symbol and check the line number.
+ EXPECT_CALL(handler_, AddLine(testing::Eq(0x401184lu), _, _, /*line_num*/ 7, _)).Times(1);
+ EXPECT_EQ(line_reader.Start(), sizeof(debug_line));
+}
+
+} // anonymous namespace
diff --git a/src/common/dwarf/dwarf2reader_test_common.h b/src/common/dwarf/dwarf2reader_test_common.h
index e91de906..1c45d527 100644
--- a/src/common/dwarf/dwarf2reader_test_common.h
+++ b/src/common/dwarf/dwarf2reader_test_common.h
@@ -1,7 +1,6 @@
// -*- mode: c++ -*-
-// Copyright (c) 2012, Google Inc.
-// All rights reserved.
+// Copyright 2012 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -13,7 +12,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -45,9 +44,9 @@
// DWARF compilation units.
class TestCompilationUnit: public google_breakpad::test_assembler::Section {
public:
- typedef dwarf2reader::DwarfTag DwarfTag;
- typedef dwarf2reader::DwarfAttribute DwarfAttribute;
- typedef dwarf2reader::DwarfForm DwarfForm;
+ typedef google_breakpad::DwarfTag DwarfTag;
+ typedef google_breakpad::DwarfAttribute DwarfAttribute;
+ typedef google_breakpad::DwarfForm DwarfForm;
typedef google_breakpad::test_assembler::Label Label;
// Set the section's DWARF format size (the 32-bit DWARF format or the
@@ -57,7 +56,7 @@ class TestCompilationUnit: public google_breakpad::test_assembler::Section {
assert(format_size == 4 || format_size == 8);
format_size_ = format_size;
}
-
+
// Append a DWARF section offset value, of the appropriate size for this
// compilation unit.
template<typename T>
@@ -70,8 +69,8 @@ class TestCompilationUnit: public google_breakpad::test_assembler::Section {
// Append a DWARF compilation unit header to the section, with the given
// DWARF version, abbrev table offset, and address size.
- TestCompilationUnit &Header(int version, const Label &abbrev_offset,
- size_t address_size) {
+ TestCompilationUnit& Header(int version, const Label& abbrev_offset,
+ size_t address_size, int header_type) {
if (format_size_ == 4) {
D32(length_);
} else {
@@ -80,13 +79,28 @@ class TestCompilationUnit: public google_breakpad::test_assembler::Section {
}
post_length_offset_ = Size();
D16(version);
- SectionOffset(abbrev_offset);
- D8(address_size);
+ if (version <= 4) {
+ SectionOffset(abbrev_offset);
+ D8(address_size);
+ } else {
+ D8(header_type); // DW_UT_compile, DW_UT_type, etc.
+ D8(address_size);
+ SectionOffset(abbrev_offset);
+ if (header_type == google_breakpad::DW_UT_type) {
+ uint64_t dummy_type_signature = 0xdeadbeef;
+ uint64_t dummy_type_offset = 0x2b;
+ D64(dummy_type_signature);
+ if (format_size_ == 4)
+ D32(dummy_type_offset);
+ else
+ D64(dummy_type_offset);
+ }
+ }
return *this;
}
// Mark the end of this header's DIEs.
- TestCompilationUnit &Finish() {
+ TestCompilationUnit& Finish() {
length_ = Size() - post_length_offset_;
return *this;
}
@@ -107,16 +121,16 @@ class TestCompilationUnit: public google_breakpad::test_assembler::Section {
// abbreviation tables.
class TestAbbrevTable: public google_breakpad::test_assembler::Section {
public:
- typedef dwarf2reader::DwarfTag DwarfTag;
- typedef dwarf2reader::DwarfAttribute DwarfAttribute;
- typedef dwarf2reader::DwarfForm DwarfForm;
- typedef dwarf2reader::DwarfHasChild DwarfHasChild;
+ typedef google_breakpad::DwarfTag DwarfTag;
+ typedef google_breakpad::DwarfAttribute DwarfAttribute;
+ typedef google_breakpad::DwarfForm DwarfForm;
+ typedef google_breakpad::DwarfHasChild DwarfHasChild;
typedef google_breakpad::test_assembler::Label Label;
// Start a new abbreviation table entry for abbreviation code |code|,
// encoding a DIE whose tag is |tag|, and which has children if and only
// if |has_children| is true.
- TestAbbrevTable &Abbrev(int code, DwarfTag tag, DwarfHasChild has_children) {
+ TestAbbrevTable& Abbrev(int code, DwarfTag tag, DwarfHasChild has_children) {
assert(code != 0);
ULEB128(code);
ULEB128(static_cast<unsigned>(tag));
@@ -126,21 +140,21 @@ class TestAbbrevTable: public google_breakpad::test_assembler::Section {
// Add an attribute to the current abbreviation code whose name is |name|
// and whose form is |form|.
- TestAbbrevTable &Attribute(DwarfAttribute name, DwarfForm form) {
+ TestAbbrevTable& Attribute(DwarfAttribute name, DwarfForm form) {
ULEB128(static_cast<unsigned>(name));
ULEB128(static_cast<unsigned>(form));
return *this;
}
// Finish the current abbreviation code.
- TestAbbrevTable &EndAbbrev() {
+ TestAbbrevTable& EndAbbrev() {
ULEB128(0);
ULEB128(0);
return *this;
}
// Finish the current abbreviation table.
- TestAbbrevTable &EndTable() {
+ TestAbbrevTable& EndTable() {
ULEB128(0);
return *this;
}
diff --git a/src/common/dwarf/elf_reader.cc b/src/common/dwarf/elf_reader.cc
index 1b665213..7664377c 100644
--- a/src/common/dwarf/elf_reader.cc
+++ b/src/common/dwarf/elf_reader.cc
@@ -1,4 +1,4 @@
-// Copyright 2005 Google Inc. All Rights Reserved.
+// Copyright 2005 Google LLC
// Author: chatham@google.com (Andrew Chatham)
// Author: satorux@google.com (Satoru Takabayashi)
//
@@ -41,6 +41,7 @@
#include <algorithm>
#include <map>
#include <string>
+#include <string_view>
#include <vector>
// TODO(saugustine): Add support for compressed debug.
// Also need to add configure tests for zlib.
@@ -106,9 +107,15 @@ const int kAARCH64PLT0Size = 0x20;
// Suffix for PLT functions when it needs to be explicitly identified as such.
const char kPLTFunctionSuffix[] = "@plt";
+// Replace callsites of this function to std::string_view::starts_with after
+// adopting C++20.
+bool StringViewStartsWith(std::string_view sv, std::string_view prefix) {
+ return sv.compare(0, prefix.size(), prefix) == 0;
+}
+
} // namespace
-namespace dwarf2reader {
+namespace google_breakpad {
template <class ElfArch> class ElfReaderImpl;
@@ -130,11 +137,11 @@ class Elf32 {
static const int kElfClass = ELFCLASS32;
// Given a symbol pointer, return the binding type (eg STB_WEAK).
- static char Bind(const Elf32_Sym *sym) {
+ static char Bind(const Elf32_Sym* sym) {
return ELF32_ST_BIND(sym->st_info);
}
// Given a symbol pointer, return the symbol type (eg STT_FUNC).
- static char Type(const Elf32_Sym *sym) {
+ static char Type(const Elf32_Sym* sym) {
return ELF32_ST_TYPE(sym->st_info);
}
@@ -158,10 +165,10 @@ class Elf64 {
// What should be in the EI_CLASS header.
static const int kElfClass = ELFCLASS64;
- static char Bind(const Elf64_Sym *sym) {
+ static char Bind(const Elf64_Sym* sym) {
return ELF64_ST_BIND(sym->st_info);
}
- static char Type(const Elf64_Sym *sym) {
+ static char Type(const Elf64_Sym* sym) {
return ELF64_ST_TYPE(sym->st_info);
}
static int r_sym(const Elf64_Xword r_info) {
@@ -182,8 +189,8 @@ class Elf64 {
template<class ElfArch>
class ElfSectionReader {
public:
- ElfSectionReader(const char *name, const string &path, int fd,
- const typename ElfArch::Shdr &section_header)
+ ElfSectionReader(const char* cname, const string& path, int fd,
+ const typename ElfArch::Shdr& section_header)
: contents_aligned_(NULL),
contents_(NULL),
header_(section_header) {
@@ -196,14 +203,25 @@ class ElfSectionReader {
// to process its contents.
if (header_.sh_type == SHT_NOBITS || header_.sh_size == 0)
return;
+ // extra sh_type check for string table.
+ std::string_view name{cname};
+ if ((name == ".strtab" || name == ".shstrtab") &&
+ header_.sh_type != SHT_STRTAB) {
+ fprintf(stderr,
+ "Invalid sh_type for string table section: expected "
+ "SHT_STRTAB or SHT_DYNSYM, but got %d\n",
+ header_.sh_type);
+ return;
+ }
+
contents_aligned_ = mmap(NULL, size_aligned_, PROT_READ, MAP_SHARED,
fd, offset_aligned);
// Set where the offset really should begin.
- contents_ = reinterpret_cast<char *>(contents_aligned_) +
+ contents_ = reinterpret_cast<char*>(contents_aligned_) +
(header_.sh_offset - offset_aligned);
// Check for and handle any compressed contents.
- //if (strncmp(name, ".zdebug_", strlen(".zdebug_")) == 0)
+ //if (StringViewStartsWith(name, ".zdebug_"))
// DecompressZlibContents();
// TODO(saugustine): Add support for proposed elf-section flag
// "SHF_COMPRESS".
@@ -217,24 +235,24 @@ class ElfSectionReader {
}
// Return the section header for this section.
- typename ElfArch::Shdr const &header() const { return header_; }
+ typename ElfArch::Shdr const& header() const { return header_; }
// Return memory at the given offset within this section.
- const char *GetOffset(typename ElfArch::Word bytes) const {
+ const char* GetOffset(typename ElfArch::Word bytes) const {
return contents_ + bytes;
}
- const char *contents() const { return contents_; }
+ const char* contents() const { return contents_; }
size_t section_size() const { return section_size_; }
private:
// page-aligned file contents
- void *contents_aligned_;
+ void* contents_aligned_;
// contents as usable by the client. For non-compressed sections,
// pointer within contents_aligned_ to where the section data
// begins; for compressed sections, pointer to the decompressed
// data.
- char *contents_;
+ char* contents_;
// size of contents_aligned_
size_t size_aligned_;
// size of contents.
@@ -249,7 +267,7 @@ class ElfSectionReader {
template<class ElfArch>
class SymbolIterator {
public:
- SymbolIterator(ElfReaderImpl<ElfArch> *reader,
+ SymbolIterator(ElfReaderImpl<ElfArch>* reader,
typename ElfArch::Word section_type)
: symbol_section_(reader->GetSectionByType(section_type)),
string_section_(NULL),
@@ -280,7 +298,7 @@ class SymbolIterator {
// Return a pointer to the current symbol.
// REQUIRES: !done()
- const typename ElfArch::Sym *GetSymbol() const {
+ const typename ElfArch::Sym* GetSymbol() const {
return reinterpret_cast<const typename ElfArch::Sym*>(
symbol_section_->GetOffset(symbol_within_section_ *
symbol_section_->header().sh_entsize));
@@ -288,7 +306,7 @@ class SymbolIterator {
// Return the name of the current symbol, NULL if it has none.
// REQUIRES: !done()
- const char *GetSymbolName() const {
+ const char* GetSymbolName() const {
int name_offset = GetSymbol()->st_name;
if (name_offset == 0)
return NULL;
@@ -300,8 +318,8 @@ class SymbolIterator {
}
private:
- const ElfSectionReader<ElfArch> *const symbol_section_;
- const ElfSectionReader<ElfArch> *string_section_;
+ const ElfSectionReader<ElfArch>* const symbol_section_;
+ const ElfSectionReader<ElfArch>* string_section_;
int num_symbols_in_section_;
int symbol_within_section_;
};
@@ -326,7 +344,7 @@ static inline bool MyHasSuffixString(const string& str, const string& suffix) {
template<class ElfArch>
class ElfReaderImpl {
public:
- explicit ElfReaderImpl(const string &path, int fd)
+ explicit ElfReaderImpl(const string& path, int fd)
: path_(path),
fd_(fd),
section_headers_(NULL),
@@ -347,8 +365,8 @@ class ElfReaderImpl {
// "opd_section_" must always be checked for NULL before use.
opd_section_ = GetSectionInfoByName(".opd", &opd_info_);
for (unsigned int k = 0u; k < GetNumSections(); ++k) {
- const char *name = GetSectionName(section_headers_[k].sh_name);
- if (strncmp(name, ".text", strlen(".text")) == 0) {
+ std::string_view name{GetSectionName(section_headers_[k].sh_name)};
+ if (StringViewStartsWith(name, ".text")) {
base_for_text_ =
section_headers_[k].sh_addr - section_headers_[k].sh_offset;
break;
@@ -384,7 +402,7 @@ class ElfReaderImpl {
// to see if the ELF file appears to match the current
// architecture. If error is non-NULL, it will be set with a reason
// in case of failure.
- static bool IsArchElfFile(int fd, string *error) {
+ static bool IsArchElfFile(int fd, string* error) {
unsigned char header[EI_NIDENT];
if (pread(fd, header, sizeof(header), 0) != sizeof(header)) {
if (error != NULL) *error = "Could not read header";
@@ -415,7 +433,7 @@ class ElfReaderImpl {
}
// Return true if we can use this symbol in Address-to-Symbol map.
- bool CanUseSymbol(const char *name, const typename ElfArch::Sym *sym) {
+ bool CanUseSymbol(const char* name, const typename ElfArch::Sym* sym) {
// For now we only save FUNC and NOTYPE symbols. For now we just
// care about functions, but some functions written in assembler
// don't have a proper ELF type attached to them, so we store
@@ -444,7 +462,7 @@ class ElfReaderImpl {
// Iterate over the symbols in a section, either SHT_DYNSYM or
// SHT_SYMTAB. Add all symbols to the given SymbolMap.
/*
- void GetSymbolPositions(SymbolMap *symbols,
+ void GetSymbolPositions(SymbolMap* symbols,
typename ElfArch::Word section_type,
uint64_t mem_offset,
uint64_t file_offset) {
@@ -453,10 +471,10 @@ class ElfReaderImpl {
AddrToSymMap addr_to_sym_map;
for (SymbolIterator<ElfArch> it(this, section_type);
!it.done(); it.Next()) {
- const char *name = it.GetSymbolName();
+ const char* name = it.GetSymbolName();
if (name == NULL)
continue;
- const typename ElfArch::Sym *sym = it.GetSymbol();
+ const typename ElfArch::Sym* sym = it.GetSymbol();
if (CanUseSymbol(name, sym)) {
const int sec = sym->st_shndx;
@@ -519,9 +537,9 @@ class ElfReaderImpl {
if (addr_to_sym_map.empty()) {
return;
}
- const ElfSectionReader<ElfArch> *const symbol_section =
+ const ElfSectionReader<ElfArch>* const symbol_section =
this->GetSectionByType(section_type);
- const ElfSectionReader<ElfArch> *const string_section =
+ const ElfSectionReader<ElfArch>* const string_section =
this->GetSection(symbol_section->header().sh_link);
typename AddrToSymMap::iterator curr = addr_to_sym_map.begin();
@@ -532,8 +550,8 @@ class ElfReaderImpl {
for (; curr != addr_to_sym_map.end(); ++curr) {
const uint64_t prev_addr = prev->first;
const uint64_t curr_addr = curr->first;
- const typename ElfArch::Sym *const prev_sym = prev->second;
- const typename ElfArch::Sym *const curr_sym = curr->second;
+ const typename ElfArch::Sym* const prev_sym = prev->second;
+ const typename ElfArch::Sym* const curr_sym = curr->second;
if (prev_addr + prev_sym->st_size <= curr_addr ||
// The next condition is true if two symbols overlap like this:
//
@@ -552,7 +570,7 @@ class ElfReaderImpl {
// (e.g. 0619e071) will produce the current symbol,
// which is the desired outcome.
prev_addr + prev_sym->st_size < curr_addr + curr_sym->st_size) {
- const char *name = string_section->GetOffset(curr_sym->st_name);
+ const char* name = string_section->GetOffset(curr_sym->st_name);
symbols->AddSymbol(name, curr_addr, curr_sym->st_size);
prev = curr;
} else {
@@ -572,20 +590,20 @@ class ElfReaderImpl {
*/
void VisitSymbols(typename ElfArch::Word section_type,
- ElfReader::SymbolSink *sink) {
+ ElfReader::SymbolSink* sink) {
VisitSymbols(section_type, sink, -1, -1, false);
}
void VisitSymbols(typename ElfArch::Word section_type,
- ElfReader::SymbolSink *sink,
+ ElfReader::SymbolSink* sink,
int symbol_binding,
int symbol_type,
bool get_raw_symbol_values) {
for (SymbolIterator<ElfArch> it(this, section_type);
!it.done(); it.Next()) {
- const char *name = it.GetSymbolName();
+ const char* name = it.GetSymbolName();
if (!name) continue;
- const typename ElfArch::Sym *sym = it.GetSymbol();
+ const typename ElfArch::Sym* sym = it.GetSymbol();
if ((symbol_binding < 0 || ElfArch::Bind(sym) == symbol_binding) &&
(symbol_type < 0 || ElfArch::Type(sym) == symbol_type)) {
typename ElfArch::Sym symbol = *sym;
@@ -691,7 +709,7 @@ class ElfReaderImpl {
// Return an ElfSectionReader for the first section of the given
// type by iterating through all section headers. Returns NULL if
// the section type is not found.
- const ElfSectionReader<ElfArch> *GetSectionByType(
+ const ElfSectionReader<ElfArch>* GetSectionByType(
typename ElfArch::Word section_type) {
for (unsigned int k = 0u; k < GetNumSections(); ++k) {
if (section_headers_[k].sh_type == section_type) {
@@ -703,14 +721,14 @@ class ElfReaderImpl {
// Return the name of section "shndx". Returns NULL if the section
// is not found.
- const char *GetSectionNameByIndex(int shndx) {
+ const char* GetSectionNameByIndex(int shndx) {
return GetSectionName(section_headers_[shndx].sh_name);
}
// Return a pointer to section "shndx", and store the size in
// "size". Returns NULL if the section is not found.
- const char *GetSectionContentsByIndex(int shndx, size_t *size) {
- const ElfSectionReader<ElfArch> *section = GetSection(shndx);
+ const char* GetSectionContentsByIndex(int shndx, size_t* size) {
+ const ElfSectionReader<ElfArch>* section = GetSection(shndx);
if (section != NULL) {
*size = section->section_size();
return section->contents();
@@ -721,16 +739,16 @@ class ElfReaderImpl {
// Return a pointer to the first section of the given name by
// iterating through all section headers, and store the size in
// "size". Returns NULL if the section name is not found.
- const char *GetSectionContentsByName(const string &section_name,
- size_t *size) {
+ const char* GetSectionContentsByName(const string& section_name,
+ size_t* size) {
for (unsigned int k = 0u; k < GetNumSections(); ++k) {
// When searching for sections in a .dwp file, the sections
// we're looking for will always be at the end of the section
// table, so reverse the direction of iteration.
int shndx = is_dwp_ ? GetNumSections() - k - 1 : k;
- const char *name = GetSectionName(section_headers_[shndx].sh_name);
+ const char* name = GetSectionName(section_headers_[shndx].sh_name);
if (name != NULL && ElfReader::SectionNamesMatch(section_name, name)) {
- const ElfSectionReader<ElfArch> *section = GetSection(shndx);
+ const ElfSectionReader<ElfArch>* section = GetSection(shndx);
if (section == NULL) {
return NULL;
} else {
@@ -744,16 +762,16 @@ class ElfReaderImpl {
// This is like GetSectionContentsByName() but it returns a lot of extra
// information about the section.
- const char *GetSectionInfoByName(const string &section_name,
- ElfReader::SectionInfo *info) {
+ const char* GetSectionInfoByName(const string& section_name,
+ ElfReader::SectionInfo* info) {
for (unsigned int k = 0u; k < GetNumSections(); ++k) {
// When searching for sections in a .dwp file, the sections
// we're looking for will always be at the end of the section
// table, so reverse the direction of iteration.
int shndx = is_dwp_ ? GetNumSections() - k - 1 : k;
- const char *name = GetSectionName(section_headers_[shndx].sh_name);
+ const char* name = GetSectionName(section_headers_[shndx].sh_name);
if (name != NULL && ElfReader::SectionNamesMatch(section_name, name)) {
- const ElfSectionReader<ElfArch> *section = GetSection(shndx);
+ const ElfSectionReader<ElfArch>* section = GetSection(shndx);
if (section == NULL) {
return NULL;
} else {
@@ -797,9 +815,11 @@ class ElfReaderImpl {
// Debug sections are likely to be near the end, so reverse the
// direction of iteration.
for (int k = GetNumSections() - 1; k >= 0; --k) {
- const char *name = GetSectionName(section_headers_[k].sh_name);
- if (strncmp(name, ".debug", strlen(".debug")) == 0) return true;
- if (strncmp(name, ".zdebug", strlen(".zdebug")) == 0) return true;
+ std::string_view name{GetSectionName(section_headers_[k].sh_name)};
+ if (StringViewStartsWith(name, ".debug") ||
+ StringViewStartsWith(name, ".zdebug")) {
+ return true;
+ }
}
return false;
}
@@ -816,7 +836,7 @@ class ElfReaderImpl {
}
private:
- typedef vector<pair<uint64_t, const typename ElfArch::Sym *> > AddrToSymMap;
+ typedef vector<pair<uint64_t, const typename ElfArch::Sym*> > AddrToSymMap;
static bool AddrToSymSorter(const typename AddrToSymMap::value_type& lhs,
const typename AddrToSymMap::value_type& rhs) {
@@ -854,8 +874,8 @@ class ElfReaderImpl {
// Given an offset into the section header string table, return the
// section name.
- const char *GetSectionName(typename ElfArch::Word sh_name) {
- const ElfSectionReader<ElfArch> *shstrtab =
+ const char* GetSectionName(typename ElfArch::Word sh_name) {
+ const ElfSectionReader<ElfArch>* shstrtab =
GetSection(GetStringTableIndex());
if (shstrtab != NULL) {
return shstrtab->GetOffset(sh_name);
@@ -865,25 +885,25 @@ class ElfReaderImpl {
// Return an ElfSectionReader for the given section. The reader will
// be freed when this object is destroyed.
- const ElfSectionReader<ElfArch> *GetSection(int num) {
- const char *name;
+ const ElfSectionReader<ElfArch>* GetSection(int num) {
+ const char* name;
// Hard-coding the name for the section-name string table prevents
// infinite recursion.
if (num == GetStringTableIndex())
name = ".shstrtab";
else
name = GetSectionNameByIndex(num);
- ElfSectionReader<ElfArch> *& reader = sections_[num];
+ ElfSectionReader<ElfArch>*& reader = sections_[num];
if (reader == NULL)
reader = new ElfSectionReader<ElfArch>(name, path_, fd_,
section_headers_[num]);
- return reader;
+ return reader->contents() ? reader : nullptr;
}
// Parse out the overall header information from the file and assert
// that it looks sane. This contains information like the magic
// number and target architecture.
- bool ParseHeaders(int fd, const string &path) {
+ bool ParseHeaders(int fd, const string& path) {
// Read in the global ELF header.
if (pread(fd, &header_, sizeof(header_), 0) != sizeof(header_)) {
return false;
@@ -985,11 +1005,11 @@ class ElfReaderImpl {
// Array of GetNumSections() section headers, allocated when we read
// in the global header.
- typename ElfArch::Shdr *section_headers_;
+ typename ElfArch::Shdr* section_headers_;
// Array of GetNumProgramHeaders() program headers, allocated when we read
// in the global header.
- typename ElfArch::Phdr *program_headers_;
+ typename ElfArch::Phdr* program_headers_;
// An array of pointers to ElfSectionReaders. Sections are
// mmaped as they're needed and not released until this object is
@@ -1000,7 +1020,7 @@ class ElfReaderImpl {
// values for funtion symbols values. Function descriptors are kept in the
// .opd section and are dereferenced to find the function address.
ElfReader::SectionInfo opd_info_;
- const char *opd_section_; // Must be checked for NULL before use.
+ const char* opd_section_; // Must be checked for NULL before use.
int64_t base_for_text_;
// Read PLT-related sections for the current architecture.
@@ -1026,7 +1046,7 @@ class ElfReaderImpl {
bool is_dwp_;
};
-ElfReader::ElfReader(const string &path)
+ElfReader::ElfReader(const string& path)
: path_(path), fd_(-1), impl32_(NULL), impl64_(NULL) {
// linux 2.6.XX kernel can show deleted files like this:
// /var/run/nscd/dbYLJYaE (deleted)
@@ -1063,7 +1083,7 @@ ElfReader::~ElfReader() {
#endif
template <typename ElfArch>
-static bool IsElfFile(const int fd, const string &path) {
+static bool IsElfFile(const int fd, const string& path) {
if (fd < 0)
return false;
if (!ElfReaderImpl<ElfArch>::IsArchElfFile(fd, NULL)) {
@@ -1086,7 +1106,7 @@ bool ElfReader::IsElf64File() const {
}
/*
-void ElfReader::AddSymbols(SymbolMap *symbols,
+void ElfReader::AddSymbols(SymbolMap* symbols,
uint64_t mem_offset, uint64_t file_offset,
uint64_t length) {
if (fd_ < 0)
@@ -1109,17 +1129,17 @@ void ElfReader::AddSymbols(SymbolMap *symbols,
}
*/
-void ElfReader::VisitSymbols(ElfReader::SymbolSink *sink) {
+void ElfReader::VisitSymbols(ElfReader::SymbolSink* sink) {
VisitSymbols(sink, -1, -1);
}
-void ElfReader::VisitSymbols(ElfReader::SymbolSink *sink,
+void ElfReader::VisitSymbols(ElfReader::SymbolSink* sink,
int symbol_binding,
int symbol_type) {
VisitSymbols(sink, symbol_binding, symbol_type, false);
}
-void ElfReader::VisitSymbols(ElfReader::SymbolSink *sink,
+void ElfReader::VisitSymbols(ElfReader::SymbolSink* sink,
int symbol_binding,
int symbol_type,
bool get_raw_symbol_values) {
@@ -1148,7 +1168,7 @@ uint64_t ElfReader::VaddrOfFirstLoadSegment() {
}
}
-const char *ElfReader::GetSectionName(int shndx) {
+const char* ElfReader::GetSectionName(int shndx) {
if (shndx < 0 || static_cast<unsigned int>(shndx) >= GetNumSections()) return NULL;
if (IsElf32File()) {
return GetImpl32()->GetSectionNameByIndex(shndx);
@@ -1169,7 +1189,7 @@ uint64_t ElfReader::GetNumSections() {
}
}
-const char *ElfReader::GetSectionByIndex(int shndx, size_t *size) {
+const char* ElfReader::GetSectionByIndex(int shndx, size_t* size) {
if (IsElf32File()) {
return GetImpl32()->GetSectionContentsByIndex(shndx, size);
} else if (IsElf64File()) {
@@ -1179,8 +1199,8 @@ const char *ElfReader::GetSectionByIndex(int shndx, size_t *size) {
}
}
-const char *ElfReader::GetSectionByName(const string &section_name,
- size_t *size) {
+const char* ElfReader::GetSectionByName(const string& section_name,
+ size_t* size) {
if (IsElf32File()) {
return GetImpl32()->GetSectionContentsByName(section_name, size);
} else if (IsElf64File()) {
@@ -1190,8 +1210,8 @@ const char *ElfReader::GetSectionByName(const string &section_name,
}
}
-const char *ElfReader::GetSectionInfoByName(const string &section_name,
- SectionInfo *info) {
+const char* ElfReader::GetSectionInfoByName(const string& section_name,
+ SectionInfo* info) {
if (IsElf32File()) {
return GetImpl32()->GetSectionInfoByName(section_name, info);
} else if (IsElf64File()) {
@@ -1201,11 +1221,15 @@ const char *ElfReader::GetSectionInfoByName(const string &section_name,
}
}
-bool ElfReader::SectionNamesMatch(const string &name, const string &sh_name) {
- if ((name.find(".debug_", 0) == 0) && (sh_name.find(".zdebug_", 0) == 0)) {
- const string name_suffix(name, strlen(".debug_"));
- const string sh_name_suffix(sh_name, strlen(".zdebug_"));
- return name_suffix == sh_name_suffix;
+bool ElfReader::SectionNamesMatch(std::string_view name,
+ std::string_view sh_name) {
+ std::string_view debug_prefix{".debug_"};
+ std::string_view zdebug_prefix{".zdebug_"};
+ if (StringViewStartsWith(name, debug_prefix) &&
+ StringViewStartsWith(sh_name, zdebug_prefix)) {
+ name.remove_prefix(debug_prefix.length());
+ sh_name.remove_prefix(zdebug_prefix.length());
+ return name == sh_name;
}
return name == sh_name;
}
@@ -1220,14 +1244,14 @@ bool ElfReader::IsDynamicSharedObject() {
}
}
-ElfReaderImpl<Elf32> *ElfReader::GetImpl32() {
+ElfReaderImpl<Elf32>* ElfReader::GetImpl32() {
if (impl32_ == NULL) {
impl32_ = new ElfReaderImpl<Elf32>(path_, fd_);
}
return impl32_;
}
-ElfReaderImpl<Elf64> *ElfReader::GetImpl64() {
+ElfReaderImpl<Elf64>* ElfReader::GetImpl64() {
if (impl64_ == NULL) {
impl64_ = new ElfReaderImpl<Elf64>(path_, fd_);
}
@@ -1238,7 +1262,7 @@ ElfReaderImpl<Elf64> *ElfReader::GetImpl64() {
// debug info (debug_only=true) or symbol table (debug_only=false).
// Otherwise, return false.
template <typename ElfArch>
-static bool IsNonStrippedELFBinaryImpl(const string &path, const int fd,
+static bool IsNonStrippedELFBinaryImpl(const string& path, const int fd,
bool debug_only) {
if (!ElfReaderImpl<ElfArch>::IsArchElfFile(fd, NULL)) return false;
ElfReaderImpl<ElfArch> elf_reader(path, fd);
@@ -1248,7 +1272,7 @@ static bool IsNonStrippedELFBinaryImpl(const string &path, const int fd,
}
// Helper for the IsNon[Debug]StrippedELFBinary functions.
-static bool IsNonStrippedELFBinaryHelper(const string &path,
+static bool IsNonStrippedELFBinaryHelper(const string& path,
bool debug_only) {
const int fd = open(path.c_str(), O_RDONLY);
if (fd == -1) {
@@ -1264,11 +1288,11 @@ static bool IsNonStrippedELFBinaryHelper(const string &path,
return false;
}
-bool ElfReader::IsNonStrippedELFBinary(const string &path) {
+bool ElfReader::IsNonStrippedELFBinary(const string& path) {
return IsNonStrippedELFBinaryHelper(path, false);
}
-bool ElfReader::IsNonDebugStrippedELFBinary(const string &path) {
+bool ElfReader::IsNonDebugStrippedELFBinary(const string& path) {
return IsNonStrippedELFBinaryHelper(path, true);
}
-} // namespace dwarf2reader
+} // namespace google_breakpad
diff --git a/src/common/dwarf/elf_reader.h b/src/common/dwarf/elf_reader.h
index 8eaa5aa9..a6dec755 100644
--- a/src/common/dwarf/elf_reader.h
+++ b/src/common/dwarf/elf_reader.h
@@ -1,4 +1,4 @@
-// Copyright 2005 Google Inc. All Rights Reserved.
+// Copyright 2005 Google LLC
// Author: chatham@google.com (Andrew Chatham)
// Author: satorux@google.com (Satoru Takabayashi)
//
@@ -16,6 +16,7 @@
#define COMMON_DWARF_ELF_READER_H__
#include <string>
+#include <string_view>
#include <vector>
#include "common/dwarf/types.h"
@@ -24,7 +25,7 @@
using std::vector;
using std::pair;
-namespace dwarf2reader {
+namespace google_breakpad {
class SymbolMap;
class Elf32;
@@ -34,7 +35,7 @@ class ElfReaderImpl;
class ElfReader {
public:
- explicit ElfReader(const string &path);
+ explicit ElfReader(const string& path);
~ElfReader();
// Parse the ELF prologue of this file and return whether it was
@@ -62,29 +63,29 @@ class ElfReader {
// mem_offset - position at which the segment is mapped into memory
// file_offset - offset in the file where the mapping begins
// length - length of the mapped segment
- void AddSymbols(SymbolMap *symbols,
+ void AddSymbols(SymbolMap* symbols,
uint64_t mem_offset, uint64_t file_offset,
uint64_t length);
class SymbolSink {
public:
virtual ~SymbolSink() {}
- virtual void AddSymbol(const char *name, uint64_t address,
+ virtual void AddSymbol(const char* name, uint64_t address,
uint64_t size) = 0;
};
// Like AddSymbols above, but with no address correction.
// Processes any SHT_SYMTAB section, followed by any SHT_DYNSYM section.
- void VisitSymbols(SymbolSink *sink);
+ void VisitSymbols(SymbolSink* sink);
// Like VisitSymbols above, but for a specific symbol binding/type.
// A negative value for the binding and type parameters means any
// binding or type.
- void VisitSymbols(SymbolSink *sink, int symbol_binding, int symbol_type);
+ void VisitSymbols(SymbolSink* sink, int symbol_binding, int symbol_type);
// Like VisitSymbols above but can optionally export raw symbol values instead
// of adjusted ones.
- void VisitSymbols(SymbolSink *sink, int symbol_binding, int symbol_type,
+ void VisitSymbols(SymbolSink* sink, int symbol_binding, int symbol_type,
bool get_raw_symbol_values);
// p_vaddr of the first PT_LOAD segment (if any), or 0 if no PT_LOAD
@@ -95,7 +96,7 @@ class ElfReader {
// Return the name of section "shndx". Returns NULL if the section
// is not found.
- const char *GetSectionName(int shndx);
+ const char* GetSectionName(int shndx);
// Return the number of sections in the given ELF file.
uint64_t GetNumSections();
@@ -104,14 +105,14 @@ class ElfReader {
// the pointer to the section and store the size in "size".
// On error, return NULL. The returned section data is only valid
// until the ElfReader gets destroyed.
- const char *GetSectionByIndex(int shndx, size_t *size);
+ const char* GetSectionByIndex(int shndx, size_t* size);
// Get section with "section_name" (ex. ".text", ".symtab") in the
// given ELF file. On success, return the pointer to the section
// and store the size in "size". On error, return NULL. The
// returned section data is only valid until the ElfReader gets
// destroyed.
- const char *GetSectionByName(const string &section_name, size_t *size);
+ const char* GetSectionByName(const string& section_name, size_t* size);
// This is like GetSectionByName() but it returns a lot of extra information
// about the section. The SectionInfo structure is almost identical to
@@ -129,39 +130,40 @@ class ElfReader {
uint64_t addralign; // Section alignment.
uint64_t entsize; // Entry size if section holds a table.
};
- const char *GetSectionInfoByName(const string &section_name,
- SectionInfo *info);
+ const char* GetSectionInfoByName(const string& section_name,
+ SectionInfo* info);
// Check if "path" is an ELF binary that has not been stripped of symbol
// tables. This function supports both 32-bit and 64-bit ELF binaries.
- static bool IsNonStrippedELFBinary(const string &path);
+ static bool IsNonStrippedELFBinary(const string& path);
// Check if "path" is an ELF binary that has not been stripped of debug
// info. Unlike IsNonStrippedELFBinary, this function will return
// false for binaries passed through "strip -S".
- static bool IsNonDebugStrippedELFBinary(const string &path);
+ static bool IsNonDebugStrippedELFBinary(const string& path);
// Match a requested section name with the section name as it
// appears in the elf-file, adjusting for compressed debug section
// names. For example, returns true if name == ".debug_abbrev" and
// sh_name == ".zdebug_abbrev"
- static bool SectionNamesMatch(const string &name, const string &sh_name);
+ static bool SectionNamesMatch(std::string_view name,
+ std::string_view sh_name);
private:
// Lazily initialize impl32_ and return it.
- ElfReaderImpl<Elf32> *GetImpl32();
+ ElfReaderImpl<Elf32>* GetImpl32();
// Ditto for impl64_.
- ElfReaderImpl<Elf64> *GetImpl64();
+ ElfReaderImpl<Elf64>* GetImpl64();
// Path of the file we're reading.
const string path_;
// Read-only file descriptor for the file. May be -1 if there was an
// error during open.
int fd_;
- ElfReaderImpl<Elf32> *impl32_;
- ElfReaderImpl<Elf64> *impl64_;
+ ElfReaderImpl<Elf32>* impl32_;
+ ElfReaderImpl<Elf64>* impl64_;
};
-} // namespace dwarf2reader
+} // namespace google_breakpad
#endif // COMMON_DWARF_ELF_READER_H__
diff --git a/src/common/dwarf/functioninfo.cc b/src/common/dwarf/functioninfo.cc
index 358a6eef..d8fdb842 100644
--- a/src/common/dwarf/functioninfo.cc
+++ b/src/common/dwarf/functioninfo.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2010 Google Inc. All Rights Reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -10,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -42,24 +42,16 @@
#include "common/scoped_ptr.h"
#include "common/using_std_string.h"
-using google_breakpad::scoped_ptr;
-
-namespace dwarf2reader {
+namespace google_breakpad {
CULineInfoHandler::CULineInfoHandler(std::vector<SourceFileInfo>* files,
std::vector<string>* dirs,
LineMap* linemap):linemap_(linemap),
files_(files),
dirs_(dirs) {
- // The dirs and files are 1 indexed, so just make sure we put
- // nothing in the 0 vector.
- assert(dirs->size() == 0);
- assert(files->size() == 0);
- dirs->push_back("");
- SourceFileInfo s;
- s.name = "";
- s.lowpc = ULLONG_MAX;
- files->push_back(s);
+ // In dwarf4, the dirs and files are 1 indexed, and in dwarf5 they are zero
+ // indexed. This is handled in the LineInfo reader, so empty files are not
+ // needed here.
}
void CULineInfoHandler::DefineDir(const string& name, uint32_t dir_num) {
@@ -150,7 +142,7 @@ bool CUFunctionInfoHandler::StartDIE(uint64_t offset, enum DwarfTag tag) {
void CUFunctionInfoHandler::ProcessAttributeString(uint64_t offset,
enum DwarfAttribute attr,
enum DwarfForm form,
- const string &data) {
+ const string& data) {
if (current_function_info_) {
if (attr == DW_AT_name)
current_function_info_->name = data;
@@ -164,7 +156,8 @@ void CUFunctionInfoHandler::ProcessAttributeUnsigned(uint64_t offset,
enum DwarfForm form,
uint64_t data) {
if (attr == DW_AT_stmt_list) {
- SectionMap::const_iterator iter = sections_.find("__debug_line");
+ SectionMap::const_iterator iter =
+ GetSectionByName(sections_, ".debug_line");
assert(iter != sections_.end());
scoped_ptr<LineInfo> lireader(new LineInfo(iter->second.first + data,
@@ -232,4 +225,4 @@ void CUFunctionInfoHandler::EndDIE(uint64_t offset) {
current_function_info_));
}
-} // namespace dwarf2reader
+} // namespace google_breakpad
diff --git a/src/common/dwarf/functioninfo.h b/src/common/dwarf/functioninfo.h
index 5c733c6d..1387c5ba 100644
--- a/src/common/dwarf/functioninfo.h
+++ b/src/common/dwarf/functioninfo.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2010 Google Inc. All Rights Reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -10,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -43,7 +43,7 @@
#include "common/using_std_string.h"
-namespace dwarf2reader {
+namespace google_breakpad {
struct FunctionInfo {
// Name of the function
@@ -187,5 +187,5 @@ class CUFunctionInfoHandler: public Dwarf2Handler {
uint64_t current_compilation_unit_offset_;
};
-} // namespace dwarf2reader
+} // namespace google_breakpad
#endif // COMMON_DWARF_FUNCTIONINFO_H__
diff --git a/src/common/dwarf/line_state_machine.h b/src/common/dwarf/line_state_machine.h
index fc301c76..1797e3bc 100644
--- a/src/common/dwarf/line_state_machine.h
+++ b/src/common/dwarf/line_state_machine.h
@@ -1,4 +1,4 @@
-// Copyright 2008 Google Inc. All Rights Reserved.
+// Copyright 2008 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -10,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -30,7 +30,9 @@
#ifndef COMMON_DWARF_LINE_STATE_MACHINE_H__
#define COMMON_DWARF_LINE_STATE_MACHINE_H__
-namespace dwarf2reader {
+#include <stdint.h>
+
+namespace google_breakpad {
// This is the format of a DWARF2/3 line state machine that we process
// opcodes using. There is no need for anything outside the lineinfo
@@ -55,7 +57,7 @@ struct LineStateMachine {
bool end_sequence;
};
-} // namespace dwarf2reader
+} // namespace google_breakpad
#endif // COMMON_DWARF_LINE_STATE_MACHINE_H__
diff --git a/src/common/dwarf/types.h b/src/common/dwarf/types.h
index 23412d0e..b14d7a3e 100644
--- a/src/common/dwarf/types.h
+++ b/src/common/dwarf/types.h
@@ -1,4 +1,4 @@
-// Copyright 2008 Google, Inc. All Rights reserved
+// Copyright 2008 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -10,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/common/dwarf_cfi_to_module.cc b/src/common/dwarf_cfi_to_module.cc
index 3dd85edd..7da8507d 100644
--- a/src/common/dwarf_cfi_to_module.cc
+++ b/src/common/dwarf_cfi_to_module.cc
@@ -1,7 +1,6 @@
// -*- mode: c++ -*-
-// Copyright (c) 2010, Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -13,7 +12,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -34,7 +33,9 @@
// Implementation of google_breakpad::DwarfCFIToModule.
// See dwarf_cfi_to_module.h for details.
+#include <memory>
#include <sstream>
+#include <utility>
#include "common/dwarf_cfi_to_module.h"
@@ -143,16 +144,16 @@ vector<string> DwarfCFIToModule::RegisterNames::MIPS() {
}
bool DwarfCFIToModule::Entry(size_t offset, uint64_t address, uint64_t length,
- uint8_t version, const string &augmentation,
+ uint8_t version, const string& augmentation,
unsigned return_address) {
assert(!entry_);
- // If dwarf2reader::CallFrameInfo can handle this version and
+ // If CallFrameInfo can handle this version and
// augmentation, then we should be okay with that, so there's no
// need to check them here.
// Get ready to collect entries.
- entry_ = new Module::StackFrameEntry;
+ entry_ = std::make_unique<Module::StackFrameEntry>();
entry_->address = address;
entry_->size = length;
entry_offset_ = offset;
@@ -184,13 +185,11 @@ string DwarfCFIToModule::RegisterName(int i) {
return register_names_[reg];
reporter_->UnnamedRegister(entry_offset_, reg);
- char buf[30];
- sprintf(buf, "unnamed_register%u", reg);
- return buf;
+ return string("unnamed_register") + std::to_string(reg);
}
void DwarfCFIToModule::Record(Module::Address address, int reg,
- const string &rule) {
+ const string& rule) {
assert(entry_);
// Place the name in our global set of strings, and then use the string
@@ -247,25 +246,28 @@ bool DwarfCFIToModule::RegisterRule(uint64_t address, int reg,
}
bool DwarfCFIToModule::ExpressionRule(uint64_t address, int reg,
- const string &expression) {
+ const string& expression) {
reporter_->ExpressionsNotSupported(entry_offset_, RegisterName(reg));
// Treat this as a non-fatal error.
return true;
}
bool DwarfCFIToModule::ValExpressionRule(uint64_t address, int reg,
- const string &expression) {
+ const string& expression) {
reporter_->ExpressionsNotSupported(entry_offset_, RegisterName(reg));
// Treat this as a non-fatal error.
return true;
}
bool DwarfCFIToModule::End() {
- module_->AddStackFrameEntry(entry_);
- entry_ = NULL;
+ module_->AddStackFrameEntry(std::move(entry_));
return true;
}
+string DwarfCFIToModule::Architecture() {
+ return module_->architecture();
+}
+
void DwarfCFIToModule::Reporter::UnnamedRegister(size_t offset, int reg) {
fprintf(stderr, "%s, section '%s': "
"the call frame entry at offset 0x%zx refers to register %d,"
@@ -274,7 +276,7 @@ void DwarfCFIToModule::Reporter::UnnamedRegister(size_t offset, int reg) {
}
void DwarfCFIToModule::Reporter::UndefinedNotSupported(size_t offset,
- const string &reg) {
+ const string& reg) {
fprintf(stderr, "%s, section '%s': "
"the call frame entry at offset 0x%zx sets the rule for "
"register '%s' to 'undefined', but the Breakpad symbol file format"
@@ -283,7 +285,7 @@ void DwarfCFIToModule::Reporter::UndefinedNotSupported(size_t offset,
}
void DwarfCFIToModule::Reporter::ExpressionsNotSupported(size_t offset,
- const string &reg) {
+ const string& reg) {
fprintf(stderr, "%s, section '%s': "
"the call frame entry at offset 0x%zx uses a DWARF expression to"
" describe how to recover register '%s', "
diff --git a/src/common/dwarf_cfi_to_module.h b/src/common/dwarf_cfi_to_module.h
index 4d2db7ee..42b618d5 100644
--- a/src/common/dwarf_cfi_to_module.h
+++ b/src/common/dwarf_cfi_to_module.h
@@ -1,7 +1,6 @@
// -*- mode: c++ -*-
-// Copyright (c) 2010, Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -13,7 +12,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -44,6 +43,7 @@
#include <set>
#include <string>
+#include <memory>
#include <vector>
#include "common/module.h"
@@ -52,7 +52,6 @@
namespace google_breakpad {
-using dwarf2reader::CallFrameInfo;
using google_breakpad::Module;
using std::set;
using std::vector;
@@ -71,7 +70,7 @@ class DwarfCFIToModule: public CallFrameInfo::Handler {
// stream. FILE is the name of the file we're processing, and
// SECTION is the name of the section within that file that we're
// looking at (.debug_frame, .eh_frame, etc.).
- Reporter(const string &file, const string &section)
+ Reporter(const string& file, const string& section)
: file_(file), section_(section) { }
virtual ~Reporter() { }
@@ -83,13 +82,13 @@ class DwarfCFIToModule: public CallFrameInfo::Handler {
// The DWARF CFI entry at OFFSET says that REG is undefined, but the
// Breakpad symbol file format cannot express this.
- virtual void UndefinedNotSupported(size_t offset, const string &reg);
+ virtual void UndefinedNotSupported(size_t offset, const string& reg);
// The DWARF CFI entry at OFFSET says that REG uses a DWARF
// expression to find its value, but DwarfCFIToModule is not
// capable of translating DWARF expressions to Breakpad postfix
// expressions.
- virtual void ExpressionsNotSupported(size_t offset, const string &reg);
+ virtual void ExpressionsNotSupported(size_t offset, const string& reg);
protected:
string file_, section_;
@@ -118,10 +117,10 @@ class DwarfCFIToModule: public CallFrameInfo::Handler {
private:
// Given STRINGS, an array of C strings with SIZE elements, return an
// equivalent vector<string>.
- static vector<string> MakeVector(const char * const *strings, size_t size);
+ static vector<string> MakeVector(const char* const* strings, size_t size);
};
- // Create a handler for the dwarf2reader::CallFrameInfo parser that
+ // Create a handler for the CallFrameInfo parser that
// records the stack unwinding information it receives in MODULE.
//
// Use REGISTER_NAMES[I] as the name of register number I; *this
@@ -130,15 +129,15 @@ class DwarfCFIToModule: public CallFrameInfo::Handler {
//
// Use REPORTER for reporting problems encountered in the conversion
// process.
- DwarfCFIToModule(Module *module, const vector<string> &register_names,
- Reporter *reporter)
+ DwarfCFIToModule(Module* module, const vector<string>& register_names,
+ Reporter* reporter)
: module_(module), register_names_(register_names), reporter_(reporter),
- entry_(NULL), return_address_(-1), cfa_name_(".cfa"), ra_name_(".ra") {
+ return_address_(-1), cfa_name_(".cfa"), ra_name_(".ra") {
}
- virtual ~DwarfCFIToModule() { delete entry_; }
+ virtual ~DwarfCFIToModule() = default;
virtual bool Entry(size_t offset, uint64_t address, uint64_t length,
- uint8_t version, const string &augmentation,
+ uint8_t version, const string& augmentation,
unsigned return_address);
virtual bool UndefinedRule(uint64_t address, int reg);
virtual bool SameValueRule(uint64_t address, int reg);
@@ -148,29 +147,31 @@ class DwarfCFIToModule: public CallFrameInfo::Handler {
int base_register, long offset);
virtual bool RegisterRule(uint64_t address, int reg, int base_register);
virtual bool ExpressionRule(uint64_t address, int reg,
- const string &expression);
+ const string& expression);
virtual bool ValExpressionRule(uint64_t address, int reg,
- const string &expression);
+ const string& expression);
virtual bool End();
+ virtual string Architecture();
+
private:
// Return the name to use for register REG.
string RegisterName(int i);
// Record RULE for register REG at ADDRESS.
- void Record(Module::Address address, int reg, const string &rule);
+ void Record(Module::Address address, int reg, const string& rule);
// The module to which we should add entries.
- Module *module_;
+ Module* module_;
// Map from register numbers to register names.
- const vector<string> &register_names_;
+ const vector<string>& register_names_;
// The reporter to use to report problems.
- Reporter *reporter_;
+ Reporter* reporter_;
// The current entry we're constructing.
- Module::StackFrameEntry *entry_;
+ std::unique_ptr<Module::StackFrameEntry> entry_;
// The section offset of the current frame description entry, for
// use in error messages.
diff --git a/src/common/dwarf_cfi_to_module_unittest.cc b/src/common/dwarf_cfi_to_module_unittest.cc
index 60a9a3ee..0b677b21 100644
--- a/src/common/dwarf_cfi_to_module_unittest.cc
+++ b/src/common/dwarf_cfi_to_module_unittest.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2010, Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -47,11 +46,11 @@ using testing::Test;
using testing::_;
struct MockCFIReporter: public DwarfCFIToModule::Reporter {
- MockCFIReporter(const string &file, const string &section)
+ MockCFIReporter(const string& file, const string& section)
: Reporter(file, section) { }
MOCK_METHOD2(UnnamedRegister, void(size_t offset, int reg));
- MOCK_METHOD2(UndefinedNotSupported, void(size_t offset, const string &reg));
- MOCK_METHOD2(ExpressionsNotSupported, void(size_t offset, const string &reg));
+ MOCK_METHOD2(UndefinedNotSupported, void(size_t offset, const string& reg));
+ MOCK_METHOD2(ExpressionsNotSupported, void(size_t offset, const string& reg));
};
struct DwarfCFIToModuleFixture {
@@ -80,7 +79,7 @@ struct DwarfCFIToModuleFixture {
vector<string> register_names;
MockCFIReporter reporter;
DwarfCFIToModule handler;
- vector<Module::StackFrameEntry *> entries;
+ vector<Module::StackFrameEntry*> entries;
};
class Entry: public DwarfCFIToModuleFixture, public Test { };
diff --git a/src/common/dwarf_cu_to_module.cc b/src/common/dwarf_cu_to_module.cc
index ad873059..a5a1fd06 100644
--- a/src/common/dwarf_cu_to_module.cc
+++ b/src/common/dwarf_cu_to_module.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2010 Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -44,11 +43,12 @@
#include <stdio.h>
#include <algorithm>
+#include <memory>
#include <numeric>
#include <utility>
+#include "common/string_view.h"
#include "common/dwarf_line_to_module.h"
-#include "common/unordered.h"
#include "google_breakpad/common/breakpad_types.h"
namespace google_breakpad {
@@ -58,6 +58,7 @@ using std::map;
using std::pair;
using std::sort;
using std::vector;
+using std::unique_ptr;
// Data provided by a DWARF specification DIE.
//
@@ -78,22 +79,21 @@ using std::vector;
// we may need if we find a DW_AT_specification link pointing to it.
struct DwarfCUToModule::Specification {
// The qualified name that can be found by demangling DW_AT_MIPS_linkage_name.
- string qualified_name;
+ StringView qualified_name;
// The name of the enclosing scope, or the empty string if there is none.
- string enclosing_name;
+ StringView enclosing_name;
// The name for the specification DIE itself, without any enclosing
// name components.
- string unqualified_name;
+ StringView unqualified_name;
};
// An abstract origin -- base definition of an inline function.
struct AbstractOrigin {
- AbstractOrigin() : name() {}
- explicit AbstractOrigin(const string& name) : name(name) {}
+ explicit AbstractOrigin(StringView name) : name(name) {}
- string name;
+ StringView name;
};
typedef map<uint64_t, AbstractOrigin> AbstractOriginByOffset;
@@ -101,35 +101,20 @@ typedef map<uint64_t, AbstractOrigin> AbstractOriginByOffset;
// Data global to the DWARF-bearing file that is private to the
// DWARF-to-Module process.
struct DwarfCUToModule::FilePrivate {
- // A set of strings used in this CU. Before storing a string in one of
- // our data structures, insert it into this set, and then use the string
- // from the set.
- //
- // In some STL implementations, strings are reference-counted internally,
- // meaning that simply using strings from this set, even if passed by
- // value, assigned, or held directly in structures and containers
- // (map<string, ...>, for example), causes those strings to share a
- // single instance of each distinct piece of text. GNU's libstdc++ uses
- // reference counts, and I believe MSVC did as well, at some point.
- // However, C++ '11 implementations are moving away from reference
- // counting.
- //
- // In other implementations, string assignments copy the string's text,
- // so this set will actually hold yet another copy of the string (although
- // everything will still work). To improve memory consumption portably,
- // we will probably need to use pointers to strings held in this set.
- unordered_set<string> common_strings;
-
// A map from offsets of DIEs within the .debug_info section to
// Specifications describing those DIEs. Specification references can
// cross compilation unit boundaries.
SpecificationByOffset specifications;
AbstractOriginByOffset origins;
+
+ // Keep a list of forward references from DW_AT_abstract_origin and
+ // DW_AT_specification attributes so names can be fixed up.
+ std::map<uint64_t, Module::Function*> forward_ref_die_to_func;
};
-DwarfCUToModule::FileContext::FileContext(const string &filename,
- Module *module,
+DwarfCUToModule::FileContext::FileContext(const string& filename,
+ Module* module,
bool handle_inter_cu_refs)
: filename_(filename),
module_(module),
@@ -138,18 +123,28 @@ DwarfCUToModule::FileContext::FileContext(const string &filename,
}
DwarfCUToModule::FileContext::~FileContext() {
+ for (std::vector<uint8_t *>::iterator i = uncompressed_sections_.begin();
+ i != uncompressed_sections_.end(); ++i) {
+ delete[] *i;
+ }
}
void DwarfCUToModule::FileContext::AddSectionToSectionMap(
- const string& name, const uint8_t *contents, uint64_t length) {
+ const string& name, const uint8_t* contents, uint64_t length) {
section_map_[name] = std::make_pair(contents, length);
}
+void DwarfCUToModule::FileContext::AddManagedSectionToSectionMap(
+ const string& name, uint8_t* contents, uint64_t length) {
+ section_map_[name] = std::make_pair(contents, length);
+ uncompressed_sections_.push_back(contents);
+}
+
void DwarfCUToModule::FileContext::ClearSectionMapForTest() {
section_map_.clear();
}
-const dwarf2reader::SectionMap&
+const SectionMap&
DwarfCUToModule::FileContext::section_map() const {
return section_map_;
}
@@ -170,52 +165,104 @@ bool DwarfCUToModule::FileContext::IsUnhandledInterCUReference(
// parsing. This is for data shared across the CU's entire DIE tree,
// and parameters from the code invoking the CU parser.
struct DwarfCUToModule::CUContext {
- CUContext(FileContext *file_context_arg, WarningReporter *reporter_arg,
- RangesHandler *ranges_handler_arg)
- : file_context(file_context_arg),
+ CUContext(FileContext* file_context_arg, WarningReporter* reporter_arg,
+ RangesHandler* ranges_handler_arg)
+ : version(0),
+ file_context(file_context_arg),
reporter(reporter_arg),
ranges_handler(ranges_handler_arg),
language(Language::CPlusPlus),
low_pc(0),
high_pc(0),
- ranges(0) {}
+ ranges_form(DW_FORM_sec_offset),
+ ranges_data(0),
+ ranges_base(0),
+ str_offsets_base(0) { }
~CUContext() {
- for (vector<Module::Function *>::iterator it = functions.begin();
+ for (vector<Module::Function*>::iterator it = functions.begin();
it != functions.end(); ++it) {
delete *it;
}
};
+ // Dwarf version of the source CU.
+ uint8_t version;
+
// The DWARF-bearing file into which this CU was incorporated.
- FileContext *file_context;
+ FileContext* file_context;
// For printing error messages.
- WarningReporter *reporter;
+ WarningReporter* reporter;
// For reading ranges from the .debug_ranges section
- RangesHandler *ranges_handler;
+ RangesHandler* ranges_handler;
// The source language of this compilation unit.
- const Language *language;
+ const Language* language;
// Addresses covered by this CU. If high_pc_ is non-zero then the CU covers
- // low_pc to high_pc, otherwise ranges is non-zero and low_pc represents
- // the base address of the ranges covered by the CU.
+ // low_pc to high_pc, otherwise ranges_data is non-zero and low_pc represents
+ // the base address of the ranges covered by the CU. ranges_data will define
+ // the CU's actual ranges.
uint64_t low_pc;
uint64_t high_pc;
- uint64_t ranges;
+
+ // Ranges for this CU are read according to this form.
+ enum DwarfForm ranges_form;
+ uint64_t ranges_data;
+
+ // Offset into .debug_rngslists where this CU's ranges are stored.
+ // Data in DW_FORM_rnglistx is relative to this offset.
+ uint64_t ranges_base;
+
+ // Offset into .debug_addr where this CU's addresses are stored. Data in
+ // form DW_FORM_addrxX is relative to this offset.
+ uint64_t addr_base;
+
+ // Offset into this CU's contribution to .debug_str_offsets.
+ uint64_t str_offsets_base;
+
+ // Collect all the data from the CU that a RangeListReader needs to read a
+ // range.
+ bool AssembleRangeListInfo(
+ RangeListReader::CURangesInfo* info) {
+ const SectionMap& section_map
+ = file_context->section_map();
+ info->version_ = version;
+ info->base_address_ = low_pc;
+ info->ranges_base_ = ranges_base;
+ const char* section_name = (version <= 4 ?
+ ".debug_ranges" : ".debug_rnglists");
+ SectionMap::const_iterator map_entry
+ = GetSectionByName(section_map, section_name);
+ if (map_entry == section_map.end()) {
+ return false;
+ }
+ info->buffer_ = map_entry->second.first;
+ info->size_ = map_entry->second.second;
+ if (version > 4) {
+ SectionMap::const_iterator map_entry
+ = GetSectionByName(section_map, ".debug_addr");
+ if (map_entry == section_map.end()) {
+ return false;
+ }
+ info->addr_buffer_ = map_entry->second.first;
+ info->addr_buffer_size_ = map_entry->second.second;
+ info->addr_base_ = addr_base;
+ }
+ return true;
+ }
// The functions defined in this compilation unit. We accumulate
// them here during parsing. Then, in DwarfCUToModule::Finish, we
// assign them lines and add them to file_context->module.
//
// Destroying this destroys all the functions this vector points to.
- vector<Module::Function *> functions;
+ vector<Module::Function*> functions;
- // Keep a list of forward references from DW_AT_abstract_origin and
- // DW_AT_specification attributes so names can be fixed up.
- std::map<uint64_t, Module::Function *> forward_ref_die_to_func;
+ // A map of function pointers to the its forward specification DIE's offset.
+ map<Module::Function*, uint64_t> spec_function_offsets;
};
// Information about the context of a particular DIE. This is for
@@ -232,23 +279,25 @@ struct DwarfCUToModule::DIEContext {
// in a C++ compilation unit, the DIEContext's name for the
// DW_TAG_subprogram DIE would be "Foo::Bar". The DIEContext's
// name for the DW_TAG_namespace DIE would be "".
- string name;
+ StringView name;
};
// An abstract base class for all the dumper's DIE handlers.
-class DwarfCUToModule::GenericDIEHandler: public dwarf2reader::DIEHandler {
+class DwarfCUToModule::GenericDIEHandler: public DIEHandler {
public:
// Create a handler for the DIE at OFFSET whose compilation unit is
// described by CU_CONTEXT, and whose immediate context is described
// by PARENT_CONTEXT.
- GenericDIEHandler(CUContext *cu_context, DIEContext *parent_context,
+ GenericDIEHandler(CUContext* cu_context, DIEContext* parent_context,
uint64_t offset)
: cu_context_(cu_context),
parent_context_(parent_context),
offset_(offset),
declaration_(false),
specification_(NULL),
- forward_ref_die_offset_(0) { }
+ no_specification(false),
+ abstract_origin_(NULL),
+ forward_ref_die_offset_(0), specification_offset_(0) { }
// Derived classes' ProcessAttributeUnsigned can defer to this to
// handle DW_AT_declaration, or simply not override it.
@@ -266,7 +315,7 @@ class DwarfCUToModule::GenericDIEHandler: public dwarf2reader::DIEHandler {
// handle DW_AT_specification, or simply not override it.
void ProcessAttributeString(enum DwarfAttribute attr,
enum DwarfForm form,
- const string &data);
+ const string& data);
protected:
// Compute and return the fully-qualified name of the DIE. If this
@@ -277,20 +326,12 @@ class DwarfCUToModule::GenericDIEHandler: public dwarf2reader::DIEHandler {
// Use this from EndAttributes member functions, not ProcessAttribute*
// functions; only the former can be sure that all the DIE's attributes
// have been seen.
- string ComputeQualifiedName();
+ StringView ComputeQualifiedName();
- CUContext *cu_context_;
- DIEContext *parent_context_;
+ CUContext* cu_context_;
+ DIEContext* parent_context_;
uint64_t offset_;
- // Place the name in the global set of strings. Even though this looks
- // like a copy, all the major string implementations use reference
- // counting internally, so the effect is to have all the data structures
- // share copies of strings whenever possible.
- // FIXME: Should this return something like a string_ref to avoid the
- // assumption about how strings are implemented?
- string AddStringToPool(const string &str);
-
// If this DIE has a DW_AT_declaration attribute, this is its value.
// It is false on DIEs with no DW_AT_declaration attribute.
bool declaration_;
@@ -298,25 +339,37 @@ class DwarfCUToModule::GenericDIEHandler: public dwarf2reader::DIEHandler {
// If this DIE has a DW_AT_specification attribute, this is the
// Specification structure for the DIE the attribute refers to.
// Otherwise, this is NULL.
- Specification *specification_;
+ Specification* specification_;
+
+ // If this DIE has DW_AT_specification with offset smaller than this DIE and
+ // we can't find that in the specification map.
+ bool no_specification;
+
+ // If this DIE has a DW_AT_abstract_origin attribute, this is the
+ // AbstractOrigin structure for the DIE the attribute refers to.
+ // Otherwise, this is NULL.
+ const AbstractOrigin* abstract_origin_;
// If this DIE has a DW_AT_specification or DW_AT_abstract_origin and it is a
// forward reference, no Specification will be available. Track the reference
// to be fixed up when the DIE is parsed.
uint64_t forward_ref_die_offset_;
+ // The root offset of Specification or abstract origin.
+ uint64_t specification_offset_;
+
// The value of the DW_AT_name attribute, or the empty string if the
// DIE has no such attribute.
- string name_attribute_;
+ StringView name_attribute_;
// The demangled value of the DW_AT_MIPS_linkage_name attribute, or the empty
// string if the DIE has no such attribute or its content could not be
// demangled.
- string demangled_name_;
+ StringView demangled_name_;
// The non-demangled value of the DW_AT_MIPS_linkage_name attribute,
// it its content count not be demangled.
- string raw_name_;
+ StringView raw_name_;
};
void DwarfCUToModule::GenericDIEHandler::ProcessAttributeUnsigned(
@@ -324,7 +377,7 @@ void DwarfCUToModule::GenericDIEHandler::ProcessAttributeUnsigned(
enum DwarfForm form,
uint64_t data) {
switch (attr) {
- case dwarf2reader::DW_AT_declaration: declaration_ = (data != 0); break;
+ case DW_AT_declaration: declaration_ = (data != 0); break;
default: break;
}
}
@@ -334,8 +387,8 @@ void DwarfCUToModule::GenericDIEHandler::ProcessAttributeReference(
enum DwarfForm form,
uint64_t data) {
switch (attr) {
- case dwarf2reader::DW_AT_specification: {
- FileContext *file_context = cu_context_->file_context;
+ case DW_AT_specification: {
+ FileContext* file_context = cu_context_->file_context;
if (file_context->IsUnhandledInterCUReference(
data, cu_context_->reporter->cu_offset())) {
cu_context_->reporter->UnhandledInterCUReference(offset_, data);
@@ -346,7 +399,7 @@ void DwarfCUToModule::GenericDIEHandler::ProcessAttributeReference(
// here, but it's better to leave the real work to our
// EndAttribute member function, at which point we know we have
// seen all the DIE's attributes.
- SpecificationByOffset *specifications =
+ SpecificationByOffset* specifications =
&file_context->file_private_->specifications;
SpecificationByOffset::iterator spec = specifications->find(data);
if (spec != specifications->end()) {
@@ -354,45 +407,53 @@ void DwarfCUToModule::GenericDIEHandler::ProcessAttributeReference(
} else if (data > offset_) {
forward_ref_die_offset_ = data;
} else {
- cu_context_->reporter->UnknownSpecification(offset_, data);
+ no_specification = true;
}
+ specification_offset_ = data;
+ break;
+ }
+ case DW_AT_abstract_origin: {
+ const AbstractOriginByOffset& origins =
+ cu_context_->file_context->file_private_->origins;
+ AbstractOriginByOffset::const_iterator origin = origins.find(data);
+ if (origin != origins.end()) {
+ abstract_origin_ = &(origin->second);
+ } else if (data > offset_) {
+ forward_ref_die_offset_ = data;
+ }
+ specification_offset_ = data;
break;
}
default: break;
}
}
-string DwarfCUToModule::GenericDIEHandler::AddStringToPool(const string &str) {
- pair<unordered_set<string>::iterator, bool> result =
- cu_context_->file_context->file_private_->common_strings.insert(str);
- return *result.first;
-}
-
void DwarfCUToModule::GenericDIEHandler::ProcessAttributeString(
enum DwarfAttribute attr,
enum DwarfForm form,
- const string &data) {
+ const string& data) {
switch (attr) {
- case dwarf2reader::DW_AT_name:
- name_attribute_ = AddStringToPool(data);
+ case DW_AT_name:
+ name_attribute_ =
+ cu_context_->file_context->module_->AddStringToPool(data);
break;
- case dwarf2reader::DW_AT_MIPS_linkage_name:
- case dwarf2reader::DW_AT_linkage_name: {
+ case DW_AT_MIPS_linkage_name:
+ case DW_AT_linkage_name: {
string demangled;
Language::DemangleResult result =
cu_context_->language->DemangleName(data, &demangled);
switch (result) {
case Language::kDemangleSuccess:
- demangled_name_ = AddStringToPool(demangled);
+ demangled_name_ =
+ cu_context_->file_context->module_->AddStringToPool(demangled);
break;
case Language::kDemangleFailure:
cu_context_->reporter->DemangleError(data);
// fallthrough
- [[fallthrough]];
case Language::kDontDemangle:
- demangled_name_.clear();
- raw_name_ = AddStringToPool(data);
+ demangled_name_ = StringView();
+ raw_name_ = cu_context_->file_context->module_->AddStringToPool(data);
break;
}
break;
@@ -401,11 +462,11 @@ void DwarfCUToModule::GenericDIEHandler::ProcessAttributeString(
}
}
-string DwarfCUToModule::GenericDIEHandler::ComputeQualifiedName() {
+StringView DwarfCUToModule::GenericDIEHandler::ComputeQualifiedName() {
// Use the demangled name, if one is available. Demangled names are
// preferable to those inferred from the DWARF structure because they
// include argument types.
- const string *qualified_name = NULL;
+ StringView* qualified_name = nullptr;
if (!demangled_name_.empty()) {
// Found it is this DIE.
qualified_name = &demangled_name_;
@@ -414,37 +475,39 @@ string DwarfCUToModule::GenericDIEHandler::ComputeQualifiedName() {
qualified_name = &specification_->qualified_name;
}
- const string *unqualified_name = NULL;
- const string *enclosing_name;
+ StringView* unqualified_name = nullptr;
+ StringView* enclosing_name = nullptr;
if (!qualified_name) {
// Find the unqualified name. If the DIE has its own DW_AT_name
// attribute, then use that; otherwise, check the specification.
- if (!name_attribute_.empty())
+ if (!name_attribute_.empty()) {
unqualified_name = &name_attribute_;
- else if (specification_)
+ } else if (specification_) {
unqualified_name = &specification_->unqualified_name;
- else if (!raw_name_.empty())
+ } else if (!raw_name_.empty()) {
unqualified_name = &raw_name_;
+ }
// Find the name of the enclosing context. If this DIE has a
// specification, it's the specification's enclosing context that
// counts; otherwise, use this DIE's context.
- if (specification_)
+ if (specification_) {
enclosing_name = &specification_->enclosing_name;
- else
+ } else if (parent_context_) {
enclosing_name = &parent_context_->name;
+ }
}
// Prepare the return value before upcoming mutations possibly invalidate the
// existing pointers.
string return_value;
if (qualified_name) {
- return_value = *qualified_name;
+ return_value = qualified_name->str();
} else if (unqualified_name && enclosing_name) {
// Combine the enclosing name and unqualified name to produce our
// own fully-qualified name.
- return_value = cu_context_->language->MakeQualifiedName(*enclosing_name,
- *unqualified_name);
+ return_value = cu_context_->language->MakeQualifiedName(
+ enclosing_name->str(), unqualified_name->str());
}
// If this DIE was marked as a declaration, record its names in the
@@ -461,39 +524,224 @@ string DwarfCUToModule::GenericDIEHandler::ComputeQualifiedName() {
cu_context_->file_context->file_private_->specifications[offset_] = spec;
}
- return return_value;
+ return cu_context_->file_context->module_->AddStringToPool(return_value);
+}
+
+static bool IsEmptyRange(const vector<Module::Range>& ranges) {
+ uint64_t size = accumulate(ranges.cbegin(), ranges.cend(), 0,
+ [](uint64_t total, Module::Range entry) {
+ return total + entry.size;
+ }
+ );
+
+ return size == 0;
+}
+
+
+// A handler for DW_TAG_inlined_subroutine DIEs.
+class DwarfCUToModule::InlineHandler : public GenericDIEHandler {
+ public:
+ InlineHandler(CUContext* cu_context,
+ DIEContext* parent_context,
+ uint64_t offset,
+ int inline_nest_level,
+ vector<unique_ptr<Module::Inline>>& inlines)
+ : GenericDIEHandler(cu_context, parent_context, offset),
+ low_pc_(0),
+ high_pc_(0),
+ high_pc_form_(DW_FORM_addr),
+ ranges_form_(DW_FORM_sec_offset),
+ ranges_data_(0),
+ call_site_line_(0),
+ inline_nest_level_(inline_nest_level),
+ inlines_(inlines) {}
+
+ void ProcessAttributeUnsigned(enum DwarfAttribute attr,
+ enum DwarfForm form,
+ uint64_t data);
+ DIEHandler* FindChildHandler(uint64_t offset, enum DwarfTag tag);
+ bool EndAttributes();
+ void Finish();
+
+ private:
+ // The fully-qualified name, as derived from name_attribute_,
+ // specification_, parent_context_. Computed in EndAttributes.
+ StringView name_;
+ uint64_t low_pc_; // DW_AT_low_pc
+ uint64_t high_pc_; // DW_AT_high_pc
+ DwarfForm high_pc_form_; // DW_AT_high_pc can be length or address.
+ DwarfForm ranges_form_; // DW_FORM_sec_offset or DW_FORM_rnglistx
+ uint64_t ranges_data_; // DW_AT_ranges
+ int call_site_line_; // DW_AT_call_line
+ int call_site_file_id_; // DW_AT_call_file
+ int inline_nest_level_;
+ // A vector of inlines in the same nest level. It's owned by its parent
+ // function/inline. At Finish(), add this inline into the vector.
+ vector<unique_ptr<Module::Inline>>& inlines_;
+ // A vector of child inlines.
+ vector<unique_ptr<Module::Inline>> child_inlines_;
+};
+
+void DwarfCUToModule::InlineHandler::ProcessAttributeUnsigned(
+ enum DwarfAttribute attr,
+ enum DwarfForm form,
+ uint64_t data) {
+ switch (attr) {
+ case DW_AT_low_pc:
+ low_pc_ = data;
+ break;
+ case DW_AT_high_pc:
+ high_pc_form_ = form;
+ high_pc_ = data;
+ break;
+ case DW_AT_ranges:
+ ranges_data_ = data;
+ ranges_form_ = form;
+ break;
+ case DW_AT_call_line:
+ call_site_line_ = data;
+ break;
+ case DW_AT_call_file:
+ call_site_file_id_ = data;
+ break;
+ default:
+ GenericDIEHandler::ProcessAttributeUnsigned(attr, form, data);
+ break;
+ }
+}
+
+DIEHandler* DwarfCUToModule::InlineHandler::FindChildHandler(
+ uint64_t offset,
+ enum DwarfTag tag) {
+ switch (tag) {
+ case DW_TAG_inlined_subroutine:
+ return new InlineHandler(cu_context_, nullptr, offset,
+ inline_nest_level_ + 1, child_inlines_);
+ default:
+ return NULL;
+ }
}
+bool DwarfCUToModule::InlineHandler::EndAttributes() {
+ if (abstract_origin_)
+ name_ = abstract_origin_->name;
+ if (name_.empty()) {
+ // We haven't seen the abstract origin yet, which might appears later and we
+ // will fix the name after calling
+ // InlineOriginMap::GetOrCreateInlineOrigin with right name.
+ name_ =
+ cu_context_->file_context->module_->AddStringToPool("<name omitted>");
+ }
+ return true;
+}
+
+void DwarfCUToModule::InlineHandler::Finish() {
+ vector<Module::Range> ranges;
+
+ if (low_pc_ && high_pc_) {
+ if (high_pc_form_ != DW_FORM_addr &&
+ high_pc_form_ != DW_FORM_GNU_addr_index &&
+ high_pc_form_ != DW_FORM_addrx &&
+ high_pc_form_ != DW_FORM_addrx1 &&
+ high_pc_form_ != DW_FORM_addrx2 &&
+ high_pc_form_ != DW_FORM_addrx3 &&
+ high_pc_form_ != DW_FORM_addrx4) {
+ high_pc_ += low_pc_;
+ }
+
+ Module::Range range(low_pc_, high_pc_ - low_pc_);
+ ranges.push_back(range);
+ } else {
+ RangesHandler* ranges_handler = cu_context_->ranges_handler;
+ if (ranges_handler) {
+ RangeListReader::CURangesInfo cu_info;
+ if (cu_context_->AssembleRangeListInfo(&cu_info)) {
+ if (!ranges_handler->ReadRanges(ranges_form_, ranges_data_,
+ &cu_info, &ranges)) {
+ ranges.clear();
+ cu_context_->reporter->MalformedRangeList(ranges_data_);
+ }
+ } else {
+ cu_context_->reporter->MissingRanges();
+ }
+ }
+ }
+
+ // Ignore DW_TAG_inlined_subroutine with empty range.
+ if (ranges.empty()) {
+ return;
+ }
+
+ // Every DW_TAG_inlined_subroutine should have a DW_AT_abstract_origin.
+ assert(specification_offset_ != 0);
+
+ cu_context_->file_context->module_->inline_origin_map.SetReference(
+ specification_offset_, specification_offset_);
+ Module::InlineOrigin* origin =
+ cu_context_->file_context->module_->inline_origin_map
+ .GetOrCreateInlineOrigin(specification_offset_, name_);
+ unique_ptr<Module::Inline> in(
+ new Module::Inline(origin, ranges, call_site_line_, call_site_file_id_,
+ inline_nest_level_, std::move(child_inlines_)));
+ inlines_.push_back(std::move(in));
+}
+
+// A handler for DIEs that contain functions and contribute a
+// component to their names: namespaces, classes, etc.
+class DwarfCUToModule::NamedScopeHandler: public GenericDIEHandler {
+ public:
+ NamedScopeHandler(CUContext* cu_context,
+ DIEContext* parent_context,
+ uint64_t offset,
+ bool handle_inline)
+ : GenericDIEHandler(cu_context, parent_context, offset),
+ handle_inline_(handle_inline) {}
+ bool EndAttributes();
+ DIEHandler* FindChildHandler(uint64_t offset, enum DwarfTag tag);
+
+ private:
+ DIEContext child_context_; // A context for our children.
+ bool handle_inline_;
+};
+
// A handler class for DW_TAG_subprogram DIEs.
class DwarfCUToModule::FuncHandler: public GenericDIEHandler {
public:
- FuncHandler(CUContext *cu_context, DIEContext *parent_context,
- uint64_t offset)
+ FuncHandler(CUContext* cu_context,
+ DIEContext* parent_context,
+ uint64_t offset,
+ bool handle_inline)
: GenericDIEHandler(cu_context, parent_context, offset),
- low_pc_(0), high_pc_(0), high_pc_form_(dwarf2reader::DW_FORM_addr),
- ranges_(0), abstract_origin_(NULL), inline_(false) { }
+ low_pc_(0),
+ high_pc_(0),
+ high_pc_form_(DW_FORM_addr),
+ ranges_form_(DW_FORM_sec_offset),
+ ranges_data_(0),
+ inline_(false),
+ handle_inline_(handle_inline) {}
+
void ProcessAttributeUnsigned(enum DwarfAttribute attr,
enum DwarfForm form,
uint64_t data);
void ProcessAttributeSigned(enum DwarfAttribute attr,
enum DwarfForm form,
int64_t data);
- void ProcessAttributeReference(enum DwarfAttribute attr,
- enum DwarfForm form,
- uint64_t data);
-
+ DIEHandler* FindChildHandler(uint64_t offset, enum DwarfTag tag);
bool EndAttributes();
void Finish();
private:
// The fully-qualified name, as derived from name_attribute_,
// specification_, parent_context_. Computed in EndAttributes.
- string name_;
+ StringView name_;
uint64_t low_pc_, high_pc_; // DW_AT_low_pc, DW_AT_high_pc
DwarfForm high_pc_form_; // DW_AT_high_pc can be length or address.
- uint64_t ranges_; // DW_AT_ranges
- const AbstractOrigin* abstract_origin_;
+ DwarfForm ranges_form_; // DW_FORM_sec_offset or DW_FORM_rnglistx
+ uint64_t ranges_data_; // DW_AT_ranges
bool inline_;
+ vector<unique_ptr<Module::Inline>> child_inlines_;
+ bool handle_inline_;
+ DIEContext child_context_; // A context for our children.
};
void DwarfCUToModule::FuncHandler::ProcessAttributeUnsigned(
@@ -504,17 +752,17 @@ void DwarfCUToModule::FuncHandler::ProcessAttributeUnsigned(
// If this attribute is present at all --- even if its value is
// DW_INL_not_inlined --- then GCC may cite it as someone else's
// DW_AT_abstract_origin attribute.
- case dwarf2reader::DW_AT_inline: inline_ = true; break;
+ case DW_AT_inline: inline_ = true; break;
- case dwarf2reader::DW_AT_low_pc: low_pc_ = data; break;
- case dwarf2reader::DW_AT_high_pc:
+ case DW_AT_low_pc: low_pc_ = data; break;
+ case DW_AT_high_pc:
high_pc_form_ = form;
high_pc_ = data;
break;
- case dwarf2reader::DW_AT_ranges:
- ranges_ = data;
+ case DW_AT_ranges:
+ ranges_data_ = data;
+ ranges_form_ = form;
break;
-
default:
GenericDIEHandler::ProcessAttributeUnsigned(attr, form, data);
break;
@@ -529,34 +777,28 @@ void DwarfCUToModule::FuncHandler::ProcessAttributeSigned(
// If this attribute is present at all --- even if its value is
// DW_INL_not_inlined --- then GCC may cite it as someone else's
// DW_AT_abstract_origin attribute.
- case dwarf2reader::DW_AT_inline: inline_ = true; break;
+ case DW_AT_inline: inline_ = true; break;
default:
break;
}
}
-void DwarfCUToModule::FuncHandler::ProcessAttributeReference(
- enum DwarfAttribute attr,
- enum DwarfForm form,
- uint64_t data) {
- switch (attr) {
- case dwarf2reader::DW_AT_abstract_origin: {
- const AbstractOriginByOffset& origins =
- cu_context_->file_context->file_private_->origins;
- AbstractOriginByOffset::const_iterator origin = origins.find(data);
- if (origin != origins.end()) {
- abstract_origin_ = &(origin->second);
- } else if (data > offset_) {
- forward_ref_die_offset_ = data;
- } else {
- cu_context_->reporter->UnknownAbstractOrigin(offset_, data);
- }
- break;
- }
+DIEHandler* DwarfCUToModule::FuncHandler::FindChildHandler(
+ uint64_t offset,
+ enum DwarfTag tag) {
+ switch (tag) {
+ case DW_TAG_inlined_subroutine:
+ if (handle_inline_)
+ return new InlineHandler(cu_context_, nullptr, offset, 0,
+ child_inlines_);
+ case DW_TAG_class_type:
+ case DW_TAG_structure_type:
+ case DW_TAG_union_type:
+ return new NamedScopeHandler(cu_context_, &child_context_, offset,
+ handle_inline_);
default:
- GenericDIEHandler::ProcessAttributeReference(attr, form, data);
- break;
+ return NULL;
}
}
@@ -566,19 +808,13 @@ bool DwarfCUToModule::FuncHandler::EndAttributes() {
if (name_.empty() && abstract_origin_) {
name_ = abstract_origin_->name;
}
+ child_context_.name = name_;
+ if (name_.empty() && no_specification) {
+ cu_context_->reporter->UnknownSpecification(offset_, specification_offset_);
+ }
return true;
}
-static bool IsEmptyRange(const vector<Module::Range>& ranges) {
- uint64_t size = accumulate(ranges.cbegin(), ranges.cend(), 0,
- [](uint64_t total, Module::Range entry) {
- return total + entry.size;
- }
- );
-
- return size == 0;
-}
-
void DwarfCUToModule::FuncHandler::Finish() {
vector<Module::Range> ranges;
@@ -586,54 +822,56 @@ void DwarfCUToModule::FuncHandler::Finish() {
// to be processed, and fix up the name of the appropriate Module::Function.
// "name_" will have already been fixed up in EndAttributes().
if (!name_.empty()) {
- auto iter = cu_context_->forward_ref_die_to_func.find(offset_);
- if (iter != cu_context_->forward_ref_die_to_func.end())
+ auto iter =
+ cu_context_->file_context->file_private_->forward_ref_die_to_func.find(
+ offset_);
+ if (iter !=
+ cu_context_->file_context->file_private_->forward_ref_die_to_func.end())
iter->second->name = name_;
}
- if (!ranges_) {
+ if (!ranges_data_) {
// Make high_pc_ an address, if it isn't already.
- if (high_pc_form_ != dwarf2reader::DW_FORM_addr &&
- high_pc_form_ != dwarf2reader::DW_FORM_GNU_addr_index) {
+ if (high_pc_form_ != DW_FORM_addr &&
+ high_pc_form_ != DW_FORM_GNU_addr_index &&
+ high_pc_form_ != DW_FORM_addrx &&
+ high_pc_form_ != DW_FORM_addrx1 &&
+ high_pc_form_ != DW_FORM_addrx2 &&
+ high_pc_form_ != DW_FORM_addrx3 &&
+ high_pc_form_ != DW_FORM_addrx4) {
high_pc_ += low_pc_;
}
Module::Range range(low_pc_, high_pc_ - low_pc_);
ranges.push_back(range);
} else {
- RangesHandler *ranges_handler = cu_context_->ranges_handler;
-
+ RangesHandler* ranges_handler = cu_context_->ranges_handler;
if (ranges_handler) {
- if (!ranges_handler->ReadRanges(ranges_, cu_context_->low_pc, &ranges)) {
- ranges.clear();
- cu_context_->reporter->MalformedRangeList(ranges_);
+ RangeListReader::CURangesInfo cu_info;
+ if (cu_context_->AssembleRangeListInfo(&cu_info)) {
+ if (!ranges_handler->ReadRanges(ranges_form_, ranges_data_,
+ &cu_info, &ranges)) {
+ ranges.clear();
+ cu_context_->reporter->MalformedRangeList(ranges_data_);
+ }
+ } else {
+ cu_context_->reporter->MissingRanges();
}
- } else {
- cu_context_->reporter->MissingRanges();
}
}
+ StringView name_omitted =
+ cu_context_->file_context->module_->AddStringToPool("<name omitted>");
+ bool empty_range = IsEmptyRange(ranges);
// Did we collect the information we need? Not all DWARF function
// entries are non-empty (for example, inlined functions that were never
// used), but all the ones we're interested in cover a non-empty range of
// bytes.
- if (!IsEmptyRange(ranges)) {
+ if (!empty_range) {
low_pc_ = ranges.front().address;
-
// Malformed DWARF may omit the name, but all Module::Functions must
// have names.
- string name;
- if (!name_.empty()) {
- name = name_;
- } else {
- // If we have a forward reference to a DW_AT_specification or
- // DW_AT_abstract_origin, then don't warn, the name will be fixed up
- // later
- if (forward_ref_die_offset_ == 0)
- cu_context_->reporter->UnnamedFunction(offset_);
- name = "<name omitted>";
- }
-
+ StringView name = name_.empty() ? name_omitted : name_;
// Create a Module::Function based on the data we've gathered, and
// add it to the functions_ list.
scoped_ptr<Module::Function> func(new Module::Function(name, low_pc_));
@@ -644,52 +882,55 @@ void DwarfCUToModule::FuncHandler::Finish() {
// description is just empty debug data and should just be discarded.
cu_context_->functions.push_back(func.release());
if (forward_ref_die_offset_ != 0) {
- auto iter =
- cu_context_->forward_ref_die_to_func.find(forward_ref_die_offset_);
- if (iter == cu_context_->forward_ref_die_to_func.end()) {
- cu_context_->reporter->UnknownSpecification(offset_,
- forward_ref_die_offset_);
- } else {
- iter->second = cu_context_->functions.back();
- }
+ cu_context_->file_context->file_private_
+ ->forward_ref_die_to_func[forward_ref_die_offset_] =
+ cu_context_->functions.back();
+
+ cu_context_->spec_function_offsets[cu_context_->functions.back()] =
+ forward_ref_die_offset_;
}
+
+ cu_context_->functions.back()->inlines.swap(child_inlines_);
}
} else if (inline_) {
AbstractOrigin origin(name_);
- cu_context_->file_context->file_private_->origins[offset_] = origin;
+ cu_context_->file_context->file_private_->origins.insert({offset_, origin});
}
-}
-
-// A handler for DIEs that contain functions and contribute a
-// component to their names: namespaces, classes, etc.
-class DwarfCUToModule::NamedScopeHandler: public GenericDIEHandler {
- public:
- NamedScopeHandler(CUContext *cu_context, DIEContext *parent_context,
- uint64_t offset)
- : GenericDIEHandler(cu_context, parent_context, offset) { }
- bool EndAttributes();
- DIEHandler *FindChildHandler(uint64_t offset, enum DwarfTag tag);
- private:
- DIEContext child_context_; // A context for our children.
-};
+ // Only keep track of DW_TAG_subprogram which have the attributes we are
+ // interested.
+ if (handle_inline_ && (!empty_range || inline_)) {
+ StringView name = name_.empty() ? name_omitted : name_;
+ uint64_t offset =
+ specification_offset_ != 0 ? specification_offset_ : offset_;
+ cu_context_->file_context->module_->inline_origin_map.SetReference(offset_,
+ offset);
+ cu_context_->file_context->module_->inline_origin_map
+ .GetOrCreateInlineOrigin(offset_, name);
+ }
+}
bool DwarfCUToModule::NamedScopeHandler::EndAttributes() {
child_context_.name = ComputeQualifiedName();
+ if (child_context_.name.empty() && no_specification) {
+ cu_context_->reporter->UnknownSpecification(offset_, specification_offset_);
+ }
return true;
}
-dwarf2reader::DIEHandler *DwarfCUToModule::NamedScopeHandler::FindChildHandler(
+DIEHandler* DwarfCUToModule::NamedScopeHandler::FindChildHandler(
uint64_t offset,
enum DwarfTag tag) {
switch (tag) {
- case dwarf2reader::DW_TAG_subprogram:
- return new FuncHandler(cu_context_, &child_context_, offset);
- case dwarf2reader::DW_TAG_namespace:
- case dwarf2reader::DW_TAG_class_type:
- case dwarf2reader::DW_TAG_structure_type:
- case dwarf2reader::DW_TAG_union_type:
- return new NamedScopeHandler(cu_context_, &child_context_, offset);
+ case DW_TAG_subprogram:
+ return new FuncHandler(cu_context_, &child_context_, offset,
+ handle_inline_);
+ case DW_TAG_namespace:
+ case DW_TAG_class_type:
+ case DW_TAG_structure_type:
+ case DW_TAG_union_type:
+ return new NamedScopeHandler(cu_context_, &child_context_, offset,
+ handle_inline_);
default:
return NULL;
}
@@ -721,7 +962,7 @@ void DwarfCUToModule::WarningReporter::UnknownAbstractOrigin(uint64_t offset,
filename_.c_str(), offset, target);
}
-void DwarfCUToModule::WarningReporter::MissingSection(const string &name) {
+void DwarfCUToModule::WarningReporter::MissingSection(const string& name) {
CUHeading();
fprintf(stderr, "%s: warning: couldn't find DWARF '%s' section\n",
filename_.c_str(), name.c_str());
@@ -744,16 +985,16 @@ void DwarfCUToModule::WarningReporter::UncoveredHeading() {
}
void DwarfCUToModule::WarningReporter::UncoveredFunction(
- const Module::Function &function) {
+ const Module::Function& function) {
if (!uncovered_warnings_enabled_)
return;
UncoveredHeading();
fprintf(stderr, " function%s: %s\n",
IsEmptyRange(function.ranges) ? " (zero-length)" : "",
- function.name.c_str());
+ function.name.str().c_str());
}
-void DwarfCUToModule::WarningReporter::UncoveredLine(const Module::Line &line) {
+void DwarfCUToModule::WarningReporter::UncoveredLine(const Module::Line& line) {
if (!uncovered_warnings_enabled_)
return;
UncoveredHeading();
@@ -768,7 +1009,7 @@ void DwarfCUToModule::WarningReporter::UnnamedFunction(uint64_t offset) {
filename_.c_str(), offset);
}
-void DwarfCUToModule::WarningReporter::DemangleError(const string &input) {
+void DwarfCUToModule::WarningReporter::DemangleError(const string& input) {
CUHeading();
fprintf(stderr, "%s: warning: failed to demangle %s\n",
filename_.c_str(), input.c_str());
@@ -796,15 +1037,16 @@ void DwarfCUToModule::WarningReporter::MissingRanges() {
"the .debug_ranges section is missing.\n", filename_.c_str());
}
-DwarfCUToModule::DwarfCUToModule(FileContext *file_context,
- LineToModuleHandler *line_reader,
- RangesHandler *ranges_handler,
- WarningReporter *reporter)
- : line_reader_(line_reader),
+DwarfCUToModule::DwarfCUToModule(FileContext* file_context,
+ LineToModuleHandler* line_reader,
+ RangesHandler* ranges_handler,
+ WarningReporter* reporter,
+ bool handle_inline)
+ : RootDIEHandler(handle_inline),
+ line_reader_(line_reader),
cu_context_(new CUContext(file_context, reporter, ranges_handler)),
child_context_(new DIEContext()),
- has_source_line_info_(false) {
-}
+ has_source_line_info_(false) {}
DwarfCUToModule::~DwarfCUToModule() {
}
@@ -813,7 +1055,7 @@ void DwarfCUToModule::ProcessAttributeSigned(enum DwarfAttribute attr,
enum DwarfForm form,
int64_t data) {
switch (attr) {
- case dwarf2reader::DW_AT_language: // source language of this CU
+ case DW_AT_language: // source language of this CU
SetLanguage(static_cast<DwarfLanguage>(data));
break;
default:
@@ -825,23 +1067,33 @@ void DwarfCUToModule::ProcessAttributeUnsigned(enum DwarfAttribute attr,
enum DwarfForm form,
uint64_t data) {
switch (attr) {
- case dwarf2reader::DW_AT_stmt_list: // Line number information.
+ case DW_AT_stmt_list: // Line number information.
has_source_line_info_ = true;
source_line_offset_ = data;
break;
- case dwarf2reader::DW_AT_language: // source language of this CU
+ case DW_AT_language: // source language of this CU
SetLanguage(static_cast<DwarfLanguage>(data));
break;
- case dwarf2reader::DW_AT_low_pc:
+ case DW_AT_low_pc:
cu_context_->low_pc = data;
break;
- case dwarf2reader::DW_AT_high_pc:
+ case DW_AT_high_pc:
cu_context_->high_pc = data;
break;
- case dwarf2reader::DW_AT_ranges:
- cu_context_->ranges = data;
+ case DW_AT_ranges:
+ cu_context_->ranges_data = data;
+ cu_context_->ranges_form = form;
+ break;
+ case DW_AT_rnglists_base:
+ cu_context_->ranges_base = data;
+ break;
+ case DW_AT_addr_base:
+ case DW_AT_GNU_addr_base:
+ cu_context_->addr_base = data;
+ break;
+ case DW_AT_str_offsets_base:
+ cu_context_->str_offsets_base = data;
break;
-
default:
break;
}
@@ -849,12 +1101,12 @@ void DwarfCUToModule::ProcessAttributeUnsigned(enum DwarfAttribute attr,
void DwarfCUToModule::ProcessAttributeString(enum DwarfAttribute attr,
enum DwarfForm form,
- const string &data) {
+ const string& data) {
switch (attr) {
- case dwarf2reader::DW_AT_name:
+ case DW_AT_name:
cu_context_->reporter->SetCUName(data);
break;
- case dwarf2reader::DW_AT_comp_dir:
+ case DW_AT_comp_dir:
line_reader_->StartCompilationUnit(data);
break;
default:
@@ -866,19 +1118,20 @@ bool DwarfCUToModule::EndAttributes() {
return true;
}
-dwarf2reader::DIEHandler *DwarfCUToModule::FindChildHandler(
+DIEHandler* DwarfCUToModule::FindChildHandler(
uint64_t offset,
enum DwarfTag tag) {
switch (tag) {
- case dwarf2reader::DW_TAG_subprogram:
- return new FuncHandler(cu_context_.get(), child_context_.get(), offset);
- case dwarf2reader::DW_TAG_namespace:
- case dwarf2reader::DW_TAG_class_type:
- case dwarf2reader::DW_TAG_structure_type:
- case dwarf2reader::DW_TAG_union_type:
- case dwarf2reader::DW_TAG_module:
+ case DW_TAG_subprogram:
+ return new FuncHandler(cu_context_.get(), child_context_.get(), offset,
+ handle_inline);
+ case DW_TAG_namespace:
+ case DW_TAG_class_type:
+ case DW_TAG_structure_type:
+ case DW_TAG_union_type:
+ case DW_TAG_module:
return new NamedScopeHandler(cu_context_.get(), child_context_.get(),
- offset);
+ offset, handle_inline);
default:
return NULL;
}
@@ -886,21 +1139,21 @@ dwarf2reader::DIEHandler *DwarfCUToModule::FindChildHandler(
void DwarfCUToModule::SetLanguage(DwarfLanguage language) {
switch (language) {
- case dwarf2reader::DW_LANG_Java:
+ case DW_LANG_Java:
cu_context_->language = Language::Java;
break;
- case dwarf2reader::DW_LANG_Swift:
+ case DW_LANG_Swift:
cu_context_->language = Language::Swift;
break;
- case dwarf2reader::DW_LANG_Rust:
+ case DW_LANG_Rust:
cu_context_->language = Language::Rust;
break;
// DWARF has no generic language code for assembly language; this is
// what the GNU toolchain uses.
- case dwarf2reader::DW_LANG_Mips_Assembler:
+ case DW_LANG_Mips_Assembler:
cu_context_->language = Language::Assembler;
break;
@@ -916,67 +1169,83 @@ void DwarfCUToModule::SetLanguage(DwarfLanguage language) {
// nested in struct types, but if it ever does, then C++'s
// notation is probably not a bad choice for that.
default:
- case dwarf2reader::DW_LANG_ObjC:
- case dwarf2reader::DW_LANG_ObjC_plus_plus:
- case dwarf2reader::DW_LANG_C:
- case dwarf2reader::DW_LANG_C89:
- case dwarf2reader::DW_LANG_C99:
- case dwarf2reader::DW_LANG_C_plus_plus:
+ case DW_LANG_ObjC:
+ case DW_LANG_ObjC_plus_plus:
+ case DW_LANG_C:
+ case DW_LANG_C89:
+ case DW_LANG_C99:
+ case DW_LANG_C_plus_plus:
cu_context_->language = Language::CPlusPlus;
break;
}
}
void DwarfCUToModule::ReadSourceLines(uint64_t offset) {
- const dwarf2reader::SectionMap &section_map
+ const SectionMap& section_map
= cu_context_->file_context->section_map();
- dwarf2reader::SectionMap::const_iterator map_entry
- = section_map.find(".debug_line");
- // Mac OS X puts DWARF data in sections whose names begin with "__"
- // instead of ".".
- if (map_entry == section_map.end())
- map_entry = section_map.find("__debug_line");
+ SectionMap::const_iterator map_entry
+ = GetSectionByName(section_map, ".debug_line");
if (map_entry == section_map.end()) {
cu_context_->reporter->MissingSection(".debug_line");
return;
}
- const uint8_t *section_start = map_entry->second.first;
- uint64_t section_length = map_entry->second.second;
- if (offset >= section_length) {
+ const uint8_t* line_section_start = map_entry->second.first + offset;
+ uint64_t line_section_length = map_entry->second.second;
+ if (offset >= line_section_length) {
cu_context_->reporter->BadLineInfoOffset(offset);
return;
}
- line_reader_->ReadProgram(section_start + offset, section_length - offset,
- cu_context_->file_context->module_, &lines_);
+ line_section_length -= offset;
+ // When reading line tables, string sections are never needed for dwarf4, and
+ // may or may not be needed by dwarf5, so no error if they are missing.
+ const uint8_t* string_section_start = nullptr;
+ uint64_t string_section_length = 0;
+ map_entry = GetSectionByName(section_map, ".debug_str");
+ if (map_entry != section_map.end()) {
+ string_section_start = map_entry->second.first;
+ string_section_length = map_entry->second.second;
+ }
+ const uint8_t* line_string_section_start = nullptr;
+ uint64_t line_string_section_length = 0;
+ map_entry = GetSectionByName(section_map, ".debug_line_str");
+ if (map_entry != section_map.end()) {
+ line_string_section_start = map_entry->second.first;
+ line_string_section_length = map_entry->second.second;
+ }
+ line_reader_->ReadProgram(
+ line_section_start, line_section_length,
+ string_section_start, string_section_length,
+ line_string_section_start, line_string_section_length,
+ cu_context_->file_context->module_, &lines_, &files_);
}
namespace {
class FunctionRange {
public:
- FunctionRange(const Module::Range &range, Module::Function *function) :
+ FunctionRange(const Module::Range& range, Module::Function* function) :
address(range.address), size(range.size), function(function) { }
- void AddLine(Module::Line &line) {
+ void AddLine(Module::Line& line) {
function->lines.push_back(line);
}
Module::Address address;
Module::Address size;
- Module::Function *function;
+ Module::Function* function;
};
// Fills an array of ranges with pointers to the functions which owns
// them. The array is sorted in ascending order and the ranges are non
// empty and non-overlapping.
-static void FillSortedFunctionRanges(vector<FunctionRange> &dest_ranges,
- vector<Module::Function *> *functions) {
- for (vector<Module::Function *>::const_iterator func_it = functions->cbegin();
+static void FillSortedFunctionRanges(vector<FunctionRange>& dest_ranges,
+ vector<Module::Function*>* functions) {
+ for (vector<Module::Function*>::const_iterator func_it = functions->cbegin();
func_it != functions->cend();
func_it++)
{
- Module::Function *func = *func_it;
- vector<Module::Range> &ranges = func->ranges;
+ Module::Function* func = *func_it;
+ vector<Module::Range>& ranges = func->ranges;
for (vector<Module::Range>::const_iterator ranges_it = ranges.cbegin();
ranges_it != ranges.cend();
++ranges_it) {
@@ -988,7 +1257,7 @@ static void FillSortedFunctionRanges(vector<FunctionRange> &dest_ranges,
}
sort(dest_ranges.begin(), dest_ranges.end(),
- [](const FunctionRange &fr1, const FunctionRange &fr2) {
+ [](const FunctionRange& fr1, const FunctionRange& fr2) {
return fr1.address < fr2.address;
}
);
@@ -996,7 +1265,7 @@ static void FillSortedFunctionRanges(vector<FunctionRange> &dest_ranges,
// Return true if ADDRESS falls within the range of ITEM.
template <class T>
-inline bool within(const T &item, Module::Address address) {
+inline bool within(const T& item, Module::Address address) {
// Because Module::Address is unsigned, and unsigned arithmetic
// wraps around, this will be false if ADDRESS falls before the
// start of ITEM, or if it falls after ITEM's end.
@@ -1005,8 +1274,8 @@ inline bool within(const T &item, Module::Address address) {
}
void DwarfCUToModule::AssignLinesToFunctions() {
- vector<Module::Function *> *functions = &cu_context_->functions;
- WarningReporter *reporter = cu_context_->reporter;
+ vector<Module::Function*>* functions = &cu_context_->functions;
+ WarningReporter* reporter = cu_context_->reporter;
// This would be simpler if we assumed that source line entries
// don't cross function boundaries. However, there's no real reason
@@ -1026,12 +1295,12 @@ void DwarfCUToModule::AssignLinesToFunctions() {
// The last line that we used any piece of. We use this only for
// generating warnings.
- const Module::Line *last_line_used = NULL;
+ const Module::Line* last_line_used = NULL;
// The last function and line we warned about --- so we can avoid
// doing so more than once.
- const Module::Function *last_function_cited = NULL;
- const Module::Line *last_line_cited = NULL;
+ const Module::Function* last_function_cited = NULL;
+ const Module::Line* last_line_cited = NULL;
// Prepare a sorted list of ranges with range-to-function mapping
vector<FunctionRange> sorted_ranges;
@@ -1047,8 +1316,8 @@ void DwarfCUToModule::AssignLinesToFunctions() {
// Pointers to the referents of func_it and line_it, or NULL if the
// iterator is at the end of the sequence.
- FunctionRange *range;
- const Module::Line *line;
+ FunctionRange* range;
+ const Module::Line* line;
// Start current at the beginning of the first line or function,
// whichever is earlier.
@@ -1068,6 +1337,11 @@ void DwarfCUToModule::AssignLinesToFunctions() {
return;
}
+ // Some dwarf producers handle linker-removed functions by using -1 as a
+ // tombstone in the line table. So the end marker can be -1.
+ if (current == Module::kMaxAddress)
+ return;
+
while (range || line) {
// This loop has two invariants that hold at the top.
//
@@ -1174,7 +1448,10 @@ void DwarfCUToModule::AssignLinesToFunctions() {
// next_transition may end up being zero, in which case we've completed
// our pass. Handle that here, instead of trying to deal with it in
// each place we compute next_transition.
- if (!next_transition)
+
+ // Some dwarf producers handle linker-removed functions by using -1 as a
+ // tombstone in the line table. So the end marker can be -1.
+ if (!next_transition || next_transition == Module::kMaxAddress)
break;
// Advance iterators as needed. If lines overlap or functions overlap,
@@ -1198,6 +1475,16 @@ void DwarfCUToModule::AssignLinesToFunctions() {
}
}
+void DwarfCUToModule::AssignFilesToInlines() {
+ // Assign File* to Inlines inside this CU.
+ auto assignFile = [this](unique_ptr<Module::Inline>& in) {
+ in->call_site_file = files_[in->call_site_file_id];
+ };
+ for (auto func : cu_context_->functions) {
+ Module::Inline::InlineDFS(func->inlines, assignFile);
+ }
+}
+
void DwarfCUToModule::Finish() {
// Assembly language files have no function data, and that gives us
// no place to store our line numbers (even though the GNU toolchain
@@ -1211,15 +1498,23 @@ void DwarfCUToModule::Finish() {
if (has_source_line_info_)
ReadSourceLines(source_line_offset_);
- vector<Module::Function *> *functions = &cu_context_->functions;
+ vector<Module::Function*>* functions = &cu_context_->functions;
// Dole out lines to the appropriate functions.
AssignLinesToFunctions();
+ AssignFilesToInlines();
+
// Add our functions, which now have source lines assigned to them,
- // to module_.
- cu_context_->file_context->module_->AddFunctions(functions->begin(),
- functions->end());
+ // to module_, and remove duplicate functions.
+ for (Module::Function* func : *functions)
+ if (!cu_context_->file_context->module_->AddFunction(func)) {
+ auto iter = cu_context_->spec_function_offsets.find(func);
+ if (iter != cu_context_->spec_function_offsets.end())
+ cu_context_->file_context->file_private_->forward_ref_die_to_func.erase(
+ iter->second);
+ delete func;
+ }
// Ownership of the function objects has shifted from cu_context to
// the Module.
@@ -1233,13 +1528,15 @@ bool DwarfCUToModule::StartCompilationUnit(uint64_t offset,
uint8_t offset_size,
uint64_t cu_length,
uint8_t dwarf_version) {
+ cu_context_->version = dwarf_version;
return dwarf_version >= 2;
}
bool DwarfCUToModule::StartRootDIE(uint64_t offset, enum DwarfTag tag) {
// We don't deal with partial compilation units (the only other tag
// likely to be used for root DIE).
- return tag == dwarf2reader::DW_TAG_compile_unit;
+ return (tag == DW_TAG_compile_unit
+ || tag == DW_TAG_skeleton_unit);
}
} // namespace google_breakpad
diff --git a/src/common/dwarf_cu_to_module.h b/src/common/dwarf_cu_to_module.h
index 2153bd96..5a800104 100644
--- a/src/common/dwarf_cu_to_module.h
+++ b/src/common/dwarf_cu_to_module.h
@@ -1,7 +1,6 @@
// -*- mode: c++ -*-
-// Copyright (c) 2010 Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -13,7 +12,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -42,10 +41,10 @@
#include <stdint.h>
#include <string>
+#include <vector>
#include "common/language.h"
#include "common/module.h"
-#include "common/dwarf/bytereader.h"
#include "common/dwarf/dwarf2diehandler.h"
#include "common/dwarf/dwarf2reader.h"
#include "common/scoped_ptr.h"
@@ -53,19 +52,14 @@
namespace google_breakpad {
-using dwarf2reader::DwarfAttribute;
-using dwarf2reader::DwarfForm;
-using dwarf2reader::DwarfLanguage;
-using dwarf2reader::DwarfTag;
-
// Populate a google_breakpad::Module with DWARF debugging information.
//
// An instance of this class can be provided as a handler to a
-// dwarf2reader::DIEDispatcher, which can in turn be a handler for a
-// dwarf2reader::CompilationUnit DWARF parser. The handler uses the results
+// DIEDispatcher, which can in turn be a handler for a
+// CompilationUnit DWARF parser. The handler uses the results
// of parsing to populate a google_breakpad::Module with source file,
// function, and source line information.
-class DwarfCUToModule: public dwarf2reader::RootDIEHandler {
+class DwarfCUToModule: public RootDIEHandler {
struct FilePrivate;
public:
// Information global to the DWARF-bearing file we are processing,
@@ -79,20 +73,24 @@ class DwarfCUToModule: public dwarf2reader::RootDIEHandler {
// to true to handle debugging symbols with DW_FORM_ref_addr entries.
class FileContext {
public:
- FileContext(const string &filename,
- Module *module,
+ FileContext(const string& filename,
+ Module* module,
bool handle_inter_cu_refs);
~FileContext();
// Add CONTENTS of size LENGTH to the section map as NAME.
void AddSectionToSectionMap(const string& name,
- const uint8_t *contents,
+ const uint8_t* contents,
+ uint64_t length);
+
+ void AddManagedSectionToSectionMap(const string& name,
+ uint8_t* contents,
uint64_t length);
// Clear the section map for testing.
void ClearSectionMapForTest();
- const dwarf2reader::SectionMap& section_map() const;
+ const SectionMap& section_map() const;
private:
friend class DwarfCUToModule;
@@ -111,16 +109,17 @@ class DwarfCUToModule: public dwarf2reader::RootDIEHandler {
// A map of this file's sections, used for finding other DWARF
// sections that the .debug_info section may refer to.
- dwarf2reader::SectionMap section_map_;
+ SectionMap section_map_;
// The Module to which we're contributing definitions.
- Module *module_;
+ Module* module_;
// True if we are handling references between compilation units.
const bool handle_inter_cu_refs_;
// Inter-compilation unit data used internally by the handlers.
scoped_ptr<FilePrivate> file_private_;
+ std::vector<uint8_t *> uncompressed_sections_;
};
// An abstract base class for handlers that handle DWARF range lists for
@@ -131,17 +130,16 @@ class DwarfCUToModule: public dwarf2reader::RootDIEHandler {
virtual ~RangesHandler() { }
// Called when finishing a function to populate the function's ranges.
- // The ranges' entries are read starting from offset in the .debug_ranges
- // section, base_address holds the base PC the range list values are
- // offsets off. Return false if the rangelist falls out of the
- // .debug_ranges section.
- virtual bool ReadRanges(uint64_t offset, Module::Address base_address,
- vector<Module::Range>* ranges) = 0;
+ // The entries are read according to the form and data.
+ virtual bool ReadRanges(
+ enum DwarfForm form, uint64_t data,
+ RangeListReader::CURangesInfo* cu_info,
+ vector<Module::Range>* ranges) = 0;
};
// An abstract base class for handlers that handle DWARF line data
// for DwarfCUToModule. DwarfCUToModule could certainly just use
- // dwarf2reader::LineInfo itself directly, but decoupling things
+ // LineInfo itself directly, but decoupling things
// this way makes unit testing a little easier.
class LineToModuleHandler {
public:
@@ -158,8 +156,13 @@ class DwarfCUToModule: public dwarf2reader::RootDIEHandler {
// mappings, given a pointer to some DWARF line number data
// PROGRAM, and an overestimate of its size. Add no zero-length
// lines to LINES.
- virtual void ReadProgram(const uint8_t *program, uint64_t length,
- Module *module, vector<Module::Line> *lines) = 0;
+ virtual void ReadProgram(const uint8_t* program, uint64_t length,
+ const uint8_t* string_section,
+ uint64_t string_section_length,
+ const uint8_t* line_string_section,
+ uint64_t line_string_length,
+ Module* module, vector<Module::Line>* lines,
+ map<uint32_t, Module::File*>* files) = 0;
};
// The interface DwarfCUToModule uses to report warnings. The member
@@ -170,14 +173,14 @@ class DwarfCUToModule: public dwarf2reader::RootDIEHandler {
public:
// Warn about problems in the DWARF file FILENAME, in the
// compilation unit at OFFSET.
- WarningReporter(const string &filename, uint64_t cu_offset)
+ WarningReporter(const string& filename, uint64_t cu_offset)
: filename_(filename), cu_offset_(cu_offset), printed_cu_header_(false),
printed_unpaired_header_(false),
uncovered_warnings_enabled_(false) { }
virtual ~WarningReporter() { }
// Set the name of the compilation unit we're processing to NAME.
- virtual void SetCUName(const string &name) { cu_name_ = name; }
+ virtual void SetCUName(const string& name) { cu_name_ = name; }
// Accessor and setter for uncovered_warnings_enabled_.
// UncoveredFunction and UncoveredLine only report a problem if that is
@@ -200,17 +203,17 @@ class DwarfCUToModule: public dwarf2reader::RootDIEHandler {
virtual void UnknownAbstractOrigin(uint64_t offset, uint64_t target);
// We were unable to find the DWARF section named SECTION_NAME.
- virtual void MissingSection(const string &section_name);
+ virtual void MissingSection(const string& section_name);
// The CU's DW_AT_stmt_list offset OFFSET is bogus.
virtual void BadLineInfoOffset(uint64_t offset);
// FUNCTION includes code covered by no line number data.
- virtual void UncoveredFunction(const Module::Function &function);
+ virtual void UncoveredFunction(const Module::Function& function);
// Line number NUMBER in LINE_FILE, of length LENGTH, includes code
// covered by no function.
- virtual void UncoveredLine(const Module::Line &line);
+ virtual void UncoveredLine(const Module::Line& line);
// The DW_TAG_subprogram DIE at OFFSET has no name specified directly
// in the DIE, nor via a DW_AT_specification or DW_AT_abstract_origin
@@ -218,7 +221,7 @@ class DwarfCUToModule: public dwarf2reader::RootDIEHandler {
virtual void UnnamedFunction(uint64_t offset);
// __cxa_demangle() failed to demangle INPUT.
- virtual void DemangleError(const string &input);
+ virtual void DemangleError(const string& input);
// The DW_FORM_ref_addr at OFFSET to TARGET was not handled because
// FilePrivate did not retain the inter-CU specification data.
@@ -253,14 +256,15 @@ class DwarfCUToModule: public dwarf2reader::RootDIEHandler {
// Create a DWARF debugging info handler for a compilation unit
// within FILE_CONTEXT. This uses information received from the
- // dwarf2reader::CompilationUnit DWARF parser to populate
+ // CompilationUnit DWARF parser to populate
// FILE_CONTEXT->module. Use LINE_READER to handle the compilation
// unit's line number data. Use REPORTER to report problems with the
// data we find.
- DwarfCUToModule(FileContext *file_context,
- LineToModuleHandler *line_reader,
- RangesHandler *ranges_handler,
- WarningReporter *reporter);
+ DwarfCUToModule(FileContext* file_context,
+ LineToModuleHandler* line_reader,
+ RangesHandler* ranges_handler,
+ WarningReporter* reporter,
+ bool handle_inline = false);
~DwarfCUToModule();
void ProcessAttributeSigned(enum DwarfAttribute attr,
@@ -271,9 +275,9 @@ class DwarfCUToModule: public dwarf2reader::RootDIEHandler {
uint64_t data);
void ProcessAttributeString(enum DwarfAttribute attr,
enum DwarfForm form,
- const string &data);
+ const string& data);
bool EndAttributes();
- DIEHandler *FindChildHandler(uint64_t offset, enum DwarfTag tag);
+ DIEHandler* FindChildHandler(uint64_t offset, enum DwarfTag tag);
// Assign all our source Lines to the Functions that cover their
// addresses, and then add them to module_.
@@ -292,6 +296,7 @@ class DwarfCUToModule: public dwarf2reader::RootDIEHandler {
struct Specification;
class GenericDIEHandler;
class FuncHandler;
+ class InlineHandler;
class NamedScopeHandler;
// A map from section offsets to specifications.
@@ -312,6 +317,8 @@ class DwarfCUToModule: public dwarf2reader::RootDIEHandler {
// lines belong to which functions, beyond their addresses.)
void AssignLinesToFunctions();
+ void AssignFilesToInlines();
+
// The only reason cu_context_ and child_context_ are pointers is
// that we want to keep their definitions private to
// dwarf_cu_to_module.cc, instead of listing them all here. They are
@@ -319,7 +326,7 @@ class DwarfCUToModule: public dwarf2reader::RootDIEHandler {
// destructor deletes them.
// The handler to use to handle line number data.
- LineToModuleHandler *line_reader_;
+ LineToModuleHandler* line_reader_;
// This compilation unit's context.
scoped_ptr<CUContext> cu_context_;
@@ -338,6 +345,9 @@ class DwarfCUToModule: public dwarf2reader::RootDIEHandler {
// during parsing. Then, in Finish, we call AssignLinesToFunctions
// to dole them out to the appropriate functions.
vector<Module::Line> lines_;
+
+ // The map from file index to File* in this CU.
+ std::map<uint32_t, Module::File*> files_;
};
} // namespace google_breakpad
diff --git a/src/common/dwarf_cu_to_module_unittest.cc b/src/common/dwarf_cu_to_module_unittest.cc
index ed1d7c9b..f3fa4903 100644
--- a/src/common/dwarf_cu_to_module_unittest.cc
+++ b/src/common/dwarf_cu_to_module_unittest.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2010 Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -44,17 +43,17 @@
using std::make_pair;
using std::vector;
-using dwarf2reader::DIEHandler;
-using dwarf2reader::DwarfTag;
-using dwarf2reader::DwarfAttribute;
-using dwarf2reader::DwarfForm;
-using dwarf2reader::DwarfInline;
-using dwarf2reader::RootDIEHandler;
+using google_breakpad::DIEHandler;
+using google_breakpad::DwarfTag;
+using google_breakpad::DwarfAttribute;
+using google_breakpad::DwarfForm;
+using google_breakpad::DwarfInline;
using google_breakpad::DwarfCUToModule;
using google_breakpad::Module;
using ::testing::_;
using ::testing::AtMost;
+using ::testing::DoAll;
using ::testing::Invoke;
using ::testing::Return;
using ::testing::Test;
@@ -67,23 +66,28 @@ using ::testing::ValuesIn;
class MockLineToModuleHandler: public DwarfCUToModule::LineToModuleHandler {
public:
MOCK_METHOD1(StartCompilationUnit, void(const string& compilation_dir));
- MOCK_METHOD4(ReadProgram, void(const uint8_t *program, uint64_t length,
- Module *module, vector<Module::Line> *lines));
+ MOCK_METHOD9(ReadProgram, void(const uint8_t* program, uint64_t length,
+ const uint8_t* string_section,
+ uint64_t string_section_length,
+ const uint8_t* line_string_section,
+ uint64_t line_string_section_length,
+ Module* module, vector<Module::Line>* lines,
+ std::map<uint32_t, Module::File*>* files));
};
class MockWarningReporter: public DwarfCUToModule::WarningReporter {
public:
- MockWarningReporter(const string &filename, uint64_t cu_offset)
+ MockWarningReporter(const string& filename, uint64_t cu_offset)
: DwarfCUToModule::WarningReporter(filename, cu_offset) { }
- MOCK_METHOD1(SetCUName, void(const string &name));
+ MOCK_METHOD1(SetCUName, void(const string& name));
MOCK_METHOD2(UnknownSpecification, void(uint64_t offset, uint64_t target));
MOCK_METHOD2(UnknownAbstractOrigin, void(uint64_t offset, uint64_t target));
- MOCK_METHOD1(MissingSection, void(const string &section_name));
+ MOCK_METHOD1(MissingSection, void(const string& section_name));
MOCK_METHOD1(BadLineInfoOffset, void(uint64_t offset));
- MOCK_METHOD1(UncoveredFunction, void(const Module::Function &function));
- MOCK_METHOD1(UncoveredLine, void(const Module::Line &line));
+ MOCK_METHOD1(UncoveredFunction, void(const Module::Function& function));
+ MOCK_METHOD1(UncoveredLine, void(const Module::Line& line));
MOCK_METHOD1(UnnamedFunction, void(uint64_t offset));
- MOCK_METHOD1(DemangleError, void(const string &input));
+ MOCK_METHOD1(DemangleError, void(const string& input));
MOCK_METHOD2(UnhandledInterCUReference, void(uint64_t offset, uint64_t target));
};
@@ -112,19 +116,24 @@ class CUFixtureBase {
class AppendLinesFunctor {
public:
explicit AppendLinesFunctor(
- const vector<Module::Line> *lines) : lines_(lines) { }
- void operator()(const uint8_t *program, uint64_t length,
- Module *module, vector<Module::Line> *lines) {
+ const vector<Module::Line>* lines) : lines_(lines) { }
+ void operator()(const uint8_t* program, uint64_t length,
+ const uint8_t* string_section,
+ uint64_t string_section_length,
+ const uint8_t* line_string_section,
+ uint64_t line_string_section_length,
+ Module *module, vector<Module::Line>* lines,
+ std::map<uint32_t, Module::File*>* files) {
lines->insert(lines->end(), lines_->begin(), lines_->end());
}
private:
- const vector<Module::Line> *lines_;
+ const vector<Module::Line>* lines_;
};
CUFixtureBase()
: module_("module-name", "module-os", "module-arch", "module-id"),
file_context_("dwarf-filename", &module_, true),
- language_(dwarf2reader::DW_LANG_none),
+ language_(google_breakpad::DW_LANG_none),
language_signed_(false),
appender_(&lines_),
reporter_("dwarf-filename", 0xcf8f9bb6443d29b5LL),
@@ -147,7 +156,7 @@ class CUFixtureBase {
// By default, expect the line program reader not to be invoked. We
// may override this in StartCU.
EXPECT_CALL(line_reader_, StartCompilationUnit(_)).Times(0);
- EXPECT_CALL(line_reader_, ReadProgram(_,_,_,_)).Times(0);
+ EXPECT_CALL(line_reader_, ReadProgram(_,_,_,_,_,_,_,_,_)).Times(0);
// The handler will consult this section map to decide what to
// pass to our line reader.
@@ -161,12 +170,12 @@ class CUFixtureBase {
// when it invokes its LineToModuleHandler. Call this before calling
// StartCU.
void PushLine(Module::Address address, Module::Address size,
- const string &filename, int line_number);
+ const string& filename, int line_number);
// Use LANGUAGE for the compilation unit. More precisely, arrange
// for StartCU to pass the compilation unit's root DIE a
// DW_AT_language attribute whose value is LANGUAGE.
- void SetLanguage(dwarf2reader::DwarfLanguage language) {
+ void SetLanguage(google_breakpad::DwarfLanguage language) {
language_ = language;
}
@@ -182,61 +191,61 @@ class CUFixtureBase {
void StartCU();
// Have HANDLER process some strange attribute/form/value triples.
- void ProcessStrangeAttributes(dwarf2reader::DIEHandler *handler);
+ void ProcessStrangeAttributes(google_breakpad::DIEHandler* handler);
// Start a child DIE of PARENT with the given tag and name. Leave
// the handler ready to hear about children: call EndAttributes, but
// not Finish.
- DIEHandler *StartNamedDIE(DIEHandler *parent, DwarfTag tag,
- const string &name);
+ DIEHandler* StartNamedDIE(DIEHandler* parent, DwarfTag tag,
+ const string& name);
// Start a child DIE of PARENT with the given tag and a
// DW_AT_specification attribute whose value is SPECIFICATION. Leave
// the handler ready to hear about children: call EndAttributes, but
// not Finish. If NAME is non-zero, use it as the DW_AT_name
// attribute.
- DIEHandler *StartSpecifiedDIE(DIEHandler *parent, DwarfTag tag,
- uint64_t specification, const char *name = NULL);
+ DIEHandler* StartSpecifiedDIE(DIEHandler* parent, DwarfTag tag,
+ uint64_t specification, const char* name = NULL);
// Define a function as a child of PARENT with the given name, address, and
// size. If high_pc_form is DW_FORM_addr then the DW_AT_high_pc attribute
// will be written as an address; otherwise it will be written as the
// function's size. Call EndAttributes and Finish; one cannot define
// children of the defined function's DIE.
- void DefineFunction(DIEHandler *parent, const string &name,
+ void DefineFunction(DIEHandler* parent, const string& name,
Module::Address address, Module::Address size,
const char* mangled_name,
- DwarfForm high_pc_form = dwarf2reader::DW_FORM_addr);
+ DwarfForm high_pc_form = google_breakpad::DW_FORM_addr);
// Create a declaration DIE as a child of PARENT with the given
// offset, tag and name. If NAME is the empty string, don't provide
// a DW_AT_name attribute. Call EndAttributes and Finish.
- void DeclarationDIE(DIEHandler *parent, uint64_t offset,
- DwarfTag tag, const string &name,
- const string &mangled_name);
+ void DeclarationDIE(DIEHandler* parent, uint64_t offset,
+ DwarfTag tag, const string& name,
+ const string& mangled_name);
// Create a definition DIE as a child of PARENT with the given tag
// that refers to the declaration DIE at offset SPECIFICATION as its
// specification. If NAME is non-empty, pass it as the DW_AT_name
// attribute. If SIZE is non-zero, record ADDRESS and SIZE as
// low_pc/high_pc attributes.
- void DefinitionDIE(DIEHandler *parent, DwarfTag tag,
- uint64_t specification, const string &name,
+ void DefinitionDIE(DIEHandler* parent, DwarfTag tag,
+ uint64_t specification, const string& name,
Module::Address address = 0, Module::Address size = 0);
// Create an inline DW_TAG_subprogram DIE as a child of PARENT. If
// SPECIFICATION is non-zero, then the DIE refers to the declaration DIE at
// offset SPECIFICATION as its specification. If Name is non-empty, pass it
// as the DW_AT_name attribute.
- void AbstractInstanceDIE(DIEHandler *parent, uint64_t offset,
+ void AbstractInstanceDIE(DIEHandler* parent, uint64_t offset,
DwarfInline type, uint64_t specification,
- const string &name,
- DwarfForm form = dwarf2reader::DW_FORM_data1);
+ const string& name,
+ DwarfForm form = google_breakpad::DW_FORM_data1);
// Create a DW_TAG_subprogram DIE as a child of PARENT that refers to
// ORIGIN in its DW_AT_abstract_origin attribute. If NAME is the empty
// string, don't provide a DW_AT_name attribute.
- void DefineInlineInstanceDIE(DIEHandler *parent, const string &name,
+ void DefineInlineInstanceDIE(DIEHandler* parent, const string& name,
uint64_t origin, Module::Address address,
Module::Address size);
@@ -251,7 +260,7 @@ class CUFixtureBase {
// Test that the I'th function (ordered by address) in the module
// this.module_ has the given name, address, and size, and that its
// parameter size is zero.
- void TestFunction(int i, const string &name,
+ void TestFunction(int i, const string& name,
Module::Address address, Module::Address size);
// Test that the number of source lines owned by the I'th function
@@ -262,7 +271,7 @@ class CUFixtureBase {
// (again, by address) has the given address, size, filename, and
// line number.
void TestLine(int i, int j, Module::Address address, Module::Address size,
- const string &filename, int number);
+ const string& filename, int number);
// Actual objects under test.
Module module_;
@@ -270,7 +279,7 @@ class CUFixtureBase {
// If this is not DW_LANG_none, we'll pass it as a DW_AT_language
// attribute to the compilation unit. This defaults to DW_LANG_none.
- dwarf2reader::DwarfLanguage language_;
+ google_breakpad::DwarfLanguage language_;
// If this is true, report DW_AT_language as a signed value; if false,
// report it as an unsigned value.
@@ -300,7 +309,7 @@ class CUFixtureBase {
// If functions_filled_ is true, this is a table of functions we've
// extracted from module_, sorted by address.
- vector<Module::Function *> functions_;
+ vector<Module::Function*> functions_;
// True if we have filled the above vector with this.module_'s function list.
bool functions_filled_;
};
@@ -310,7 +319,7 @@ const size_t CUFixtureBase::dummy_line_size_ =
sizeof(CUFixtureBase::dummy_line_program_);
void CUFixtureBase::PushLine(Module::Address address, Module::Address size,
- const string &filename, int line_number) {
+ const string& filename, int line_number) {
Module::Line l;
l.address = address;
l.size = size;
@@ -332,43 +341,43 @@ void CUFixtureBase::StartCU() {
if (!lines_.empty())
EXPECT_CALL(line_reader_,
ReadProgram(&dummy_line_program_[0], dummy_line_size_,
- &module_, _))
+ _,_,_,_,
+ &module_, _,_))
.Times(AtMost(1))
.WillOnce(DoAll(Invoke(appender_), Return()));
-
ASSERT_TRUE(root_handler_
.StartCompilationUnit(0x51182ec307610b51ULL, 0x81, 0x44,
0x4241b4f33720dd5cULL, 3));
{
ASSERT_TRUE(root_handler_.StartRootDIE(0x02e56bfbda9e7337ULL,
- dwarf2reader::DW_TAG_compile_unit));
+ google_breakpad::DW_TAG_compile_unit));
}
- root_handler_.ProcessAttributeString(dwarf2reader::DW_AT_name,
- dwarf2reader::DW_FORM_strp,
+ root_handler_.ProcessAttributeString(google_breakpad::DW_AT_name,
+ google_breakpad::DW_FORM_strp,
"compilation-unit-name");
if (!compilation_dir_.empty())
- root_handler_.ProcessAttributeString(dwarf2reader::DW_AT_comp_dir,
- dwarf2reader::DW_FORM_strp,
+ root_handler_.ProcessAttributeString(google_breakpad::DW_AT_comp_dir,
+ google_breakpad::DW_FORM_strp,
compilation_dir_);
if (!lines_.empty())
- root_handler_.ProcessAttributeUnsigned(dwarf2reader::DW_AT_stmt_list,
- dwarf2reader::DW_FORM_ref4,
+ root_handler_.ProcessAttributeUnsigned(google_breakpad::DW_AT_stmt_list,
+ google_breakpad::DW_FORM_ref4,
0);
- if (language_ != dwarf2reader::DW_LANG_none) {
+ if (language_ != google_breakpad::DW_LANG_none) {
if (language_signed_)
- root_handler_.ProcessAttributeSigned(dwarf2reader::DW_AT_language,
- dwarf2reader::DW_FORM_sdata,
+ root_handler_.ProcessAttributeSigned(google_breakpad::DW_AT_language,
+ google_breakpad::DW_FORM_sdata,
language_);
else
- root_handler_.ProcessAttributeUnsigned(dwarf2reader::DW_AT_language,
- dwarf2reader::DW_FORM_udata,
+ root_handler_.ProcessAttributeUnsigned(google_breakpad::DW_AT_language,
+ google_breakpad::DW_FORM_udata,
language_);
}
ASSERT_TRUE(root_handler_.EndAttributes());
}
void CUFixtureBase::ProcessStrangeAttributes(
- dwarf2reader::DIEHandler *handler) {
+ google_breakpad::DIEHandler* handler) {
handler->ProcessAttributeUnsigned((DwarfAttribute) 0xf560dead,
(DwarfForm) 0x4106e4db,
0xa592571997facda1ULL);
@@ -387,15 +396,15 @@ void CUFixtureBase::ProcessStrangeAttributes(
"strange string");
}
-DIEHandler *CUFixtureBase::StartNamedDIE(DIEHandler *parent,
+DIEHandler* CUFixtureBase::StartNamedDIE(DIEHandler* parent,
DwarfTag tag,
- const string &name) {
- dwarf2reader::DIEHandler *handler
+ const string& name) {
+ google_breakpad::DIEHandler* handler
= parent->FindChildHandler(0x8f4c783c0467c989ULL, tag);
if (!handler)
return NULL;
- handler->ProcessAttributeString(dwarf2reader::DW_AT_name,
- dwarf2reader::DW_FORM_strp,
+ handler->ProcessAttributeString(google_breakpad::DW_AT_name,
+ google_breakpad::DW_FORM_strp,
name);
ProcessStrangeAttributes(handler);
if (!handler->EndAttributes()) {
@@ -407,20 +416,20 @@ DIEHandler *CUFixtureBase::StartNamedDIE(DIEHandler *parent,
return handler;
}
-DIEHandler *CUFixtureBase::StartSpecifiedDIE(DIEHandler *parent,
+DIEHandler* CUFixtureBase::StartSpecifiedDIE(DIEHandler* parent,
DwarfTag tag,
uint64_t specification,
- const char *name) {
- dwarf2reader::DIEHandler *handler
+ const char* name) {
+ google_breakpad::DIEHandler* handler
= parent->FindChildHandler(0x8f4c783c0467c989ULL, tag);
if (!handler)
return NULL;
if (name)
- handler->ProcessAttributeString(dwarf2reader::DW_AT_name,
- dwarf2reader::DW_FORM_strp,
+ handler->ProcessAttributeString(google_breakpad::DW_AT_name,
+ google_breakpad::DW_FORM_strp,
name);
- handler->ProcessAttributeReference(dwarf2reader::DW_AT_specification,
- dwarf2reader::DW_FORM_ref4,
+ handler->ProcessAttributeReference(google_breakpad::DW_AT_specification,
+ google_breakpad::DW_FORM_ref4,
specification);
if (!handler->EndAttributes()) {
handler->Finish();
@@ -431,33 +440,33 @@ DIEHandler *CUFixtureBase::StartSpecifiedDIE(DIEHandler *parent,
return handler;
}
-void CUFixtureBase::DefineFunction(dwarf2reader::DIEHandler *parent,
- const string &name, Module::Address address,
+void CUFixtureBase::DefineFunction(google_breakpad::DIEHandler* parent,
+ const string& name, Module::Address address,
Module::Address size,
const char* mangled_name,
DwarfForm high_pc_form) {
- dwarf2reader::DIEHandler *func
+ google_breakpad::DIEHandler* func
= parent->FindChildHandler(0xe34797c7e68590a8LL,
- dwarf2reader::DW_TAG_subprogram);
+ google_breakpad::DW_TAG_subprogram);
ASSERT_TRUE(func != NULL);
- func->ProcessAttributeString(dwarf2reader::DW_AT_name,
- dwarf2reader::DW_FORM_strp,
+ func->ProcessAttributeString(google_breakpad::DW_AT_name,
+ google_breakpad::DW_FORM_strp,
name);
- func->ProcessAttributeUnsigned(dwarf2reader::DW_AT_low_pc,
- dwarf2reader::DW_FORM_addr,
+ func->ProcessAttributeUnsigned(google_breakpad::DW_AT_low_pc,
+ google_breakpad::DW_FORM_addr,
address);
Module::Address high_pc = size;
- if (high_pc_form == dwarf2reader::DW_FORM_addr) {
+ if (high_pc_form == google_breakpad::DW_FORM_addr) {
high_pc += address;
}
- func->ProcessAttributeUnsigned(dwarf2reader::DW_AT_high_pc,
+ func->ProcessAttributeUnsigned(google_breakpad::DW_AT_high_pc,
high_pc_form,
high_pc);
if (mangled_name)
- func->ProcessAttributeString(dwarf2reader::DW_AT_MIPS_linkage_name,
- dwarf2reader::DW_FORM_strp,
+ func->ProcessAttributeString(google_breakpad::DW_AT_MIPS_linkage_name,
+ google_breakpad::DW_FORM_strp,
mangled_name);
ProcessStrangeAttributes(func);
@@ -466,51 +475,51 @@ void CUFixtureBase::DefineFunction(dwarf2reader::DIEHandler *parent,
delete func;
}
-void CUFixtureBase::DeclarationDIE(DIEHandler *parent, uint64_t offset,
+void CUFixtureBase::DeclarationDIE(DIEHandler* parent, uint64_t offset,
DwarfTag tag,
- const string &name,
- const string &mangled_name) {
- dwarf2reader::DIEHandler *die = parent->FindChildHandler(offset, tag);
+ const string& name,
+ const string& mangled_name) {
+ google_breakpad::DIEHandler* die = parent->FindChildHandler(offset, tag);
ASSERT_TRUE(die != NULL);
if (!name.empty())
- die->ProcessAttributeString(dwarf2reader::DW_AT_name,
- dwarf2reader::DW_FORM_strp,
+ die->ProcessAttributeString(google_breakpad::DW_AT_name,
+ google_breakpad::DW_FORM_strp,
name);
if (!mangled_name.empty())
- die->ProcessAttributeString(dwarf2reader::DW_AT_MIPS_linkage_name,
- dwarf2reader::DW_FORM_strp,
+ die->ProcessAttributeString(google_breakpad::DW_AT_MIPS_linkage_name,
+ google_breakpad::DW_FORM_strp,
mangled_name);
- die->ProcessAttributeUnsigned(dwarf2reader::DW_AT_declaration,
- dwarf2reader::DW_FORM_flag,
+ die->ProcessAttributeUnsigned(google_breakpad::DW_AT_declaration,
+ google_breakpad::DW_FORM_flag,
1);
EXPECT_TRUE(die->EndAttributes());
die->Finish();
delete die;
}
-void CUFixtureBase::DefinitionDIE(DIEHandler *parent,
+void CUFixtureBase::DefinitionDIE(DIEHandler* parent,
DwarfTag tag,
uint64_t specification,
- const string &name,
+ const string& name,
Module::Address address,
Module::Address size) {
- dwarf2reader::DIEHandler *die
+ google_breakpad::DIEHandler* die
= parent->FindChildHandler(0x6ccfea031a9e6cc9ULL, tag);
ASSERT_TRUE(die != NULL);
- die->ProcessAttributeReference(dwarf2reader::DW_AT_specification,
- dwarf2reader::DW_FORM_ref4,
+ die->ProcessAttributeReference(google_breakpad::DW_AT_specification,
+ google_breakpad::DW_FORM_ref4,
specification);
if (!name.empty())
- die->ProcessAttributeString(dwarf2reader::DW_AT_name,
- dwarf2reader::DW_FORM_strp,
+ die->ProcessAttributeString(google_breakpad::DW_AT_name,
+ google_breakpad::DW_FORM_strp,
name);
if (size) {
- die->ProcessAttributeUnsigned(dwarf2reader::DW_AT_low_pc,
- dwarf2reader::DW_FORM_addr,
+ die->ProcessAttributeUnsigned(google_breakpad::DW_AT_low_pc,
+ google_breakpad::DW_FORM_addr,
address);
- die->ProcessAttributeUnsigned(dwarf2reader::DW_AT_high_pc,
- dwarf2reader::DW_FORM_addr,
+ die->ProcessAttributeUnsigned(google_breakpad::DW_AT_high_pc,
+ google_breakpad::DW_FORM_addr,
address + size);
}
EXPECT_TRUE(die->EndAttributes());
@@ -518,27 +527,27 @@ void CUFixtureBase::DefinitionDIE(DIEHandler *parent,
delete die;
}
-void CUFixtureBase::AbstractInstanceDIE(DIEHandler *parent,
+void CUFixtureBase::AbstractInstanceDIE(DIEHandler* parent,
uint64_t offset,
DwarfInline type,
uint64_t specification,
- const string &name,
+ const string& name,
DwarfForm form) {
- dwarf2reader::DIEHandler *die
- = parent->FindChildHandler(offset, dwarf2reader::DW_TAG_subprogram);
+ google_breakpad::DIEHandler* die
+ = parent->FindChildHandler(offset, google_breakpad::DW_TAG_subprogram);
ASSERT_TRUE(die != NULL);
if (specification != 0ULL)
- die->ProcessAttributeReference(dwarf2reader::DW_AT_specification,
- dwarf2reader::DW_FORM_ref4,
+ die->ProcessAttributeReference(google_breakpad::DW_AT_specification,
+ google_breakpad::DW_FORM_ref4,
specification);
- if (form == dwarf2reader::DW_FORM_sdata) {
- die->ProcessAttributeSigned(dwarf2reader::DW_AT_inline, form, type);
+ if (form == google_breakpad::DW_FORM_sdata) {
+ die->ProcessAttributeSigned(google_breakpad::DW_AT_inline, form, type);
} else {
- die->ProcessAttributeUnsigned(dwarf2reader::DW_AT_inline, form, type);
+ die->ProcessAttributeUnsigned(google_breakpad::DW_AT_inline, form, type);
}
if (!name.empty())
- die->ProcessAttributeString(dwarf2reader::DW_AT_name,
- dwarf2reader::DW_FORM_strp,
+ die->ProcessAttributeString(google_breakpad::DW_AT_name,
+ google_breakpad::DW_FORM_strp,
name);
EXPECT_TRUE(die->EndAttributes());
@@ -546,28 +555,28 @@ void CUFixtureBase::AbstractInstanceDIE(DIEHandler *parent,
delete die;
}
-void CUFixtureBase::DefineInlineInstanceDIE(DIEHandler *parent,
- const string &name,
+void CUFixtureBase::DefineInlineInstanceDIE(DIEHandler* parent,
+ const string& name,
uint64_t origin,
Module::Address address,
Module::Address size) {
- dwarf2reader::DIEHandler *func
+ google_breakpad::DIEHandler* func
= parent->FindChildHandler(0x11c70f94c6e87ccdLL,
- dwarf2reader::DW_TAG_subprogram);
+ google_breakpad::DW_TAG_subprogram);
ASSERT_TRUE(func != NULL);
if (!name.empty()) {
- func->ProcessAttributeString(dwarf2reader::DW_AT_name,
- dwarf2reader::DW_FORM_strp,
+ func->ProcessAttributeString(google_breakpad::DW_AT_name,
+ google_breakpad::DW_FORM_strp,
name);
}
- func->ProcessAttributeUnsigned(dwarf2reader::DW_AT_low_pc,
- dwarf2reader::DW_FORM_addr,
+ func->ProcessAttributeUnsigned(google_breakpad::DW_AT_low_pc,
+ google_breakpad::DW_FORM_addr,
address);
- func->ProcessAttributeUnsigned(dwarf2reader::DW_AT_high_pc,
- dwarf2reader::DW_FORM_addr,
+ func->ProcessAttributeUnsigned(google_breakpad::DW_AT_high_pc,
+ google_breakpad::DW_FORM_addr,
address + size);
- func->ProcessAttributeReference(dwarf2reader::DW_AT_abstract_origin,
- dwarf2reader::DW_FORM_ref4,
+ func->ProcessAttributeReference(google_breakpad::DW_AT_abstract_origin,
+ google_breakpad::DW_FORM_ref4,
origin);
ProcessStrangeAttributes(func);
EXPECT_TRUE(func->EndAttributes());
@@ -589,13 +598,13 @@ void CUFixtureBase::TestFunctionCount(size_t expected) {
ASSERT_EQ(expected, functions_.size());
}
-void CUFixtureBase::TestFunction(int i, const string &name,
+void CUFixtureBase::TestFunction(int i, const string& name,
Module::Address address,
Module::Address size) {
FillFunctions();
ASSERT_LT((size_t) i, functions_.size());
- Module::Function *function = functions_[i];
+ Module::Function* function = functions_[i];
EXPECT_EQ(name, function->name);
EXPECT_EQ(address, function->address);
EXPECT_EQ(size, function->ranges[0].size);
@@ -611,12 +620,12 @@ void CUFixtureBase::TestLineCount(int i, size_t expected) {
void CUFixtureBase::TestLine(int i, int j,
Module::Address address, Module::Address size,
- const string &filename, int number) {
+ const string& filename, int number) {
FillFunctions();
ASSERT_LT((size_t) i, functions_.size());
ASSERT_LT((size_t) j, functions_[i]->lines.size());
- Module::Line *line = &functions_[i]->lines[j];
+ Module::Line* line = &functions_[i]->lines[j];
EXPECT_EQ(address, line->address);
EXPECT_EQ(size, line->size);
EXPECT_EQ(filename, line->file->name.c_str());
@@ -672,7 +681,7 @@ TEST_F(SimpleCU, OneFuncHighPcIsLength) {
StartCU();
DefineFunction6(&root_handler_, "function1",
0x938cf8c07def4d34ULL, 0x55592d727f6cd01fLL, NULL,
- dwarf2reader::DW_FORM_udata);
+ google_breakpad::DW_FORM_udata);
root_handler_.Finish();
TestFunctionCount(1);
@@ -698,17 +707,17 @@ TEST_F(SimpleCU, IrrelevantRootChildren) {
StartCU();
EXPECT_FALSE(root_handler_
.FindChildHandler(0x7db32bff4e2dcfb1ULL,
- dwarf2reader::DW_TAG_lexical_block));
+ google_breakpad::DW_TAG_lexical_block));
}
TEST_F(SimpleCU, IrrelevantNamedScopeChildren) {
StartCU();
- DIEHandler *class_A_handler
- = StartNamedDIE(&root_handler_, dwarf2reader::DW_TAG_class_type, "class_A");
+ DIEHandler* class_A_handler
+ = StartNamedDIE(&root_handler_, google_breakpad::DW_TAG_class_type, "class_A");
EXPECT_TRUE(class_A_handler != NULL);
EXPECT_FALSE(class_A_handler
->FindChildHandler(0x02e55999b865e4e9ULL,
- dwarf2reader::DW_TAG_lexical_block));
+ google_breakpad::DW_TAG_lexical_block));
delete class_A_handler;
}
@@ -726,7 +735,7 @@ TEST_F(SimpleCU, InlineFunction) {
StartCU();
AbstractInstanceDIE(&root_handler_, 0x1e8dac5d507ed7abULL,
- dwarf2reader::DW_INL_inlined, 0, "inline-name");
+ google_breakpad::DW_INL_inlined, 0, "inline-name");
DefineInlineInstanceDIE(&root_handler_, "", 0x1e8dac5d507ed7abULL,
0x1758a0f941b71efbULL, 0x1cf154f1f545e146ULL);
root_handler_.Finish();
@@ -741,8 +750,8 @@ TEST_F(SimpleCU, InlineFunctionSignedAttribute) {
StartCU();
AbstractInstanceDIE(&root_handler_, 0x1e8dac5d507ed7abULL,
- dwarf2reader::DW_INL_inlined, 0, "inline-name",
- dwarf2reader::DW_FORM_sdata);
+ google_breakpad::DW_INL_inlined, 0, "inline-name",
+ google_breakpad::DW_FORM_sdata);
DefineInlineInstanceDIE(&root_handler_, "", 0x1e8dac5d507ed7abULL,
0x1758a0f941b71efbULL, 0x1cf154f1f545e146ULL);
root_handler_.Finish();
@@ -760,7 +769,7 @@ TEST_F(SimpleCU, AbstractOriginNotInlined) {
StartCU();
AbstractInstanceDIE(&root_handler_, 0x93e9cdad52826b39ULL,
- dwarf2reader::DW_INL_not_inlined, 0, "abstract-instance");
+ google_breakpad::DW_INL_not_inlined, 0, "abstract-instance");
DefineInlineInstanceDIE(&root_handler_, "", 0x93e9cdad52826b39ULL,
0x2805c4531be6ca0eULL, 0x686b52155a8d4d2cULL);
root_handler_.Finish();
@@ -771,14 +780,11 @@ TEST_F(SimpleCU, AbstractOriginNotInlined) {
}
TEST_F(SimpleCU, UnknownAbstractOrigin) {
- EXPECT_CALL(reporter_, UnknownAbstractOrigin(_, 1ULL)).WillOnce(Return());
- EXPECT_CALL(reporter_, UnnamedFunction(0x11c70f94c6e87ccdLL))
- .WillOnce(Return());
PushLine(0x1758a0f941b71efbULL, 0x1cf154f1f545e146ULL, "line-file", 75173118);
StartCU();
AbstractInstanceDIE(&root_handler_, 0x1e8dac5d507ed7abULL,
- dwarf2reader::DW_INL_inlined, 0, "inline-name");
+ google_breakpad::DW_INL_inlined, 0, "inline-name");
DefineInlineInstanceDIE(&root_handler_, "", 1ULL,
0x1758a0f941b71efbULL, 0x1cf154f1f545e146ULL);
root_handler_.Finish();
@@ -789,8 +795,6 @@ TEST_F(SimpleCU, UnknownAbstractOrigin) {
}
TEST_F(SimpleCU, UnnamedFunction) {
- EXPECT_CALL(reporter_, UnnamedFunction(0xe34797c7e68590a8LL))
- .WillOnce(Return());
PushLine(0x72b80e41a0ac1d40ULL, 0x537174f231ee181cULL, "line-file", 14044850);
StartCU();
@@ -849,11 +853,11 @@ Situation situations[] = {
class FuncLinePairing: public CUFixtureBase,
public TestWithParam<Situation> { };
-INSTANTIATE_TEST_CASE_P(AllSituations, FuncLinePairing,
- ValuesIn(situations));
+INSTANTIATE_TEST_SUITE_P(AllSituations, FuncLinePairing,
+ ValuesIn(situations));
TEST_P(FuncLinePairing, Pairing) {
- const Situation &s = GetParam();
+ const Situation& s = GetParam();
PushLine(s.lines[0].start,
s.lines[0].end - s.lines[0].start,
"line-file", 67636963);
@@ -1035,21 +1039,21 @@ TEST_F(FuncLinePairing, WarnOnceLine) {
class CXXQualifiedNames: public CUFixtureBase,
public TestWithParam<DwarfTag> { };
-INSTANTIATE_TEST_CASE_P(VersusEnclosures, CXXQualifiedNames,
- Values(dwarf2reader::DW_TAG_class_type,
- dwarf2reader::DW_TAG_structure_type,
- dwarf2reader::DW_TAG_union_type,
- dwarf2reader::DW_TAG_namespace));
+INSTANTIATE_TEST_SUITE_P(VersusEnclosures, CXXQualifiedNames,
+ Values(google_breakpad::DW_TAG_class_type,
+ google_breakpad::DW_TAG_structure_type,
+ google_breakpad::DW_TAG_union_type,
+ google_breakpad::DW_TAG_namespace));
TEST_P(CXXQualifiedNames, TwoFunctions) {
DwarfTag tag = GetParam();
- SetLanguage(dwarf2reader::DW_LANG_C_plus_plus);
+ SetLanguage(google_breakpad::DW_LANG_C_plus_plus);
PushLine(10, 1, "filename1", 69819327);
PushLine(20, 1, "filename2", 95115701);
StartCU();
- DIEHandler *enclosure_handler = StartNamedDIE(&root_handler_, tag,
+ DIEHandler* enclosure_handler = StartNamedDIE(&root_handler_, tag,
"Enclosure");
EXPECT_TRUE(enclosure_handler != NULL);
DefineFunction(enclosure_handler, "func_B", 10, 1, NULL);
@@ -1066,15 +1070,15 @@ TEST_P(CXXQualifiedNames, TwoFunctions) {
TEST_P(CXXQualifiedNames, FuncInEnclosureInNamespace) {
DwarfTag tag = GetParam();
- SetLanguage(dwarf2reader::DW_LANG_C_plus_plus);
+ SetLanguage(google_breakpad::DW_LANG_C_plus_plus);
PushLine(10, 1, "line-file", 69819327);
StartCU();
- DIEHandler *namespace_handler
- = StartNamedDIE(&root_handler_, dwarf2reader::DW_TAG_namespace,
+ DIEHandler* namespace_handler
+ = StartNamedDIE(&root_handler_, google_breakpad::DW_TAG_namespace,
"Namespace");
EXPECT_TRUE(namespace_handler != NULL);
- DIEHandler *enclosure_handler = StartNamedDIE(namespace_handler, tag,
+ DIEHandler* enclosure_handler = StartNamedDIE(namespace_handler, tag,
"Enclosure");
EXPECT_TRUE(enclosure_handler != NULL);
DefineFunction(enclosure_handler, "function", 10, 1, NULL);
@@ -1089,20 +1093,20 @@ TEST_P(CXXQualifiedNames, FuncInEnclosureInNamespace) {
}
TEST_F(CXXQualifiedNames, FunctionInClassInStructInNamespace) {
- SetLanguage(dwarf2reader::DW_LANG_C_plus_plus);
+ SetLanguage(google_breakpad::DW_LANG_C_plus_plus);
PushLine(10, 1, "filename1", 69819327);
StartCU();
- DIEHandler *namespace_handler
- = StartNamedDIE(&root_handler_, dwarf2reader::DW_TAG_namespace,
+ DIEHandler* namespace_handler
+ = StartNamedDIE(&root_handler_, google_breakpad::DW_TAG_namespace,
"namespace_A");
EXPECT_TRUE(namespace_handler != NULL);
- DIEHandler *struct_handler
- = StartNamedDIE(namespace_handler, dwarf2reader::DW_TAG_structure_type,
+ DIEHandler* struct_handler
+ = StartNamedDIE(namespace_handler, google_breakpad::DW_TAG_structure_type,
"struct_B");
EXPECT_TRUE(struct_handler != NULL);
- DIEHandler *class_handler
- = StartNamedDIE(struct_handler, dwarf2reader::DW_TAG_class_type,
+ DIEHandler* class_handler
+ = StartNamedDIE(struct_handler, google_breakpad::DW_TAG_class_type,
"class_C");
DefineFunction(class_handler, "function_D", 10, 1, NULL);
class_handler->Finish();
@@ -1118,37 +1122,37 @@ TEST_F(CXXQualifiedNames, FunctionInClassInStructInNamespace) {
}
struct LanguageAndQualifiedName {
- dwarf2reader::DwarfLanguage language;
- const char *name;
+ google_breakpad::DwarfLanguage language;
+ const char* name;
};
const LanguageAndQualifiedName LanguageAndQualifiedNameCases[] = {
- { dwarf2reader::DW_LANG_none, "class_A::function_B" },
- { dwarf2reader::DW_LANG_C, "class_A::function_B" },
- { dwarf2reader::DW_LANG_C89, "class_A::function_B" },
- { dwarf2reader::DW_LANG_C99, "class_A::function_B" },
- { dwarf2reader::DW_LANG_C_plus_plus, "class_A::function_B" },
- { dwarf2reader::DW_LANG_Java, "class_A.function_B" },
- { dwarf2reader::DW_LANG_Cobol74, "class_A::function_B" },
- { dwarf2reader::DW_LANG_Mips_Assembler, NULL }
+ { google_breakpad::DW_LANG_none, "class_A::function_B" },
+ { google_breakpad::DW_LANG_C, "class_A::function_B" },
+ { google_breakpad::DW_LANG_C89, "class_A::function_B" },
+ { google_breakpad::DW_LANG_C99, "class_A::function_B" },
+ { google_breakpad::DW_LANG_C_plus_plus, "class_A::function_B" },
+ { google_breakpad::DW_LANG_Java, "class_A.function_B" },
+ { google_breakpad::DW_LANG_Cobol74, "class_A::function_B" },
+ { google_breakpad::DW_LANG_Mips_Assembler, NULL }
};
class QualifiedForLanguage
: public CUFixtureBase,
public TestWithParam<LanguageAndQualifiedName> { };
-INSTANTIATE_TEST_CASE_P(LanguageAndQualifiedName, QualifiedForLanguage,
- ValuesIn(LanguageAndQualifiedNameCases));
+INSTANTIATE_TEST_SUITE_P(LanguageAndQualifiedName, QualifiedForLanguage,
+ ValuesIn(LanguageAndQualifiedNameCases));
TEST_P(QualifiedForLanguage, MemberFunction) {
- const LanguageAndQualifiedName &param = GetParam();
+ const LanguageAndQualifiedName& param = GetParam();
PushLine(10, 1, "line-file", 212966758);
SetLanguage(param.language);
StartCU();
- DIEHandler *class_handler
- = StartNamedDIE(&root_handler_, dwarf2reader::DW_TAG_class_type,
+ DIEHandler* class_handler
+ = StartNamedDIE(&root_handler_, google_breakpad::DW_TAG_class_type,
"class_A");
DefineFunction(class_handler, "function_B", 10, 1, NULL);
class_handler->Finish();
@@ -1164,15 +1168,15 @@ TEST_P(QualifiedForLanguage, MemberFunction) {
}
TEST_P(QualifiedForLanguage, MemberFunctionSignedLanguage) {
- const LanguageAndQualifiedName &param = GetParam();
+ const LanguageAndQualifiedName& param = GetParam();
PushLine(10, 1, "line-file", 212966758);
SetLanguage(param.language);
SetLanguageSigned(true);
StartCU();
- DIEHandler *class_handler
- = StartNamedDIE(&root_handler_, dwarf2reader::DW_TAG_class_type,
+ DIEHandler* class_handler
+ = StartNamedDIE(&root_handler_, google_breakpad::DW_TAG_class_type,
"class_A");
DefineFunction(class_handler, "function_B", 10, 1, NULL);
class_handler->Finish();
@@ -1194,8 +1198,8 @@ TEST_F(Specifications, Function) {
StartCU();
DeclarationDIE(&root_handler_, 0xcd3c51b946fb1eeeLL,
- dwarf2reader::DW_TAG_subprogram, "declaration-name", "");
- DefinitionDIE(&root_handler_, dwarf2reader::DW_TAG_subprogram,
+ google_breakpad::DW_TAG_subprogram, "declaration-name", "");
+ DefinitionDIE(&root_handler_, google_breakpad::DW_TAG_subprogram,
0xcd3c51b946fb1eeeLL, "",
0x93cd3dfc1aa10097ULL, 0x0397d47a0b4ca0d4ULL);
root_handler_.Finish();
@@ -1211,9 +1215,9 @@ TEST_F(Specifications, MangledName) {
StartCU();
DeclarationDIE(&root_handler_, 0xcd3c51b946fb1eeeLL,
- dwarf2reader::DW_TAG_subprogram, "declaration-name",
+ google_breakpad::DW_TAG_subprogram, "declaration-name",
"_ZN1C1fEi");
- DefinitionDIE(&root_handler_, dwarf2reader::DW_TAG_subprogram,
+ DefinitionDIE(&root_handler_, google_breakpad::DW_TAG_subprogram,
0xcd3c51b946fb1eeeLL, "",
0x93cd3dfc1aa10097ULL, 0x0397d47a0b4ca0d4ULL);
root_handler_.Finish();
@@ -1225,14 +1229,14 @@ TEST_F(Specifications, MangledName) {
TEST_F(Specifications, MangledNameSwift) {
// Swift mangled names should pass through untouched.
- SetLanguage(dwarf2reader::DW_LANG_Swift);
+ SetLanguage(google_breakpad::DW_LANG_Swift);
PushLine(0x93cd3dfc1aa10097ULL, 0x0397d47a0b4ca0d4ULL, "line-file", 54883661);
StartCU();
const string kName = "_TFC9swifttest5Shape17simpleDescriptionfS0_FT_Si";
DeclarationDIE(&root_handler_, 0xcd3c51b946fb1eeeLL,
- dwarf2reader::DW_TAG_subprogram, "declaration-name",
+ google_breakpad::DW_TAG_subprogram, "declaration-name",
kName);
- DefinitionDIE(&root_handler_, dwarf2reader::DW_TAG_subprogram,
+ DefinitionDIE(&root_handler_, google_breakpad::DW_TAG_subprogram,
0xcd3c51b946fb1eeeLL, "",
0x93cd3dfc1aa10097ULL, 0x0397d47a0b4ca0d4ULL);
root_handler_.Finish();
@@ -1243,27 +1247,27 @@ TEST_F(Specifications, MangledNameSwift) {
}
TEST_F(Specifications, MangledNameRust) {
- SetLanguage(dwarf2reader::DW_LANG_Rust);
+ SetLanguage(google_breakpad::DW_LANG_Rust);
PushLine(0x93cd3dfc1aa10097ULL, 0x0397d47a0b4ca0d4ULL, "line-file", 54883661);
StartCU();
const string kName = "_ZN14rustc_demangle8demangle17h373defa94bffacdeE";
DeclarationDIE(&root_handler_, 0xcd3c51b946fb1eeeLL,
- dwarf2reader::DW_TAG_subprogram, "declaration-name",
+ google_breakpad::DW_TAG_subprogram, "declaration-name",
kName);
- DefinitionDIE(&root_handler_, dwarf2reader::DW_TAG_subprogram,
+ DefinitionDIE(&root_handler_, google_breakpad::DW_TAG_subprogram,
0xcd3c51b946fb1eeeLL, "",
0x93cd3dfc1aa10097ULL, 0x0397d47a0b4ca0d4ULL);
root_handler_.Finish();
TestFunctionCount(1);
TestFunction(0,
-#ifndef HAVE_RUST_DEMANGLE
+#ifndef HAVE_RUSTC_DEMANGLE
// Rust mangled names should pass through untouched if not
- // using rust-demangle.
+ // using rustc-demangle.
kName,
#else
- // If rust-demangle is available this should be properly
+ // If rustc-demangle is available this should be properly
// demangled.
"rustc_demangle::demangle",
#endif
@@ -1274,13 +1278,13 @@ TEST_F(Specifications, MemberFunction) {
PushLine(0x3341a248634e7170ULL, 0x5f6938ee5553b953ULL, "line-file", 18116691);
StartCU();
- DIEHandler *class_handler
- = StartNamedDIE(&root_handler_, dwarf2reader::DW_TAG_class_type, "class_A");
+ DIEHandler* class_handler
+ = StartNamedDIE(&root_handler_, google_breakpad::DW_TAG_class_type, "class_A");
DeclarationDIE(class_handler, 0x7d83028c431406e8ULL,
- dwarf2reader::DW_TAG_subprogram, "declaration-name", "");
+ google_breakpad::DW_TAG_subprogram, "declaration-name", "");
class_handler->Finish();
delete class_handler;
- DefinitionDIE(&root_handler_, dwarf2reader::DW_TAG_subprogram,
+ DefinitionDIE(&root_handler_, google_breakpad::DW_TAG_subprogram,
0x7d83028c431406e8ULL, "",
0x3341a248634e7170ULL, 0x5f6938ee5553b953ULL);
root_handler_.Finish();
@@ -1297,17 +1301,17 @@ TEST_F(Specifications, FunctionDeclarationParent) {
StartCU();
{
- DIEHandler *class_handler
- = StartNamedDIE(&root_handler_, dwarf2reader::DW_TAG_class_type,
+ DIEHandler* class_handler
+ = StartNamedDIE(&root_handler_, google_breakpad::DW_TAG_class_type,
"class_A");
ASSERT_TRUE(class_handler != NULL);
DeclarationDIE(class_handler, 0x0e0e877c8404544aULL,
- dwarf2reader::DW_TAG_subprogram, "declaration-name", "");
+ google_breakpad::DW_TAG_subprogram, "declaration-name", "");
class_handler->Finish();
delete class_handler;
}
- DefinitionDIE(&root_handler_, dwarf2reader::DW_TAG_subprogram,
+ DefinitionDIE(&root_handler_, google_breakpad::DW_TAG_subprogram,
0x0e0e877c8404544aULL, "definition-name",
0x463c9ddf405be227ULL, 0x6a47774af5049680ULL);
@@ -1325,20 +1329,20 @@ TEST_F(Specifications, NamedScopeDeclarationParent) {
StartCU();
{
- DIEHandler *space_handler
- = StartNamedDIE(&root_handler_, dwarf2reader::DW_TAG_namespace,
+ DIEHandler* space_handler
+ = StartNamedDIE(&root_handler_, google_breakpad::DW_TAG_namespace,
"space_A");
ASSERT_TRUE(space_handler != NULL);
DeclarationDIE(space_handler, 0x419bb1d12f9a73a2ULL,
- dwarf2reader::DW_TAG_class_type, "class-declaration-name",
+ google_breakpad::DW_TAG_class_type, "class-declaration-name",
"");
space_handler->Finish();
delete space_handler;
}
{
- DIEHandler *class_handler
- = StartSpecifiedDIE(&root_handler_, dwarf2reader::DW_TAG_class_type,
+ DIEHandler* class_handler
+ = StartSpecifiedDIE(&root_handler_, google_breakpad::DW_TAG_class_type,
0x419bb1d12f9a73a2ULL, "class-definition-name");
ASSERT_TRUE(class_handler != NULL);
DefineFunction(class_handler, "function",
@@ -1360,9 +1364,9 @@ TEST_F(Specifications, InlineFunction) {
StartCU();
DeclarationDIE(&root_handler_, 0xcd3c51b946fb1eeeLL,
- dwarf2reader::DW_TAG_subprogram, "inline-name", "");
+ google_breakpad::DW_TAG_subprogram, "inline-name", "");
AbstractInstanceDIE(&root_handler_, 0x1e8dac5d507ed7abULL,
- dwarf2reader::DW_INL_inlined, 0xcd3c51b946fb1eeeLL, "");
+ google_breakpad::DW_INL_inlined, 0xcd3c51b946fb1eeeLL, "");
DefineInlineInstanceDIE(&root_handler_, "", 0x1e8dac5d507ed7abULL,
0x1758a0f941b71efbULL, 0x1cf154f1f545e146ULL);
root_handler_.Finish();
@@ -1379,11 +1383,11 @@ TEST_F(Specifications, InlineFunctionInNamespace) {
StartCU();
DIEHandler* space_handler
- = StartNamedDIE(&root_handler_, dwarf2reader::DW_TAG_namespace,
+ = StartNamedDIE(&root_handler_, google_breakpad::DW_TAG_namespace,
"Namespace");
ASSERT_TRUE(space_handler != NULL);
AbstractInstanceDIE(space_handler, 0x1e8dac5d507ed7abULL,
- dwarf2reader::DW_INL_inlined, 0LL, "func-name");
+ google_breakpad::DW_INL_inlined, 0LL, "func-name");
DefineInlineInstanceDIE(space_handler, "", 0x1e8dac5d507ed7abULL,
0x1758a0f941b71efbULL, 0x1cf154f1f545e146ULL);
space_handler->Finish();
@@ -1400,7 +1404,7 @@ TEST_F(Specifications, InlineFunctionInNamespace) {
// - direct and definition
TEST_F(Specifications, LongChain) {
PushLine(0x5a0dd6bb85db754cULL, 0x3bccb213d08c7fd3ULL, "line-file", 21192926);
- SetLanguage(dwarf2reader::DW_LANG_C_plus_plus);
+ SetLanguage(google_breakpad::DW_LANG_C_plus_plus);
StartCU();
// The structure we're building here is:
@@ -1429,24 +1433,24 @@ TEST_F(Specifications, LongChain) {
// space_A::space_B::struct_C::struct_D::union_E::union_F::
// class_G::class_H::func_I
{
- DIEHandler *space_A_handler
- = StartNamedDIE(&root_handler_, dwarf2reader::DW_TAG_namespace,
+ DIEHandler* space_A_handler
+ = StartNamedDIE(&root_handler_, google_breakpad::DW_TAG_namespace,
"space_A");
DeclarationDIE(space_A_handler, 0x2e111126496596e2ULL,
- dwarf2reader::DW_TAG_namespace, "space_B", "");
+ google_breakpad::DW_TAG_namespace, "space_B", "");
space_A_handler->Finish();
delete space_A_handler;
}
{
- DIEHandler *space_B_handler
- = StartSpecifiedDIE(&root_handler_, dwarf2reader::DW_TAG_namespace,
+ DIEHandler* space_B_handler
+ = StartSpecifiedDIE(&root_handler_, google_breakpad::DW_TAG_namespace,
0x2e111126496596e2ULL);
- DIEHandler *struct_C_handler
- = StartNamedDIE(space_B_handler, dwarf2reader::DW_TAG_structure_type,
+ DIEHandler* struct_C_handler
+ = StartNamedDIE(space_B_handler, google_breakpad::DW_TAG_structure_type,
"struct_C");
DeclarationDIE(struct_C_handler, 0x20cd423bf2a25a4cULL,
- dwarf2reader::DW_TAG_structure_type, "struct_D", "");
+ google_breakpad::DW_TAG_structure_type, "struct_D", "");
struct_C_handler->Finish();
delete struct_C_handler;
space_B_handler->Finish();
@@ -1454,14 +1458,14 @@ TEST_F(Specifications, LongChain) {
}
{
- DIEHandler *struct_D_handler
- = StartSpecifiedDIE(&root_handler_, dwarf2reader::DW_TAG_structure_type,
+ DIEHandler* struct_D_handler
+ = StartSpecifiedDIE(&root_handler_, google_breakpad::DW_TAG_structure_type,
0x20cd423bf2a25a4cULL);
- DIEHandler *union_E_handler
- = StartNamedDIE(struct_D_handler, dwarf2reader::DW_TAG_union_type,
+ DIEHandler* union_E_handler
+ = StartNamedDIE(struct_D_handler, google_breakpad::DW_TAG_union_type,
"union_E");
DeclarationDIE(union_E_handler, 0xe25c84805aa58c32ULL,
- dwarf2reader::DW_TAG_union_type, "union_F", "");
+ google_breakpad::DW_TAG_union_type, "union_F", "");
union_E_handler->Finish();
delete union_E_handler;
struct_D_handler->Finish();
@@ -1469,14 +1473,14 @@ TEST_F(Specifications, LongChain) {
}
{
- DIEHandler *union_F_handler
- = StartSpecifiedDIE(&root_handler_, dwarf2reader::DW_TAG_union_type,
+ DIEHandler* union_F_handler
+ = StartSpecifiedDIE(&root_handler_, google_breakpad::DW_TAG_union_type,
0xe25c84805aa58c32ULL);
- DIEHandler *class_G_handler
- = StartNamedDIE(union_F_handler, dwarf2reader::DW_TAG_class_type,
+ DIEHandler* class_G_handler
+ = StartNamedDIE(union_F_handler, google_breakpad::DW_TAG_class_type,
"class_G");
DeclarationDIE(class_G_handler, 0xb70d960dcc173b6eULL,
- dwarf2reader::DW_TAG_class_type, "class_H", "");
+ google_breakpad::DW_TAG_class_type, "class_H", "");
class_G_handler->Finish();
delete class_G_handler;
union_F_handler->Finish();
@@ -1484,16 +1488,16 @@ TEST_F(Specifications, LongChain) {
}
{
- DIEHandler *class_H_handler
- = StartSpecifiedDIE(&root_handler_, dwarf2reader::DW_TAG_class_type,
+ DIEHandler* class_H_handler
+ = StartSpecifiedDIE(&root_handler_, google_breakpad::DW_TAG_class_type,
0xb70d960dcc173b6eULL);
DeclarationDIE(class_H_handler, 0x27ff829e3bf69f37ULL,
- dwarf2reader::DW_TAG_subprogram, "func_I", "");
+ google_breakpad::DW_TAG_subprogram, "func_I", "");
class_H_handler->Finish();
delete class_H_handler;
}
- DefinitionDIE(&root_handler_, dwarf2reader::DW_TAG_subprogram,
+ DefinitionDIE(&root_handler_, google_breakpad::DW_TAG_subprogram,
0x27ff829e3bf69f37ULL, "",
0x5a0dd6bb85db754cULL, 0x3bccb213d08c7fd3ULL);
root_handler_.Finish();
@@ -1509,7 +1513,7 @@ TEST_F(Specifications, InterCU) {
DwarfCUToModule::FileContext fc("dwarf-filename", &m, true);
EXPECT_CALL(reporter_, UncoveredFunction(_)).WillOnce(Return());
MockLineToModuleHandler lr;
- EXPECT_CALL(lr, ReadProgram(_,_,_,_)).Times(0);
+ EXPECT_CALL(lr, ReadProgram(_,_,_,_,_,_,_,_,_)).Times(0);
// Kludge: satisfy reporter_'s expectation.
reporter_.SetCUName("compilation-unit-name");
@@ -1519,11 +1523,11 @@ TEST_F(Specifications, InterCU) {
DwarfCUToModule root1_handler(&fc, &lr, nullptr, &reporter_);
ASSERT_TRUE(root1_handler.StartCompilationUnit(0, 1, 2, 3, 3));
ASSERT_TRUE(root1_handler.StartRootDIE(1,
- dwarf2reader::DW_TAG_compile_unit));
+ google_breakpad::DW_TAG_compile_unit));
ProcessStrangeAttributes(&root1_handler);
ASSERT_TRUE(root1_handler.EndAttributes());
DeclarationDIE(&root1_handler, 0xb8fbfdd5f0b26fceULL,
- dwarf2reader::DW_TAG_class_type, "class_A", "");
+ google_breakpad::DW_TAG_class_type, "class_A", "");
root1_handler.Finish();
}
@@ -1532,13 +1536,13 @@ TEST_F(Specifications, InterCU) {
DwarfCUToModule root2_handler(&fc, &lr, nullptr, &reporter_);
ASSERT_TRUE(root2_handler.StartCompilationUnit(0, 1, 2, 3, 3));
ASSERT_TRUE(root2_handler.StartRootDIE(1,
- dwarf2reader::DW_TAG_compile_unit));
+ google_breakpad::DW_TAG_compile_unit));
ASSERT_TRUE(root2_handler.EndAttributes());
- DIEHandler *class_A_handler
- = StartSpecifiedDIE(&root2_handler, dwarf2reader::DW_TAG_class_type,
+ DIEHandler* class_A_handler
+ = StartSpecifiedDIE(&root2_handler, google_breakpad::DW_TAG_class_type,
0xb8fbfdd5f0b26fceULL);
DeclarationDIE(class_A_handler, 0xb01fef8b380bd1a2ULL,
- dwarf2reader::DW_TAG_subprogram, "member_func_B", "");
+ google_breakpad::DW_TAG_subprogram, "member_func_B", "");
class_A_handler->Finish();
delete class_A_handler;
root2_handler.Finish();
@@ -1549,18 +1553,18 @@ TEST_F(Specifications, InterCU) {
DwarfCUToModule root3_handler(&fc, &lr, nullptr, &reporter_);
ASSERT_TRUE(root3_handler.StartCompilationUnit(0, 1, 2, 3, 3));
ASSERT_TRUE(root3_handler.StartRootDIE(1,
- dwarf2reader::DW_TAG_compile_unit));
+ google_breakpad::DW_TAG_compile_unit));
ASSERT_TRUE(root3_handler.EndAttributes());
- DefinitionDIE(&root3_handler, dwarf2reader::DW_TAG_subprogram,
+ DefinitionDIE(&root3_handler, google_breakpad::DW_TAG_subprogram,
0xb01fef8b380bd1a2ULL, "",
0x2618f00a1a711e53ULL, 0x4fd94b76d7c2caf5ULL);
root3_handler.Finish();
}
- vector<Module::Function *> functions;
+ vector<Module::Function*> functions;
m.GetFunctions(&functions, functions.end());
EXPECT_EQ(1U, functions.size());
- EXPECT_STREQ("class_A::member_func_B", functions[0]->name.c_str());
+ EXPECT_STREQ("class_A::member_func_B", functions[0]->name.str().c_str());
}
TEST_F(Specifications, UnhandledInterCU) {
@@ -1568,7 +1572,7 @@ TEST_F(Specifications, UnhandledInterCU) {
DwarfCUToModule::FileContext fc("dwarf-filename", &m, false);
EXPECT_CALL(reporter_, UncoveredFunction(_)).WillOnce(Return());
MockLineToModuleHandler lr;
- EXPECT_CALL(lr, ReadProgram(_,_,_,_)).Times(0);
+ EXPECT_CALL(lr, ReadProgram(_,_,_,_,_,_,_,_,_)).Times(0);
// Kludge: satisfy reporter_'s expectation.
reporter_.SetCUName("compilation-unit-name");
@@ -1578,11 +1582,11 @@ TEST_F(Specifications, UnhandledInterCU) {
DwarfCUToModule root1_handler(&fc, &lr, nullptr, &reporter_);
ASSERT_TRUE(root1_handler.StartCompilationUnit(0, 1, 2, 3, 3));
ASSERT_TRUE(root1_handler.StartRootDIE(1,
- dwarf2reader::DW_TAG_compile_unit));
+ google_breakpad::DW_TAG_compile_unit));
ProcessStrangeAttributes(&root1_handler);
ASSERT_TRUE(root1_handler.EndAttributes());
DeclarationDIE(&root1_handler, 0xb8fbfdd5f0b26fceULL,
- dwarf2reader::DW_TAG_class_type, "class_A", "");
+ google_breakpad::DW_TAG_class_type, "class_A", "");
root1_handler.Finish();
}
@@ -1591,14 +1595,14 @@ TEST_F(Specifications, UnhandledInterCU) {
DwarfCUToModule root2_handler(&fc, &lr, nullptr, &reporter_);
ASSERT_TRUE(root2_handler.StartCompilationUnit(0, 1, 2, 3, 3));
ASSERT_TRUE(root2_handler.StartRootDIE(1,
- dwarf2reader::DW_TAG_compile_unit));
+ google_breakpad::DW_TAG_compile_unit));
ASSERT_TRUE(root2_handler.EndAttributes());
EXPECT_CALL(reporter_, UnhandledInterCUReference(_, _)).Times(1);
- DIEHandler *class_A_handler
- = StartSpecifiedDIE(&root2_handler, dwarf2reader::DW_TAG_class_type,
+ DIEHandler* class_A_handler
+ = StartSpecifiedDIE(&root2_handler, google_breakpad::DW_TAG_class_type,
0xb8fbfdd5f0b26fceULL);
DeclarationDIE(class_A_handler, 0xb01fef8b380bd1a2ULL,
- dwarf2reader::DW_TAG_subprogram, "member_func_B", "");
+ google_breakpad::DW_TAG_subprogram, "member_func_B", "");
class_A_handler->Finish();
delete class_A_handler;
root2_handler.Finish();
@@ -1609,11 +1613,10 @@ TEST_F(Specifications, UnhandledInterCU) {
DwarfCUToModule root3_handler(&fc, &lr, nullptr, &reporter_);
ASSERT_TRUE(root3_handler.StartCompilationUnit(0, 1, 2, 3, 3));
ASSERT_TRUE(root3_handler.StartRootDIE(1,
- dwarf2reader::DW_TAG_compile_unit));
+ google_breakpad::DW_TAG_compile_unit));
ASSERT_TRUE(root3_handler.EndAttributes());
EXPECT_CALL(reporter_, UnhandledInterCUReference(_, _)).Times(1);
- EXPECT_CALL(reporter_, UnnamedFunction(_)).Times(1);
- DefinitionDIE(&root3_handler, dwarf2reader::DW_TAG_subprogram,
+ DefinitionDIE(&root3_handler, google_breakpad::DW_TAG_subprogram,
0xb01fef8b380bd1a2ULL, "",
0x2618f00a1a711e53ULL, 0x4fd94b76d7c2caf5ULL);
root3_handler.Finish();
@@ -1622,13 +1625,11 @@ TEST_F(Specifications, UnhandledInterCU) {
TEST_F(Specifications, BadOffset) {
PushLine(0xa0277efd7ce83771ULL, 0x149554a184c730c1ULL, "line-file", 56636272);
- EXPECT_CALL(reporter_, UnknownSpecification(_, 0x2be953efa6f9a996ULL))
- .WillOnce(Return());
StartCU();
DeclarationDIE(&root_handler_, 0xefd7f7752c27b7e4ULL,
- dwarf2reader::DW_TAG_subprogram, "", "");
- DefinitionDIE(&root_handler_, dwarf2reader::DW_TAG_subprogram,
+ google_breakpad::DW_TAG_subprogram, "", "");
+ DefinitionDIE(&root_handler_, google_breakpad::DW_TAG_subprogram,
0x2be953efa6f9a996ULL, "function",
0xa0277efd7ce83771ULL, 0x149554a184c730c1ULL);
root_handler_.Finish();
@@ -1639,8 +1640,8 @@ TEST_F(Specifications, FunctionDefinitionHasOwnName) {
StartCU();
DeclarationDIE(&root_handler_, 0xc34ff4786cae78bdULL,
- dwarf2reader::DW_TAG_subprogram, "declaration-name", "");
- DefinitionDIE(&root_handler_, dwarf2reader::DW_TAG_subprogram,
+ google_breakpad::DW_TAG_subprogram, "declaration-name", "");
+ DefinitionDIE(&root_handler_, google_breakpad::DW_TAG_subprogram,
0xc34ff4786cae78bdULL, "definition-name",
0xced50b3eea81022cULL, 0x08dd4d301cc7a7d2ULL);
root_handler_.Finish();
@@ -1655,19 +1656,19 @@ TEST_F(Specifications, ClassDefinitionHasOwnName) {
StartCU();
DeclarationDIE(&root_handler_, 0xd0fe467ec2f1a58cULL,
- dwarf2reader::DW_TAG_class_type, "class-declaration-name", "");
+ google_breakpad::DW_TAG_class_type, "class-declaration-name", "");
- dwarf2reader::DIEHandler *class_definition
- = StartSpecifiedDIE(&root_handler_, dwarf2reader::DW_TAG_class_type,
+ google_breakpad::DIEHandler* class_definition
+ = StartSpecifiedDIE(&root_handler_, google_breakpad::DW_TAG_class_type,
0xd0fe467ec2f1a58cULL, "class-definition-name");
ASSERT_TRUE(class_definition);
DeclarationDIE(class_definition, 0x6d028229c15623dbULL,
- dwarf2reader::DW_TAG_subprogram,
+ google_breakpad::DW_TAG_subprogram,
"function-declaration-name", "");
class_definition->Finish();
delete class_definition;
- DefinitionDIE(&root_handler_, dwarf2reader::DW_TAG_subprogram,
+ DefinitionDIE(&root_handler_, google_breakpad::DW_TAG_subprogram,
0x6d028229c15623dbULL, "function-definition-name",
0x1d0f5e0f6ce309bdULL, 0x654e1852ec3599e7ULL);
@@ -1688,20 +1689,20 @@ TEST_F(Specifications, PreferSpecificationParents) {
StartCU();
{
- dwarf2reader::DIEHandler *declaration_class_handler =
- StartNamedDIE(&root_handler_, dwarf2reader::DW_TAG_class_type,
+ google_breakpad::DIEHandler* declaration_class_handler =
+ StartNamedDIE(&root_handler_, google_breakpad::DW_TAG_class_type,
"declaration-class");
DeclarationDIE(declaration_class_handler, 0x9ddb35517455ef7aULL,
- dwarf2reader::DW_TAG_subprogram, "function-declaration",
+ google_breakpad::DW_TAG_subprogram, "function-declaration",
"");
declaration_class_handler->Finish();
delete declaration_class_handler;
}
{
- dwarf2reader::DIEHandler *definition_class_handler
- = StartNamedDIE(&root_handler_, dwarf2reader::DW_TAG_class_type,
+ google_breakpad::DIEHandler* definition_class_handler
+ = StartNamedDIE(&root_handler_, google_breakpad::DW_TAG_class_type,
"definition-class");
- DefinitionDIE(definition_class_handler, dwarf2reader::DW_TAG_subprogram,
+ DefinitionDIE(definition_class_handler, google_breakpad::DW_TAG_subprogram,
0x9ddb35517455ef7aULL, "function-definition",
0xbbd9d54dce3b95b7ULL, 0x39188b7b52b0899fULL);
definition_class_handler->Finish();
@@ -1723,12 +1724,12 @@ TEST_F(CUErrors, BadStmtList) {
.StartCompilationUnit(0xc591d5b037543d7cULL, 0x11, 0xcd,
0x2d7d19546cf6590cULL, 3));
ASSERT_TRUE(root_handler_.StartRootDIE(0xae789dc102cfca54ULL,
- dwarf2reader::DW_TAG_compile_unit));
- root_handler_.ProcessAttributeString(dwarf2reader::DW_AT_name,
- dwarf2reader::DW_FORM_strp,
+ google_breakpad::DW_TAG_compile_unit));
+ root_handler_.ProcessAttributeString(google_breakpad::DW_AT_name,
+ google_breakpad::DW_FORM_strp,
"compilation-unit-name");
- root_handler_.ProcessAttributeUnsigned(dwarf2reader::DW_AT_stmt_list,
- dwarf2reader::DW_FORM_ref4,
+ root_handler_.ProcessAttributeUnsigned(google_breakpad::DW_AT_stmt_list,
+ google_breakpad::DW_FORM_ref4,
dummy_line_size_ + 10);
root_handler_.EndAttributes();
root_handler_.Finish();
@@ -1780,7 +1781,7 @@ TEST_F(CUErrors, BadCURootDIETag) {
0xc9de224ccb99ac3eULL, 3));
ASSERT_FALSE(root_handler_.StartRootDIE(0x02e56bfbda9e7337ULL,
- dwarf2reader::DW_TAG_subprogram));
+ google_breakpad::DW_TAG_subprogram));
}
// Tests for DwarfCUToModule::Reporter. These just produce (or fail to
diff --git a/src/common/dwarf_line_to_module.cc b/src/common/dwarf_line_to_module.cc
index 443d7448..e716d483 100644
--- a/src/common/dwarf_line_to_module.cc
+++ b/src/common/dwarf_line_to_module.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2010 Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -44,18 +43,18 @@
// it until we actually have to deal with DWARF on Windows.
// Return true if PATH is an absolute path, false if it is relative.
-static bool PathIsAbsolute(const string &path) {
+static bool PathIsAbsolute(const string& path) {
return (path.size() >= 1 && path[0] == '/');
}
-static bool HasTrailingSlash(const string &path) {
+static bool HasTrailingSlash(const string& path) {
return (path.size() >= 1 && path[path.size() - 1] == '/');
}
// If PATH is an absolute path, return PATH. If PATH is a relative path,
// treat it as relative to BASE and return the combined path.
-static string ExpandPath(const string &path,
- const string &base) {
+static string ExpandPath(const string& path,
+ const string& base) {
if (PathIsAbsolute(path) || base.empty())
return path;
return base + (HasTrailingSlash(base) ? "" : "/") + path;
@@ -63,14 +62,14 @@ static string ExpandPath(const string &path,
namespace google_breakpad {
-void DwarfLineToModule::DefineDir(const string &name, uint32_t dir_num) {
+void DwarfLineToModule::DefineDir(const string& name, uint32_t dir_num) {
// Directory number zero is reserved to mean the compilation
// directory. Silently ignore attempts to redefine it.
if (dir_num != 0)
directories_[dir_num] = ExpandPath(name, compilation_dir_);
}
-void DwarfLineToModule::DefineFile(const string &name, int32_t file_num,
+void DwarfLineToModule::DefineFile(const string& name, int32_t file_num,
uint32_t dir_num, uint64_t mod_time,
uint64_t length) {
if (file_num == -1)
@@ -100,7 +99,7 @@ void DwarfLineToModule::DefineFile(const string &name, int32_t file_num,
// Find a Module::File object of the given name, and add it to the
// file table.
- files_[file_num] = module_->FindFile(full_name);
+ (*files_)[file_num] = module_->FindFile(full_name);
}
void DwarfLineToModule::AddLine(uint64_t address, uint64_t length,
@@ -122,7 +121,7 @@ void DwarfLineToModule::AddLine(uint64_t address, uint64_t length,
}
// Find the source file being referred to.
- Module::File *file = files_[file_num];
+ Module::File *file = (*files_)[file_num];
if (!file) {
if (!warned_bad_file_number_) {
fprintf(stderr, "warning: DWARF line number data refers to "
diff --git a/src/common/dwarf_line_to_module.h b/src/common/dwarf_line_to_module.h
index f54ccaf5..c93a9bf5 100644
--- a/src/common/dwarf_line_to_module.h
+++ b/src/common/dwarf_line_to_module.h
@@ -1,7 +1,6 @@
// -*- mode: c++ -*-
-// Copyright (c) 2010 Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -13,7 +12,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -50,7 +49,7 @@ namespace google_breakpad {
// instances from parsed DWARF line number data.
//
// An instance of this class can be provided as a handler to a
-// dwarf2reader::LineInfo DWARF line number information parser. The
+// LineInfo DWARF line number information parser. The
// handler accepts source location information from the parser and
// uses it to produce a vector of google_breakpad::Module::Line
// objects, referring to google_breakpad::Module::File objects added
@@ -111,7 +110,7 @@ namespace google_breakpad {
// at address zero.)
//
// - If a line starts immediately after an omitted line, omit it too.
-class DwarfLineToModule: public dwarf2reader::LineInfoHandler {
+class DwarfLineToModule: public LineInfoHandler {
public:
// As the DWARF line info parser passes us line records, add source
// files to MODULE, and add all lines to the end of LINES. LINES
@@ -120,20 +119,23 @@ class DwarfLineToModule: public dwarf2reader::LineInfoHandler {
// end of the address space, we clip it. It's up to our client to
// sort out which lines belong to which functions; we don't add them
// to any particular function in MODULE ourselves.
- DwarfLineToModule(Module *module, const string& compilation_dir,
- vector<Module::Line> *lines)
+ DwarfLineToModule(Module* module,
+ const string& compilation_dir,
+ vector<Module::Line>* lines,
+ std::map<uint32_t, Module::File*>* files)
: module_(module),
compilation_dir_(compilation_dir),
lines_(lines),
+ files_(files),
highest_file_number_(-1),
omitted_line_end_(0),
warned_bad_file_number_(false),
warned_bad_directory_number_(false) { }
-
+
~DwarfLineToModule() { }
- void DefineDir(const string &name, uint32_t dir_num);
- void DefineFile(const string &name, int32_t file_num,
+ void DefineDir(const string& name, uint32_t dir_num);
+ void DefineFile(const string& name, int32_t file_num,
uint32_t dir_num, uint64_t mod_time,
uint64_t length);
void AddLine(uint64_t address, uint64_t length,
@@ -142,7 +144,7 @@ class DwarfLineToModule: public dwarf2reader::LineInfoHandler {
private:
typedef std::map<uint32_t, string> DirectoryTable;
- typedef std::map<uint32_t, Module::File *> FileTable;
+ typedef std::map<uint32_t, Module::File*> FileTable;
// The module we're contributing debugging info to. Owned by our
// client.
@@ -161,18 +163,18 @@ class DwarfLineToModule: public dwarf2reader::LineInfoHandler {
// to the appropriate function from module_ until we've read the
// function info as well. Instead, we accumulate lines here, and let
// whoever constructed this sort it all out.
- vector<Module::Line> *lines_;
+ vector<Module::Line>* lines_;
// A table mapping directory numbers to paths.
DirectoryTable directories_;
// A table mapping file numbers to Module::File pointers.
- FileTable files_;
+ FileTable* files_;
// The highest file number we've seen so far, or -1 if we've seen
// none. Used for dynamically defined file numbers.
int32_t highest_file_number_;
-
+
// This is the ending address of the last line we omitted, or zero if we
// didn't omit the previous line. It is zero before we have received any
// AddLine calls.
diff --git a/src/common/dwarf_line_to_module_unittest.cc b/src/common/dwarf_line_to_module_unittest.cc
index 7c0fcfd3..c4a02dfa 100644
--- a/src/common/dwarf_line_to_module_unittest.cc
+++ b/src/common/dwarf_line_to_module_unittest.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2010 Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -45,13 +44,14 @@ using google_breakpad::Module;
TEST(SimpleModule, One) {
Module m("name", "os", "architecture", "id");
vector<Module::Line> lines;
- DwarfLineToModule h(&m, "/", &lines);
+ std::map<uint32_t, Module::File*> cu_files;
+ DwarfLineToModule h(&m, "/", &lines, &cu_files);
h.DefineFile("file1", 0x30bf0f27, 0, 0, 0);
h.AddLine(0x6fd126fbf74f2680LL, 0x63c9a14cf556712bLL, 0x30bf0f27,
0x4c090cbf, 0x1cf9fe0d);
- vector<Module::File *> files;
+ vector<Module::File*> files;
m.GetFiles(&files);
EXPECT_EQ(1U, files.size());
EXPECT_STREQ("/file1", files[0]->name.c_str());
@@ -66,7 +66,8 @@ TEST(SimpleModule, One) {
TEST(SimpleModule, Many) {
Module m("name", "os", "architecture", "id");
vector<Module::Line> lines;
- DwarfLineToModule h(&m, "/", &lines);
+ std::map<uint32_t, Module::File*> cu_files;
+ DwarfLineToModule h(&m, "/", &lines, &cu_files);
h.DefineDir("directory1", 0x838299ab);
h.DefineDir("directory2", 0xf85de023);
@@ -86,7 +87,7 @@ TEST(SimpleModule, Many) {
h.AddLine(0xe2d72a37f8d9403aULL, 0x034dfab5b0d4d236ULL, 0x63beb4a5,
0x75047044U, 0xb6a0016cU);
- vector<Module::File *> files;
+ vector<Module::File*> files;
m.GetFiles(&files);
ASSERT_EQ(5U, files.size());
EXPECT_STREQ("/directory1/file1", files[0]->name.c_str());
@@ -126,14 +127,15 @@ TEST(SimpleModule, Many) {
TEST(Filenames, Absolute) {
Module m("name", "os", "architecture", "id");
vector<Module::Line> lines;
- DwarfLineToModule h(&m, "/", &lines);
+ std::map<uint32_t, Module::File*> cu_files;
+ DwarfLineToModule h(&m, "/", &lines, &cu_files);
h.DefineDir("directory1", 1);
h.DefineFile("/absolute", 1, 1, 0, 0);
h.AddLine(1, 1, 1, 0, 0);
- vector<Module::File *> files;
+ vector<Module::File*> files;
m.GetFiles(&files);
ASSERT_EQ(1U, files.size());
EXPECT_STREQ("/absolute", files[0]->name.c_str());
@@ -144,14 +146,15 @@ TEST(Filenames, Absolute) {
TEST(Filenames, Relative) {
Module m("name", "os", "architecture", "id");
vector<Module::Line> lines;
- DwarfLineToModule h(&m, "/", &lines);
+ std::map<uint32_t, Module::File*> cu_files;
+ DwarfLineToModule h(&m, "/", &lines, &cu_files);
h.DefineDir("directory1", 1);
h.DefineFile("relative", 1, 1, 0, 0);
h.AddLine(1, 1, 1, 0, 0);
- vector<Module::File *> files;
+ vector<Module::File*> files;
m.GetFiles(&files);
ASSERT_EQ(1U, files.size());
EXPECT_STREQ("/directory1/relative", files[0]->name.c_str());
@@ -162,7 +165,8 @@ TEST(Filenames, Relative) {
TEST(Filenames, StrangeFile) {
Module m("name", "os", "architecture", "id");
vector<Module::Line> lines;
- DwarfLineToModule h(&m, "/", &lines);
+ std::map<uint32_t, Module::File*> cu_files;
+ DwarfLineToModule h(&m, "/", &lines, &cu_files);
h.DefineDir("directory1", 1);
h.DefineFile("", 1, 1, 0, 0);
@@ -175,7 +179,8 @@ TEST(Filenames, StrangeFile) {
TEST(Filenames, StrangeDirectory) {
Module m("name", "os", "architecture", "id");
vector<Module::Line> lines;
- DwarfLineToModule h(&m, "/", &lines);
+ std::map<uint32_t, Module::File*> cu_files;
+ DwarfLineToModule h(&m, "/", &lines, &cu_files);
h.DefineDir("", 1);
h.DefineFile("file1", 1, 1, 0, 0);
@@ -188,7 +193,8 @@ TEST(Filenames, StrangeDirectory) {
TEST(Filenames, StrangeDirectoryAndFile) {
Module m("name", "os", "architecture", "id");
vector<Module::Line> lines;
- DwarfLineToModule h(&m, "/", &lines);
+ std::map<uint32_t, Module::File*> cu_files;
+ DwarfLineToModule h(&m, "/", &lines, &cu_files);
h.DefineDir("", 1);
h.DefineFile("", 1, 1, 0, 0);
@@ -203,7 +209,8 @@ TEST(Filenames, StrangeDirectoryAndFile) {
TEST(Filenames, DirectoryZeroFileIsRelativeToCompilationDir) {
Module m("name", "os", "architecture", "id");
vector<Module::Line> lines;
- DwarfLineToModule h(&m, "src/build", &lines);
+ std::map<uint32_t, Module::File*> cu_files;
+ DwarfLineToModule h(&m, "src/build", &lines, &cu_files);
h.DefineDir("Dir", 1);
h.DefineFile("File", 1, 0, 0, 0);
@@ -219,7 +226,8 @@ TEST(Filenames, DirectoryZeroFileIsRelativeToCompilationDir) {
TEST(Filenames, IncludeDirectoryRelativeToDirectoryZero) {
Module m("name", "os", "architecture", "id");
vector<Module::Line> lines;
- DwarfLineToModule h(&m, "src/build", &lines);
+ std::map<uint32_t, Module::File*> cu_files;
+ DwarfLineToModule h(&m, "src/build", &lines, &cu_files);
h.DefineDir("Dir", 1);
h.DefineFile("File", 1, 1, 0, 0);
@@ -235,7 +243,8 @@ TEST(Filenames, IncludeDirectoryRelativeToDirectoryZero) {
TEST(Filenames, IncludeDirectoryAbsolute) {
Module m("name", "os", "architecture", "id");
vector<Module::Line> lines;
- DwarfLineToModule h(&m, "src/build", &lines);
+ std::map<uint32_t, Module::File*> cu_files;
+ DwarfLineToModule h(&m, "src/build", &lines, &cu_files);
h.DefineDir("/Dir", 1);
h.DefineFile("File", 1, 1, 0, 0);
@@ -251,7 +260,8 @@ TEST(Filenames, IncludeDirectoryAbsolute) {
TEST(ModuleErrors, DirectoryZero) {
Module m("name", "os", "architecture", "id");
vector<Module::Line> lines;
- DwarfLineToModule h(&m, "/", &lines);
+ std::map<uint32_t, Module::File*> cu_files;
+ DwarfLineToModule h(&m, "/", &lines, &cu_files);
h.DefineDir("directory0", 0); // should be ignored
h.DefineFile("relative", 1, 0, 0, 0);
@@ -267,7 +277,8 @@ TEST(ModuleErrors, DirectoryZero) {
TEST(ModuleErrors, BadFileNumber) {
Module m("name", "os", "architecture", "id");
vector<Module::Line> lines;
- DwarfLineToModule h(&m, "/", &lines);
+ std::map<uint32_t, Module::File*> cu_files;
+ DwarfLineToModule h(&m, "/", &lines, &cu_files);
h.DefineFile("relative", 1, 0, 0, 0);
h.AddLine(1, 1, 2, 0, 0); // bad file number
@@ -281,7 +292,8 @@ TEST(ModuleErrors, BadFileNumber) {
TEST(ModuleErrors, BadDirectoryNumber) {
Module m("name", "os", "architecture", "id");
vector<Module::Line> lines;
- DwarfLineToModule h(&m, "/", &lines);
+ std::map<uint32_t, Module::File*> cu_files;
+ DwarfLineToModule h(&m, "/", &lines, &cu_files);
h.DefineDir("directory1", 1);
h.DefineFile("baddirnumber1", 1, 2, 0, 0); // bad directory number
@@ -296,7 +308,8 @@ TEST(ModuleErrors, BadDirectoryNumber) {
TEST(ModuleErrors, EmptyLine) {
Module m("name", "os", "architecture", "id");
vector<Module::Line> lines;
- DwarfLineToModule h(&m, "/", &lines);
+ std::map<uint32_t, Module::File*> cu_files;
+ DwarfLineToModule h(&m, "/", &lines, &cu_files);
h.DefineFile("filename1", 1, 0, 0, 0);
h.AddLine(1, 0, 1, 0, 0);
@@ -309,7 +322,8 @@ TEST(ModuleErrors, EmptyLine) {
TEST(ModuleErrors, BigLine) {
Module m("name", "os", "architecture", "id");
vector<Module::Line> lines;
- DwarfLineToModule h(&m, "/", &lines);
+ std::map<uint32_t, Module::File*> cu_files;
+ DwarfLineToModule h(&m, "/", &lines, &cu_files);
h.DefineFile("filename1", 1, 0, 0, 0);
h.AddLine(0xffffffffffffffffULL, 2, 1, 0, 0);
@@ -326,7 +340,8 @@ TEST(ModuleErrors, BigLine) {
TEST(Omitted, DroppedThenGood) {
Module m("name", "os", "architecture", "id");
vector<Module::Line> lines;
- DwarfLineToModule h(&m, "/", &lines);
+ std::map<uint32_t, Module::File*> cu_files;
+ DwarfLineToModule h(&m, "/", &lines, &cu_files);
h.DefineFile("filename1", 1, 0, 0, 0);
h.AddLine(0, 10, 1, 83816211, 0); // should be omitted
@@ -339,7 +354,8 @@ TEST(Omitted, DroppedThenGood) {
TEST(Omitted, GoodThenDropped) {
Module m("name", "os", "architecture", "id");
vector<Module::Line> lines;
- DwarfLineToModule h(&m, "/", &lines);
+ std::map<uint32_t, Module::File*> cu_files;
+ DwarfLineToModule h(&m, "/", &lines, &cu_files);
h.DefineFile("filename1", 1, 0, 0, 0);
h.AddLine(0x9dd6a372, 10, 1, 41454594, 0); // should be recorded
@@ -352,7 +368,8 @@ TEST(Omitted, GoodThenDropped) {
TEST(Omitted, Mix1) {
Module m("name", "os", "architecture", "id");
vector<Module::Line> lines;
- DwarfLineToModule h(&m, "/", &lines);
+ std::map<uint32_t, Module::File*> cu_files;
+ DwarfLineToModule h(&m, "/", &lines, &cu_files);
h.DefineFile("filename1", 1, 0, 0, 0);
h.AddLine(0x679ed72f, 10, 1, 58932642, 0); // should be recorded
@@ -373,7 +390,8 @@ TEST(Omitted, Mix1) {
TEST(Omitted, Mix2) {
Module m("name", "os", "architecture", "id");
vector<Module::Line> lines;
- DwarfLineToModule h(&m, "/", &lines);
+ std::map<uint32_t, Module::File*> cu_files;
+ DwarfLineToModule h(&m, "/", &lines, &cu_files);
h.DefineFile("filename1", 1, 0, 0, 0);
h.AddLine(0, 0xf2, 1, 58802211, 0); // should be omitted
diff --git a/src/common/dwarf_range_list_handler.cc b/src/common/dwarf_range_list_handler.cc
index cc9e39ce..4d3dbd2e 100644
--- a/src/common/dwarf_range_list_handler.cc
+++ b/src/common/dwarf_range_list_handler.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2018 Google Inc.
-// All rights reserved.
+// Copyright 2018 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -40,18 +39,14 @@
namespace google_breakpad {
void DwarfRangeListHandler::AddRange(uint64_t begin, uint64_t end) {
- Module::Range r(begin + base_address_, end - begin);
+ Module::Range r(begin, end - begin);
ranges_->push_back(r);
}
-void DwarfRangeListHandler::SetBaseAddress(uint64_t base_address) {
- base_address_ = base_address;
-}
-
void DwarfRangeListHandler::Finish() {
std::sort(ranges_->begin(), ranges_->end(),
- [](const Module::Range &a, const Module::Range &b) {
+ [](const Module::Range& a, const Module::Range& b) {
return a.address < b.address;
}
);
diff --git a/src/common/dwarf_range_list_handler.h b/src/common/dwarf_range_list_handler.h
index 83a34694..cb1b8b1e 100644
--- a/src/common/dwarf_range_list_handler.h
+++ b/src/common/dwarf_range_list_handler.h
@@ -1,7 +1,6 @@
// -*- mode: c++ -*-
-// Copyright (c) 2018 Google Inc.
-// All rights reserved.
+// Copyright 2018 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -13,7 +12,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -49,29 +48,22 @@ namespace google_breakpad {
// A class for producing a vector of google_breakpad::Module::Range
// instances from a parsed DWARF range list.
-class DwarfRangeListHandler: public dwarf2reader::RangeListHandler {
+class DwarfRangeListHandler: public RangeListHandler {
public:
- DwarfRangeListHandler(uint64_t base_address, vector<Module::Range> *ranges)
- : base_address_(base_address), ranges_(ranges) { }
+ DwarfRangeListHandler(vector<Module::Range>* ranges)
+ : ranges_(ranges) { }
~DwarfRangeListHandler() { }
// Add a range to the list
void AddRange(uint64_t begin, uint64_t end);
- // Record the new base address and use it for the following entries
- void SetBaseAddress(uint64_t base_address);
-
// Sort the ranges so that they are in ascending order of starting address
void Finish();
private:
- // The current PC to add to every entry, this can be overridden by a special
- // list entry
- uint64_t base_address_;
-
// The list of ranges to be populated
- vector<Module::Range> *ranges_;
+ vector<Module::Range>* ranges_;
};
} // namespace google_breakpad
diff --git a/src/common/language.cc b/src/common/language.cc
index 978fb855..0096a8d1 100644
--- a/src/common/language.cc
+++ b/src/common/language.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2010 Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -35,13 +34,14 @@
#include "common/language.h"
#include <stdlib.h>
+#include <array>
#if !defined(__ANDROID__)
#include <cxxabi.h>
#endif
-#if defined(HAVE_RUST_DEMANGLE)
-#include <rust_demangle.h>
+#if defined(HAVE_RUSTC_DEMANGLE)
+#include <rustc_demangle.h>
#endif
#include <limits>
@@ -67,8 +67,8 @@ class CPPLanguage: public Language {
public:
CPPLanguage() {}
- string MakeQualifiedName(const string &parent_name,
- const string &name) const {
+ string MakeQualifiedName(const string& parent_name,
+ const string& name) const {
return MakeQualifiedNameWithSeparator(parent_name, "::", name);
}
@@ -79,6 +79,13 @@ class CPPLanguage: public Language {
demangled->clear();
return kDontDemangle;
#else
+ // Attempting to demangle non-C++ symbols with the C++ demangler would print
+ // warnings and fail, so return kDontDemangle for these.
+ if (!IsMangledName(mangled)) {
+ demangled->clear();
+ return kDontDemangle;
+ }
+
int status;
char* demangled_c =
abi::__cxa_demangle(mangled.c_str(), NULL, NULL, &status);
@@ -99,6 +106,21 @@ class CPPLanguage: public Language {
return result;
#endif
}
+
+ private:
+ static bool IsMangledName(const string& name) {
+ // NOTE: For proper cross-compilation support, this should depend on target
+ // binary's platform, not current build platform.
+#if defined(__APPLE__)
+ // Mac C++ symbols can have up to 4 underscores, followed by a "Z".
+ // Non-C++ symbols are not coded that way, but may have leading underscores.
+ size_t i = name.find_first_not_of('_');
+ return i > 0 && i != string::npos && i <= 4 && name[i] == 'Z';
+#else
+ // Linux C++ symbols always start with "_Z".
+ return name.size() > 2 && name[0] == '_' && name[1] == 'Z';
+#endif
+ }
};
CPPLanguage CPPLanguageSingleton;
@@ -108,8 +130,8 @@ class JavaLanguage: public Language {
public:
JavaLanguage() {}
- string MakeQualifiedName(const string &parent_name,
- const string &name) const {
+ string MakeQualifiedName(const string& parent_name,
+ const string& name) const {
return MakeQualifiedNameWithSeparator(parent_name, ".", name);
}
};
@@ -121,8 +143,8 @@ class SwiftLanguage: public Language {
public:
SwiftLanguage() {}
- string MakeQualifiedName(const string &parent_name,
- const string &name) const {
+ string MakeQualifiedName(const string& parent_name,
+ const string& name) const {
return MakeQualifiedNameWithSeparator(parent_name, ".", name);
}
@@ -145,8 +167,8 @@ class RustLanguage: public Language {
public:
RustLanguage() {}
- string MakeQualifiedName(const string &parent_name,
- const string &name) const {
+ string MakeQualifiedName(const string& parent_name,
+ const string& name) const {
return MakeQualifiedNameWithSeparator(parent_name, ".", name);
}
@@ -156,13 +178,13 @@ class RustLanguage: public Language {
// abi_demangle doesn't produce stellar results due to them having
// another layer of encoding.
// If callers provide rustc-demangle, use that.
-#if defined(HAVE_RUST_DEMANGLE)
- char* rust_demangled = rust_demangle(mangled.c_str());
- if (rust_demangled == nullptr) {
+#if defined(HAVE_RUSTC_DEMANGLE)
+ std::array<char, 1 * 1024 * 1024> rustc_demangled;
+ if (rustc_demangle(mangled.c_str(), rustc_demangled.data(),
+ rustc_demangled.size()) == 0) {
return kDemangleFailure;
}
- demangled->assign(rust_demangled);
- free_rust_demangled_name(rust_demangled);
+ demangled->assign(rustc_demangled.data());
#else
// Otherwise, pass through the mangled name so callers can demangle
// after the fact.
@@ -180,8 +202,8 @@ class AssemblerLanguage: public Language {
AssemblerLanguage() {}
bool HasFunctions() const { return false; }
- string MakeQualifiedName(const string &parent_name,
- const string &name) const {
+ string MakeQualifiedName(const string& parent_name,
+ const string& name) const {
return name;
}
};
diff --git a/src/common/language.h b/src/common/language.h
index 2d2dbcd9..9ce8f1a6 100644
--- a/src/common/language.h
+++ b/src/common/language.h
@@ -1,7 +1,6 @@
// -*- mode: c++ -*-
-// Copyright (c) 2010 Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -13,7 +12,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -74,8 +73,8 @@ class Language {
// take into account the parent and child DIE types, allow languages
// to use their own data type for complex parent names, etc. But if
// C++ doesn't need all that, who would?
- virtual string MakeQualifiedName (const string &parent_name,
- const string &name) const = 0;
+ virtual string MakeQualifiedName (const string& parent_name,
+ const string& name) const = 0;
enum DemangleResult {
// Demangling was not performed because it’s not appropriate to attempt.
diff --git a/src/common/linux/breakpad_getcontext.S b/src/common/linux/breakpad_getcontext.S
index fea0109d..286047bf 100644
--- a/src/common/linux/breakpad_getcontext.S
+++ b/src/common/linux/breakpad_getcontext.S
@@ -1,5 +1,4 @@
-// Copyright (c) 2012, Google Inc.
-// All rights reserved.
+// Copyright 2012 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -32,7 +31,7 @@
#include "common/linux/ucontext_constants.h"
-/* int getcontext (ucontext_t *ucp) */
+/* int getcontext (ucontext_t* ucp) */
#if defined(__arm__)
@@ -90,6 +89,47 @@ breakpad_getcontext:
#elif defined(__aarch64__)
+#if defined(__ARM_FEATURE_PAC_DEFAULT) && __ARM_FEATURE_PAC_DEFAULT
+ // ENABLE_PAUTH must be defined to 1 since this value will be used in
+ // bitwise-shift later!
+ #define ENABLE_PAUTH 1
+
+ #if ((__ARM_FEATURE_PAC_DEFAULT&((1<<0)|(1<<1)))==0)
+ #error Pointer authentication defines no valid key!
+ #endif
+#else
+ #define ENABLE_PAUTH 0
+#endif
+
+#if defined(__ARM_FEATURE_BTI_DEFAULT) && (__ARM_FEATURE_BTI_DEFAULT==1)
+ // ENABLE_BTI must be defined to 1 since this value will be used in
+ // bitwise-shift later!
+ #define ENABLE_BTI 1
+#else
+ #define ENABLE_BTI 0
+#endif
+
+
+// Although Pointer Authentication and Branch Target Instructions are technically
+// seperate features they work together, i.e. the paciasp and pacibsp instructions
+// serve as BTI landing pads.
+// Therefore PA-instructions are enabled when PA _or_ BTI is enabled!
+#if ENABLE_PAUTH || ENABLE_BTI
+ // See section "Pointer Authentication" of
+ // https://developer.arm.com/documentation/101028/0012/5--Feature-test-macros
+ // for details how to interpret __ARM_FEATURE_PAC_DEFAULT
+ #if (__ARM_FEATURE_PAC_DEFAULT & (1<<0))
+ #define PAUTH_SIGN_SP paciasp
+ #define PAUTH_AUTH_SP autiasp
+ #else
+ #define PAUTH_SIGN_SP pacibsp
+ #define PAUTH_AUTH_SP autibsp
+ #endif
+#else
+ #define PAUTH_SIGN_SP
+ #define PAUTH_AUTH_SP
+#endif
+
#define _NSIG 64
#define __NR_rt_sigprocmask 135
@@ -101,6 +141,8 @@ breakpad_getcontext:
.cfi_startproc
breakpad_getcontext:
+ PAUTH_SIGN_SP
+
/* The saved context will return to the getcontext() call point
with a return value of 0 */
str xzr, [x0, MCONTEXT_GREGS_OFFSET + 0 * REGISTER_SIZE]
@@ -170,6 +212,9 @@ breakpad_getcontext:
/* Return x0 for success */
mov x0, 0
+
+ PAUTH_AUTH_SP
+
ret
.cfi_endproc
@@ -336,7 +381,7 @@ symbol: .frame sp, framesize, rpc;
.size function,.-function
#endif
-/* int getcontext (ucontext_t *ucp) */
+/* int getcontext (ucontext_t* ucp) */
NESTED (breakpad_getcontext, FRAME_SIZE, ra)
.mask 0x10000000, 0
@@ -481,6 +526,120 @@ breakpad_getcontext:
.cfi_endproc
.size breakpad_getcontext, . - breakpad_getcontext
+#elif defined(__riscv)
+
+# define SIG_BLOCK 0
+# define _NSIG8 8
+# define __NR_rt_sigprocmask 135
+
+ .text
+ .globl breakpad_getcontext
+ .type breakpad_getcontext, @function
+ .align 0
+ .cfi_startproc
+breakpad_getcontext:
+ REG_S ra, MCONTEXT_GREGS_PC(a0)
+ REG_S ra, MCONTEXT_GREGS_RA(a0)
+ REG_S sp, MCONTEXT_GREGS_SP(a0)
+ REG_S gp, MCONTEXT_GREGS_SP(a0)
+ REG_S tp, MCONTEXT_GREGS_TP(a0)
+ REG_S t0, MCONTEXT_GREGS_T0(a0)
+ REG_S t1, MCONTEXT_GREGS_T1(a0)
+ REG_S t2, MCONTEXT_GREGS_T2(a0)
+ REG_S s0, MCONTEXT_GREGS_S0(a0)
+ REG_S s1, MCONTEXT_GREGS_S1(a0)
+ REG_S a0, MCONTEXT_GREGS_A0(a0)
+ REG_S a1, MCONTEXT_GREGS_A1(a0)
+ REG_S a2, MCONTEXT_GREGS_A2(a0)
+ REG_S a3, MCONTEXT_GREGS_A3(a0)
+ REG_S a4, MCONTEXT_GREGS_A4(a0)
+ REG_S a5, MCONTEXT_GREGS_A5(a0)
+ REG_S a6, MCONTEXT_GREGS_A6(a0)
+ REG_S a7, MCONTEXT_GREGS_A7(a0)
+ REG_S s2, MCONTEXT_GREGS_S2(a0)
+ REG_S s3, MCONTEXT_GREGS_S3(a0)
+ REG_S s4, MCONTEXT_GREGS_S4(a0)
+ REG_S s5, MCONTEXT_GREGS_S5(a0)
+ REG_S s6, MCONTEXT_GREGS_S6(a0)
+ REG_S s7, MCONTEXT_GREGS_S7(a0)
+ REG_S s8, MCONTEXT_GREGS_S8(a0)
+ REG_S s9, MCONTEXT_GREGS_S9(a0)
+ REG_S s10, MCONTEXT_GREGS_S10(a0)
+ REG_S s11, MCONTEXT_GREGS_S11(a0)
+ REG_S t3, MCONTEXT_GREGS_T3(a0)
+ REG_S t4, MCONTEXT_GREGS_T4(a0)
+ REG_S t5, MCONTEXT_GREGS_T5(a0)
+ REG_S t6 , MCONTEXT_GREGS_T6(a0)
+# ifndef __riscv_float_abi_soft
+ frsr a1
+
+ FREG_S ft0, MCONTEXT_FPREGS_FT0(a0)
+ FREG_S ft1, MCONTEXT_FPREGS_FT1(a0)
+ FREG_S ft2, MCONTEXT_FPREGS_FT2(a0)
+ FREG_S ft3, MCONTEXT_FPREGS_FT3(a0)
+ FREG_S ft4, MCONTEXT_FPREGS_FT4(a0)
+ FREG_S ft5, MCONTEXT_FPREGS_FT5(a0)
+ FREG_S ft6, MCONTEXT_FPREGS_FT6(a0)
+ FREG_S ft7, MCONTEXT_FPREGS_FT7(a0)
+ FREG_S fs0, MCONTEXT_FPREGS_FS0(a0)
+ FREG_S fs1, MCONTEXT_FPREGS_FS1(a0)
+ FREG_S fa0, MCONTEXT_FPREGS_FA0(a0)
+ FREG_S fa1, MCONTEXT_FPREGS_FA1(a0)
+ FREG_S fa2, MCONTEXT_FPREGS_FA2(a0)
+ FREG_S fa3, MCONTEXT_FPREGS_FA3(a0)
+ FREG_S fa4, MCONTEXT_FPREGS_FA4(a0)
+ FREG_S fa5, MCONTEXT_FPREGS_FA5(a0)
+ FREG_S fa6, MCONTEXT_FPREGS_FA6(a0)
+ FREG_S fa7, MCONTEXT_FPREGS_FA7(a0)
+ FREG_S fs2, MCONTEXT_FPREGS_FS2(a0)
+ FREG_S fs3, MCONTEXT_FPREGS_FS3(a0)
+ FREG_S fs4, MCONTEXT_FPREGS_FS4(a0)
+ FREG_S fs5, MCONTEXT_FPREGS_FS5(a0)
+ FREG_S fs6, MCONTEXT_FPREGS_FS6(a0)
+ FREG_S fs7, MCONTEXT_FPREGS_FS7(a0)
+ FREG_S fs8, MCONTEXT_FPREGS_FS8(a0)
+ FREG_S fs9, MCONTEXT_FPREGS_FS9(a0)
+ FREG_S fs10, MCONTEXT_FPREGS_FS10(a0)
+ FREG_S fs11, MCONTEXT_FPREGS_FS11(a0)
+ FREG_S ft8, MCONTEXT_FPREGS_FT8(a0)
+ FREG_S ft9, MCONTEXT_FPREGS_FT9(a0)
+ FREG_S ft10, MCONTEXT_FPREGS_FT10(a0)
+ FREG_S ft11, MCONTEXT_FPREGS_FT11(a0)
+
+ sw a1, MCONTEXT_FPC_CSR(a0)
+# endif // __riscv_float_abi_soft
+ mv a1, zero
+ add a2, a0, UCONTEXT_SIGMASK_OFFSET
+ li a3, _NSIG8
+ mv a0, zero
+ li a7, __NR_rt_sigprocmask
+ ecall
+ mv a0, zero
+ ret
+
+ .cfi_endproc
+ .size breakpad_getcontext, . - breakpad_getcontext
+
#else
-#error "This file has not been ported for your CPU!"
+# error "This file has not been ported for your CPU!"
+#endif
+
+#if defined(__aarch64__)
+// ENABLE_PAUTH and ENABLE_BTI would be enabled at the definition
+// of AArch64 specific breakpad_getcontext function
+#if ENABLE_PAUTH || ENABLE_BTI
+// for further information on the .note.gnu.property section see
+// https://github.com/ARM-software/abi-aa/blob/main/aaelf64/aaelf64.rst#program-property
+.pushsection .note.gnu.property, "a";
+ .balign 8
+ .long 4
+ .long 0x10
+ .long 0x5
+ .asciz "GNU"
+ .long 0xc0000000 /* GNU_PROPERTY_AARCH64_FEATURE_1_AND */
+ .long 4
+ .long ((ENABLE_PAUTH)<<1) | ((ENABLE_BTI)<<0) /* PAuth and BTI */
+ .long 0
+.popsection
+#endif
#endif
diff --git a/src/common/linux/breakpad_getcontext.h b/src/common/linux/breakpad_getcontext.h
index 1418cde6..c553219f 100644
--- a/src/common/linux/breakpad_getcontext.h
+++ b/src/common/linux/breakpad_getcontext.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2012, Google Inc.
-// All rights reserved.
+// Copyright 2012 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/common/linux/breakpad_getcontext_unittest.cc b/src/common/linux/breakpad_getcontext_unittest.cc
index a57bfedf..573ddd88 100644
--- a/src/common/linux/breakpad_getcontext_unittest.cc
+++ b/src/common/linux/breakpad_getcontext_unittest.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2012, Google Inc.
-// All rights reserved.
+// Copyright 2012 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -114,6 +113,25 @@ TEST(AndroidUContext, GRegsOffset) {
ASSERT_EQ(static_cast<size_t>(MCONTEXT_FPC_CSR),
offsetof(ucontext_t,uc_mcontext.fpc_csr));
+#elif defined(__riscv)
+ ASSERT_EQ(static_cast<size_t>(MCONTEXT_GREGS_OFFSET),
+ offsetof(ucontext_t,uc_mcontext.__gregs[0]));
+
+#define CHECK_REG(x) \
+ ASSERT_EQ(static_cast<size_t>(MCONTEXT_##x##_OFFSET), \
+ offsetof(ucontext_t,uc_mcontext.__gregs[REG_##x]))
+ CHECK_REG(PC)
+ CHECK_REG(RA)
+ CHECK_REG(SP)
+ CHECK_REG(S0)
+ CHECK_REG(S1)
+ CHECK_REG(S2)
+
+ ASSERT_EQ(static_cast<size_t>(MCONTEXT_FPREGS_OFFSET),
+ offsetof(ucontext_t,uc_mcontext.__fpregs));
+
+ ASSERT_EQ(static_cast<size_t>(MCONTEXT_FPC_CSR),
+ offsetof(ucontext_t,uc_mcontext.__fpregs.__fcsr));
#elif defined(__x86_64__)
COMPILE_ASSERT_EQ(static_cast<size_t>(MCONTEXT_GREGS_OFFSET),
diff --git a/src/common/linux/crc32.cc b/src/common/linux/crc32.cc
index 8df636ce..c02f06c4 100644
--- a/src/common/linux/crc32.cc
+++ b/src/common/linux/crc32.cc
@@ -1,5 +1,4 @@
-// Copyright 2014 Google Inc.
-// All rights reserved.
+// Copyright 2014 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/common/linux/crc32.h b/src/common/linux/crc32.h
index e3d9db92..7df46999 100644
--- a/src/common/linux/crc32.h
+++ b/src/common/linux/crc32.h
@@ -1,5 +1,4 @@
-// Copyright 2014 Google Inc.
-// All rights reserved.
+// Copyright 2014 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/common/linux/dump_symbols.cc b/src/common/linux/dump_symbols.cc
index b7e77ab7..b436f765 100644
--- a/src/common/linux/dump_symbols.cc
+++ b/src/common/linux/dump_symbols.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2011 Google Inc.
-// All rights reserved.
+// Copyright 2011 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -47,8 +46,8 @@
#include <sys/mman.h>
#include <sys/stat.h>
#include <unistd.h>
+#include <zlib.h>
-#include <iostream>
#include <set>
#include <string>
#include <utility>
@@ -87,11 +86,11 @@ using google_breakpad::DwarfRangeListHandler;
using google_breakpad::ElfClass;
using google_breakpad::ElfClass32;
using google_breakpad::ElfClass64;
-using google_breakpad::FileID;
+using google_breakpad::elf::FileID;
using google_breakpad::FindElfSectionByName;
using google_breakpad::GetOffset;
using google_breakpad::IsValidElf;
-using google_breakpad::kDefaultBuildIdSize;
+using google_breakpad::elf::kDefaultBuildIdSize;
using google_breakpad::Module;
using google_breakpad::PageAllocator;
#ifndef NO_STABS_SUPPORT
@@ -144,7 +143,7 @@ class MmapWrapper {
munmap(base_, size_);
}
}
- void set(void *mapped_address, size_t mapped_size) {
+ void set(void* mapped_address, size_t mapped_size) {
is_set_ = true;
base_ = mapped_address;
size_ = mapped_size;
@@ -228,62 +227,121 @@ bool LoadStabs(const typename ElfClass::Ehdr* elf_header,
#endif // NO_STABS_SUPPORT
// A range handler that accepts rangelist data parsed by
-// dwarf2reader::RangeListReader and populates a range vector (typically
+// google_breakpad::RangeListReader and populates a range vector (typically
// owned by a function) with the results.
class DumperRangesHandler : public DwarfCUToModule::RangesHandler {
public:
- DumperRangesHandler(const uint8_t *buffer, uint64_t size,
- dwarf2reader::ByteReader* reader)
- : buffer_(buffer), size_(size), reader_(reader) { }
-
- bool ReadRanges(uint64_t offset, Module::Address base_address,
- vector<Module::Range>* ranges) {
- DwarfRangeListHandler handler(base_address, ranges);
- dwarf2reader::RangeListReader rangelist_reader(buffer_, size_, reader_,
- &handler);
-
- return rangelist_reader.ReadRangeList(offset);
+ DumperRangesHandler(google_breakpad::ByteReader* reader) :
+ reader_(reader) { }
+
+ bool ReadRanges(
+ enum google_breakpad::DwarfForm form, uint64_t data,
+ google_breakpad::RangeListReader::CURangesInfo* cu_info,
+ vector<Module::Range>* ranges) {
+ DwarfRangeListHandler handler(ranges);
+ google_breakpad::RangeListReader range_list_reader(reader_, cu_info,
+ &handler);
+ return range_list_reader.ReadRanges(form, data);
}
private:
- const uint8_t *buffer_;
- uint64_t size_;
- dwarf2reader::ByteReader* reader_;
+ google_breakpad::ByteReader* reader_;
};
// A line-to-module loader that accepts line number info parsed by
-// dwarf2reader::LineInfo and populates a Module and a line vector
+// google_breakpad::LineInfo and populates a Module and a line vector
// with the results.
class DumperLineToModule: public DwarfCUToModule::LineToModuleHandler {
public:
// Create a line-to-module converter using BYTE_READER.
- explicit DumperLineToModule(dwarf2reader::ByteReader *byte_reader)
+ explicit DumperLineToModule(google_breakpad::ByteReader* byte_reader)
: byte_reader_(byte_reader) { }
void StartCompilationUnit(const string& compilation_dir) {
compilation_dir_ = compilation_dir;
}
- void ReadProgram(const uint8_t *program, uint64_t length,
- Module* module, std::vector<Module::Line>* lines) {
- DwarfLineToModule handler(module, compilation_dir_, lines);
- dwarf2reader::LineInfo parser(program, length, byte_reader_, &handler);
+ void ReadProgram(const uint8_t* program,
+ uint64_t length,
+ const uint8_t* string_section,
+ uint64_t string_section_length,
+ const uint8_t* line_string_section,
+ uint64_t line_string_section_length,
+ Module* module,
+ std::vector<Module::Line>* lines,
+ std::map<uint32_t, Module::File*>* files) {
+ DwarfLineToModule handler(module, compilation_dir_, lines, files);
+ google_breakpad::LineInfo parser(program, length, byte_reader_,
+ string_section, string_section_length,
+ line_string_section,
+ line_string_section_length,
+ &handler);
parser.Start();
}
private:
string compilation_dir_;
- dwarf2reader::ByteReader *byte_reader_;
+ google_breakpad::ByteReader* byte_reader_;
};
template<typename ElfClass>
+bool IsCompressedHeader(const typename ElfClass::Shdr* section) {
+ return (section->sh_flags & SHF_COMPRESSED) != 0;
+}
+
+template<typename ElfClass>
+uint32_t GetCompressionHeader(
+ typename ElfClass::Chdr& compression_header,
+ const uint8_t* content, uint64_t size) {
+ const typename ElfClass::Chdr* header =
+ reinterpret_cast<const typename ElfClass::Chdr *>(content);
+
+ if (size < sizeof (*header)) {
+ return 0;
+ }
+
+ compression_header = *header;
+ return sizeof (*header);
+}
+
+std::pair<uint8_t *, uint64_t> UncompressSectionContents(
+ const uint8_t* compressed_buffer, uint64_t compressed_size, uint64_t uncompressed_size) {
+ z_stream stream;
+ memset(&stream, 0, sizeof stream);
+
+ stream.avail_in = compressed_size;
+ stream.avail_out = uncompressed_size;
+ stream.next_in = const_cast<uint8_t *>(compressed_buffer);
+
+ google_breakpad::scoped_array<uint8_t> uncompressed_buffer(
+ new uint8_t[uncompressed_size]);
+
+ int status = inflateInit(&stream);
+ while (stream.avail_in != 0 && status == Z_OK) {
+ stream.next_out =
+ uncompressed_buffer.get() + uncompressed_size - stream.avail_out;
+
+ if ((status = inflate(&stream, Z_FINISH)) != Z_STREAM_END) {
+ break;
+ }
+
+ status = inflateReset(&stream);
+ }
+
+ return inflateEnd(&stream) != Z_OK || status != Z_OK || stream.avail_out != 0
+ ? std::make_pair(nullptr, 0)
+ : std::make_pair(uncompressed_buffer.release(), uncompressed_size);
+}
+
+template<typename ElfClass>
bool LoadDwarf(const string& dwarf_filename,
const typename ElfClass::Ehdr* elf_header,
const bool big_endian,
bool handle_inter_cu_refs,
+ bool handle_inline,
Module* module) {
typedef typename ElfClass::Shdr Shdr;
- const dwarf2reader::Endianness endianness = big_endian ?
- dwarf2reader::ENDIANNESS_BIG : dwarf2reader::ENDIANNESS_LITTLE;
- dwarf2reader::ByteReader byte_reader(endianness);
+ const google_breakpad::Endianness endianness = big_endian ?
+ google_breakpad::ENDIANNESS_BIG : google_breakpad::ENDIANNESS_LITTLE;
+ google_breakpad::ByteReader byte_reader(endianness);
// Construct a context for this file.
DwarfCUToModule::FileContext file_context(dwarf_filename,
@@ -300,29 +358,44 @@ bool LoadDwarf(const string& dwarf_filename,
string name = GetOffset<ElfClass, char>(elf_header,
section_names->sh_offset) +
section->sh_name;
- const uint8_t *contents = GetOffset<ElfClass, uint8_t>(elf_header,
+ const uint8_t* contents = GetOffset<ElfClass, uint8_t>(elf_header,
section->sh_offset);
- file_context.AddSectionToSectionMap(name, contents, section->sh_size);
- }
+ uint64_t size = section->sh_size;
+
+ if (!IsCompressedHeader<ElfClass>(section)) {
+ file_context.AddSectionToSectionMap(name, contents, size);
+ continue;
+ }
+
+ typename ElfClass::Chdr chdr;
- // Optional .debug_ranges reader
- scoped_ptr<DumperRangesHandler> ranges_handler;
- dwarf2reader::SectionMap::const_iterator ranges_entry =
- file_context.section_map().find(".debug_ranges");
- if (ranges_entry != file_context.section_map().end()) {
- const std::pair<const uint8_t *, uint64_t>& ranges_section =
- ranges_entry->second;
- ranges_handler.reset(
- new DumperRangesHandler(ranges_section.first, ranges_section.second,
- &byte_reader));
+ uint32_t compression_header_size =
+ GetCompressionHeader<ElfClass>(chdr, contents, size);
+
+ if (compression_header_size == 0 || chdr.ch_size == 0) {
+ continue;
+ }
+
+ contents += compression_header_size;
+ size -= compression_header_size;
+
+ std::pair<uint8_t *, uint64_t> uncompressed =
+ UncompressSectionContents(contents, size, chdr.ch_size);
+
+ if (uncompressed.first != nullptr && uncompressed.second != 0) {
+ file_context.AddManagedSectionToSectionMap(name, uncompressed.first, uncompressed.second);
+ }
}
+ // .debug_ranges and .debug_rnglists reader
+ DumperRangesHandler ranges_handler(&byte_reader);
+
// Parse all the compilation units in the .debug_info section.
DumperLineToModule line_to_module(&byte_reader);
- dwarf2reader::SectionMap::const_iterator debug_info_entry =
+ google_breakpad::SectionMap::const_iterator debug_info_entry =
file_context.section_map().find(".debug_info");
assert(debug_info_entry != file_context.section_map().end());
- const std::pair<const uint8_t *, uint64_t>& debug_info_section =
+ const std::pair<const uint8_t*, uint64_t>& debug_info_section =
debug_info_entry->second;
// This should never have been called if the file doesn't have a
// .debug_info section.
@@ -333,11 +406,11 @@ bool LoadDwarf(const string& dwarf_filename,
// data that was found.
DwarfCUToModule::WarningReporter reporter(dwarf_filename, offset);
DwarfCUToModule root_handler(&file_context, &line_to_module,
- ranges_handler.get(), &reporter);
+ &ranges_handler, &reporter, handle_inline);
// Make a Dwarf2Handler that drives the DIEHandler.
- dwarf2reader::DIEDispatcher die_dispatcher(&root_handler);
+ google_breakpad::DIEDispatcher die_dispatcher(&root_handler);
// Make a DWARF parser for the compilation unit at OFFSET.
- dwarf2reader::CompilationUnit reader(dwarf_filename,
+ google_breakpad::CompilationUnit reader(dwarf_filename,
file_context.section_map(),
offset,
&byte_reader,
@@ -397,18 +470,18 @@ bool LoadDwarfCFI(const string& dwarf_filename,
return false;
}
- const dwarf2reader::Endianness endianness = big_endian ?
- dwarf2reader::ENDIANNESS_BIG : dwarf2reader::ENDIANNESS_LITTLE;
+ const google_breakpad::Endianness endianness = big_endian ?
+ google_breakpad::ENDIANNESS_BIG : google_breakpad::ENDIANNESS_LITTLE;
// Find the call frame information and its size.
- const uint8_t *cfi =
+ const uint8_t* cfi =
GetOffset<ElfClass, uint8_t>(elf_header, section->sh_offset);
size_t cfi_size = section->sh_size;
// Plug together the parser, handler, and their entourages.
DwarfCFIToModule::Reporter module_reporter(dwarf_filename, section_name);
DwarfCFIToModule handler(module, register_names, &module_reporter);
- dwarf2reader::ByteReader byte_reader(endianness);
+ google_breakpad::ByteReader byte_reader(endianness);
byte_reader.SetAddressSize(ElfClass::kAddrSize);
@@ -420,11 +493,44 @@ bool LoadDwarfCFI(const string& dwarf_filename,
if (text_section)
byte_reader.SetTextBase(text_section->sh_addr);
- dwarf2reader::CallFrameInfo::Reporter dwarf_reporter(dwarf_filename,
+ google_breakpad::CallFrameInfo::Reporter dwarf_reporter(dwarf_filename,
section_name);
- dwarf2reader::CallFrameInfo parser(cfi, cfi_size,
- &byte_reader, &handler, &dwarf_reporter,
- eh_frame);
+ if (!IsCompressedHeader<ElfClass>(section)) {
+ google_breakpad::CallFrameInfo parser(cfi, cfi_size,
+ &byte_reader, &handler,
+ &dwarf_reporter, eh_frame);
+ parser.Start();
+ return true;
+ }
+
+ typename ElfClass::Chdr chdr;
+ uint32_t compression_header_size =
+ GetCompressionHeader<ElfClass>(chdr, cfi, cfi_size);
+
+ if (compression_header_size == 0 || chdr.ch_size == 0) {
+ fprintf(stderr, "%s: decompression failed at header\n",
+ dwarf_filename.c_str());
+ return false;
+ }
+ if (compression_header_size > cfi_size) {
+ fprintf(stderr, "%s: decompression error, compression_header too large\n",
+ dwarf_filename.c_str());
+ return false;
+ }
+
+ cfi += compression_header_size;
+ cfi_size -= compression_header_size;
+
+ std::pair<uint8_t *, uint64_t> uncompressed =
+ UncompressSectionContents(cfi, cfi_size, chdr.ch_size);
+
+ if (uncompressed.first == nullptr || uncompressed.second == 0) {
+ fprintf(stderr, "%s: decompression failed\n", dwarf_filename.c_str());
+ return false;
+ }
+ google_breakpad::CallFrameInfo parser(uncompressed.first, uncompressed.second,
+ &byte_reader, &handler, &dwarf_reporter,
+ eh_frame);
parser.Start();
return true;
}
@@ -489,13 +595,13 @@ bool IsSameFile(const char* left_abspath, const string& right_path) {
// Read the .gnu_debuglink and get the debug file name. If anything goes
// wrong, return an empty string.
-string ReadDebugLink(const uint8_t *debuglink,
+string ReadDebugLink(const uint8_t* debuglink,
const size_t debuglink_size,
const bool big_endian,
const string& obj_file,
const std::vector<string>& debug_dirs) {
// Include '\0' + CRC32 (4 bytes).
- size_t debuglink_len = strlen(reinterpret_cast<const char *>(debuglink)) + 5;
+ size_t debuglink_len = strlen(reinterpret_cast<const char*>(debuglink)) + 5;
debuglink_len = 4 * ((debuglink_len + 3) / 4); // Round up to 4 bytes.
// Sanity check.
@@ -517,7 +623,7 @@ string ReadDebugLink(const uint8_t *debuglink,
for (it = debug_dirs.begin(); it < debug_dirs.end(); ++it) {
const string& debug_dir = *it;
debuglink_path = debug_dir + "/" +
- reinterpret_cast<const char *>(debuglink);
+ reinterpret_cast<const char*>(debuglink);
// There is the annoying case of /path/to/foo.so having foo.so as the
// debug link file name. Thus this may end up opening /path/to/foo.so again,
@@ -533,9 +639,9 @@ string ReadDebugLink(const uint8_t *debuglink,
FDWrapper debuglink_fd_wrapper(debuglink_fd);
// The CRC is the last 4 bytes in |debuglink|.
- const dwarf2reader::Endianness endianness = big_endian ?
- dwarf2reader::ENDIANNESS_BIG : dwarf2reader::ENDIANNESS_LITTLE;
- dwarf2reader::ByteReader byte_reader(endianness);
+ const google_breakpad::Endianness endianness = big_endian ?
+ google_breakpad::ENDIANNESS_BIG : google_breakpad::ENDIANNESS_LITTLE;
+ google_breakpad::ByteReader byte_reader(endianness);
uint32_t expected_crc =
byte_reader.ReadFourBytes(&debuglink[debuglink_size - 4]);
@@ -591,7 +697,7 @@ class LoadSymbolsInfo {
// Keeps track of which sections have been loaded so sections don't
// accidentally get loaded twice from two different files.
- void LoadedSection(const string &section) {
+ void LoadedSection(const string& section) {
if (loaded_sections_.count(section) == 0) {
loaded_sections_.insert(section);
} else {
@@ -602,7 +708,7 @@ class LoadSymbolsInfo {
// The ELF file and linked debug file are expected to have the same preferred
// loading address.
- void set_loading_addr(Addr addr, const string &filename) {
+ void set_loading_addr(Addr addr, const string& filename) {
if (!has_loading_addr_) {
loading_addr_ = addr;
loaded_file_ = filename;
@@ -679,11 +785,12 @@ bool LoadSymbols(const string& obj_file,
const Shdr* section_names = sections + elf_header->e_shstrndx;
const char* names =
GetOffset<ElfClass, char>(elf_header, section_names->sh_offset);
- const char *names_end = names + section_names->sh_size;
+ const char* names_end = names + section_names->sh_size;
bool found_debug_info_section = false;
bool found_usable_info = false;
- if (options.symbol_data != ONLY_CFI) {
+ if ((options.symbol_data & SYMBOLS_AND_FILES) ||
+ (options.symbol_data & INLINES)) {
#ifndef NO_STABS_SUPPORT
// Look for STABS debugging information, and load it if present.
const Shdr* stab_section =
@@ -705,32 +812,6 @@ bool LoadSymbols(const string& obj_file,
}
#endif // NO_STABS_SUPPORT
- // Look for DWARF debugging information, and load it if present.
- const Shdr* dwarf_section =
- FindElfSectionByName<ElfClass>(".debug_info", SHT_PROGBITS,
- sections, names, names_end,
- elf_header->e_shnum);
-
- // .debug_info section type is SHT_PROGBITS for mips on pnacl toolchains,
- // but MIPS_DWARF for regular gnu toolchains, so both need to be checked
- if (elf_header->e_machine == EM_MIPS && !dwarf_section) {
- dwarf_section =
- FindElfSectionByName<ElfClass>(".debug_info", SHT_MIPS_DWARF,
- sections, names, names_end,
- elf_header->e_shnum);
- }
-
- if (dwarf_section) {
- found_debug_info_section = true;
- found_usable_info = true;
- info->LoadedSection(".debug_info");
- if (!LoadDwarf<ElfClass>(obj_file, elf_header, big_endian,
- options.handle_inter_cu_refs, module)) {
- fprintf(stderr, "%s: \".debug_info\" section found, but failed to load "
- "DWARF debugging information\n", obj_file.c_str());
- }
- }
-
// See if there are export symbols available.
const Shdr* symtab_section =
FindElfSectionByName<ElfClass>(".symtab", SHT_SYMTAB,
@@ -788,9 +869,38 @@ bool LoadSymbols(const string& obj_file,
found_usable_info = found_usable_info || result;
}
}
+
+ // Only Load .debug_info after loading symbol table to avoid duplicate
+ // PUBLIC records.
+ // Look for DWARF debugging information, and load it if present.
+ const Shdr* dwarf_section =
+ FindElfSectionByName<ElfClass>(".debug_info", SHT_PROGBITS,
+ sections, names, names_end,
+ elf_header->e_shnum);
+
+ // .debug_info section type is SHT_PROGBITS for mips on pnacl toolchains,
+ // but MIPS_DWARF for regular gnu toolchains, so both need to be checked
+ if (elf_header->e_machine == EM_MIPS && !dwarf_section) {
+ dwarf_section =
+ FindElfSectionByName<ElfClass>(".debug_info", SHT_MIPS_DWARF,
+ sections, names, names_end,
+ elf_header->e_shnum);
+ }
+
+ if (dwarf_section) {
+ found_debug_info_section = true;
+ found_usable_info = true;
+ info->LoadedSection(".debug_info");
+ if (!LoadDwarf<ElfClass>(obj_file, elf_header, big_endian,
+ options.handle_inter_cu_refs,
+ options.symbol_data & INLINES, module)) {
+ fprintf(stderr, "%s: \".debug_info\" section found, but failed to load "
+ "DWARF debugging information\n", obj_file.c_str());
+ }
+ }
}
- if (options.symbol_data != NO_CFI) {
+ if (options.symbol_data & CFI) {
// Dwarf Call Frame Information (CFI) is actually independent from
// the other DWARF debugging information, and can be used alone.
const Shdr* dwarf_cfi_section =
@@ -859,7 +969,7 @@ bool LoadSymbols(const string& obj_file,
names_end, elf_header->e_shnum);
if (gnu_debuglink_section) {
if (!info->debug_dirs().empty()) {
- const uint8_t *debuglink_contents =
+ const uint8_t* debuglink_contents =
GetOffset<ElfClass, uint8_t>(elf_header,
gnu_debuglink_section->sh_offset);
string debuglink_file =
@@ -947,7 +1057,8 @@ template<typename ElfClass>
bool InitModuleForElfClass(const typename ElfClass::Ehdr* elf_header,
const string& obj_filename,
const string& obj_os,
- scoped_ptr<Module>& module) {
+ scoped_ptr<Module>& module,
+ bool enable_multiple_field) {
PageAllocator allocator;
wasteful_vector<uint8_t> identifier(&allocator, kDefaultBuildIdSize);
if (!FileID::ElfFileIdentifierFromMappedFile(elf_header, identifier)) {
@@ -956,7 +1067,7 @@ bool InitModuleForElfClass(const typename ElfClass::Ehdr* elf_header,
return false;
}
- const char *architecture = ElfArchitecture<ElfClass>(elf_header);
+ const char* architecture = ElfArchitecture<ElfClass>(elf_header);
if (!architecture) {
fprintf(stderr, "%s: unrecognized ELF machine architecture: %d\n",
obj_filename.c_str(), elf_header->e_machine);
@@ -976,7 +1087,8 @@ bool InitModuleForElfClass(const typename ElfClass::Ehdr* elf_header,
// This is just the raw Build ID in hex.
string code_id = FileID::ConvertIdentifierToString(identifier);
- module.reset(new Module(name, obj_os, architecture, id, code_id));
+ module.reset(new Module(name, obj_os, architecture, id, code_id,
+ enable_multiple_field));
return true;
}
@@ -993,8 +1105,8 @@ bool ReadSymbolDataElfClass(const typename ElfClass::Ehdr* elf_header,
*out_module = NULL;
scoped_ptr<Module> module;
- if (!InitModuleForElfClass<ElfClass>(elf_header, obj_filename, obj_os,
- module)) {
+ if (!InitModuleForElfClass<ElfClass>(elf_header, obj_filename, obj_os, module,
+ options.enable_multiple_field)) {
return false;
}
@@ -1066,12 +1178,12 @@ bool ReadSymbolDataInternal(const uint8_t* obj_file,
return false;
}
-bool WriteSymbolFile(const string &load_path,
- const string &obj_file,
- const string &obj_os,
+bool WriteSymbolFile(const string& load_path,
+ const string& obj_file,
+ const string& obj_os,
const std::vector<string>& debug_dirs,
const DumpOptions& options,
- std::ostream &sym_stream) {
+ std::ostream& sym_stream) {
Module* module;
if (!ReadSymbolData(load_path, obj_file, obj_os, debug_dirs, options,
&module))
@@ -1088,7 +1200,7 @@ bool WriteSymbolFile(const string &load_path,
bool WriteSymbolFileHeader(const string& load_path,
const string& obj_file,
const string& obj_os,
- std::ostream &sym_stream) {
+ std::ostream& sym_stream) {
MmapWrapper map_wrapper;
void* elf_header = NULL;
if (!LoadELF(load_path, &map_wrapper, &elf_header)) {
@@ -1106,14 +1218,14 @@ bool WriteSymbolFileHeader(const string& load_path,
if (elfclass == ELFCLASS32) {
if (!InitModuleForElfClass<ElfClass32>(
reinterpret_cast<const Elf32_Ehdr*>(elf_header), obj_file, obj_os,
- module)) {
+ module, /*enable_multiple_field=*/false)) {
fprintf(stderr, "Failed to load ELF module: %s\n", obj_file.c_str());
return false;
}
} else if (elfclass == ELFCLASS64) {
if (!InitModuleForElfClass<ElfClass64>(
reinterpret_cast<const Elf64_Ehdr*>(elf_header), obj_file, obj_os,
- module)) {
+ module, /*enable_multiple_field=*/false)) {
fprintf(stderr, "Failed to load ELF module: %s\n", obj_file.c_str());
return false;
}
diff --git a/src/common/linux/dump_symbols.h b/src/common/linux/dump_symbols.h
index eaddd8b2..f1802ecc 100644
--- a/src/common/linux/dump_symbols.h
+++ b/src/common/linux/dump_symbols.h
@@ -1,7 +1,6 @@
// -*- mode: c++ -*-
-// Copyright (c) 2011, Google Inc.
-// All rights reserved.
+// Copyright 2011 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -13,7 +12,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -47,13 +46,16 @@ namespace google_breakpad {
class Module;
struct DumpOptions {
- DumpOptions(SymbolData symbol_data, bool handle_inter_cu_refs)
+ DumpOptions(SymbolData symbol_data,
+ bool handle_inter_cu_refs,
+ bool enable_multiple_field)
: symbol_data(symbol_data),
- handle_inter_cu_refs(handle_inter_cu_refs) {
- }
+ handle_inter_cu_refs(handle_inter_cu_refs),
+ enable_multiple_field(enable_multiple_field) {}
SymbolData symbol_data;
bool handle_inter_cu_refs;
+ bool enable_multiple_field;
};
// Find all the debugging information in OBJ_FILE, an ELF executable
@@ -62,12 +64,12 @@ struct DumpOptions {
// If OBJ_FILE has been stripped but contains a .gnu_debuglink section,
// then look for the debug file in DEBUG_DIRS.
// SYMBOL_DATA allows limiting the type of symbol data written.
-bool WriteSymbolFile(const string &load_path,
- const string &obj_file,
- const string &obj_os,
+bool WriteSymbolFile(const string& load_path,
+ const string& obj_file,
+ const string& obj_os,
const std::vector<string>& debug_dirs,
const DumpOptions& options,
- std::ostream &sym_stream);
+ std::ostream& sym_stream);
// Read the selected object file's debugging information, and write out the
// header only to |stream|. Return true on success; if an error occurs, report
@@ -76,7 +78,7 @@ bool WriteSymbolFile(const string &load_path,
bool WriteSymbolFileHeader(const string& load_path,
const string& obj_file,
const string& obj_os,
- std::ostream &sym_stream);
+ std::ostream& sym_stream);
// As above, but simply return the debugging information in MODULE
// instead of writing it to a stream. The caller owns the resulting
diff --git a/src/common/linux/dump_symbols_unittest.cc b/src/common/linux/dump_symbols_unittest.cc
index 54c21096..97d5827e 100644
--- a/src/common/linux/dump_symbols_unittest.cc
+++ b/src/common/linux/dump_symbols_unittest.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2011 Google Inc.
-// All rights reserved.
+// Copyright 2011 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -92,7 +91,7 @@ TYPED_TEST(DumpSymbols, Invalid) {
Elf32_Ehdr header;
memset(&header, 0, sizeof(header));
Module* module;
- DumpOptions options(ALL_SYMBOL_DATA, true);
+ DumpOptions options(ALL_SYMBOL_DATA, true, false);
EXPECT_FALSE(ReadSymbolDataInternal(reinterpret_cast<uint8_t*>(&header),
"foo",
"Linux",
@@ -129,7 +128,7 @@ TYPED_TEST(DumpSymbols, SimplePublic) {
this->GetElfContents(elf);
Module* module;
- DumpOptions options(ALL_SYMBOL_DATA, true);
+ DumpOptions options(ALL_SYMBOL_DATA, true, false);
EXPECT_TRUE(ReadSymbolDataInternal(this->elfdata,
"foo",
"Linux",
@@ -186,7 +185,7 @@ TYPED_TEST(DumpSymbols, SimpleBuildID) {
this->GetElfContents(elf);
Module* module;
- DumpOptions options(ALL_SYMBOL_DATA, true);
+ DumpOptions options(ALL_SYMBOL_DATA, true, false);
EXPECT_TRUE(ReadSymbolDataInternal(this->elfdata,
"foo",
"Linux",
diff --git a/src/common/linux/eintr_wrapper.h b/src/common/linux/eintr_wrapper.h
index 3f1d1848..a8428a9d 100644
--- a/src/common/linux/eintr_wrapper.h
+++ b/src/common/linux/eintr_wrapper.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2010 Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/common/linux/elf_core_dump.cc b/src/common/linux/elf_core_dump.cc
index 0e7db7b1..f5ee3033 100644
--- a/src/common/linux/elf_core_dump.cc
+++ b/src/common/linux/elf_core_dump.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2011, Google Inc.
-// All rights reserved.
+// Copyright 2011 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -34,6 +33,7 @@
#include <stddef.h>
#include <string.h>
+#include <unistd.h>
namespace google_breakpad {
@@ -95,16 +95,29 @@ size_t ElfCoreDump::Note::AlignedSize(size_t size) {
// Implementation of ElfCoreDump.
-ElfCoreDump::ElfCoreDump() {}
+ElfCoreDump::ElfCoreDump() : proc_mem_fd_(-1) {}
ElfCoreDump::ElfCoreDump(const MemoryRange& content)
- : content_(content) {
+ : content_(content), proc_mem_fd_(-1) {}
+
+ElfCoreDump::~ElfCoreDump() {
+ if (proc_mem_fd_ != -1) {
+ close(proc_mem_fd_);
+ proc_mem_fd_ = -1;
+ }
}
void ElfCoreDump::SetContent(const MemoryRange& content) {
content_ = content;
}
+void ElfCoreDump::SetProcMem(int fd) {
+ if (proc_mem_fd_ != -1) {
+ close(proc_mem_fd_);
+ }
+ proc_mem_fd_ = fd;
+}
+
bool ElfCoreDump::IsValid() const {
const Ehdr* header = GetHeader();
return (header &&
@@ -163,6 +176,16 @@ bool ElfCoreDump::CopyData(void* buffer, Addr virtual_address, size_t length) {
}
}
}
+
+ /* fallback: if available, read from /proc/<pid>/mem */
+ if (proc_mem_fd_ != -1) {
+ off_t offset = virtual_address;
+ ssize_t r = pread(proc_mem_fd_, buffer, length, offset);
+ if (r < ssize_t(length)) {
+ return false;
+ }
+ return true;
+ }
return false;
}
diff --git a/src/common/linux/elf_core_dump.h b/src/common/linux/elf_core_dump.h
index 6e153745..4f27179f 100644
--- a/src/common/linux/elf_core_dump.h
+++ b/src/common/linux/elf_core_dump.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2011, Google Inc.
-// All rights reserved.
+// Copyright 2011 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -106,6 +105,8 @@ class ElfCoreDump {
// Constructor that takes the core dump content from |content|.
explicit ElfCoreDump(const MemoryRange& content);
+ ~ElfCoreDump();
+
// Sets the core dump content to |content|.
void SetContent(const MemoryRange& content);
@@ -139,9 +140,15 @@ class ElfCoreDump {
// an empty note if no note is found.
Note GetFirstNote() const;
+ // Sets the mem fd.
+ void SetProcMem(const int fd);
+
private:
// Core dump content.
MemoryRange content_;
+
+ // Descriptor for /proc/<pid>/mem.
+ int proc_mem_fd_;
};
} // namespace google_breakpad
diff --git a/src/common/linux/elf_core_dump_unittest.cc b/src/common/linux/elf_core_dump_unittest.cc
index 2399c12f..6789dd84 100644
--- a/src/common/linux/elf_core_dump_unittest.cc
+++ b/src/common/linux/elf_core_dump_unittest.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2011, Google Inc.
-// All rights reserved.
+// Copyright 2011 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -130,9 +129,13 @@ TEST(ElfCoreDumpTest, TestElfHeader) {
TEST(ElfCoreDumpTest, ValidCoreFile) {
CrashGenerator crash_generator;
if (!crash_generator.HasDefaultCorePattern()) {
- fprintf(stderr, "ElfCoreDumpTest.ValidCoreFile test is skipped "
- "due to non-default core pattern");
- return;
+ GTEST_SKIP() << "ElfCoreDumpTest.ValidCoreFile test is skipped "
+ "due to non-default core pattern";
+ }
+
+ if (!crash_generator.HasResourceLimitsAmenableToCrashCollection()) {
+ GTEST_SKIP() << "ElfCoreDumpTest.ValidCoreFile test is skipped "
+ "due to inadequate system resource limits";
}
const unsigned kNumOfThreads = 3;
diff --git a/src/common/linux/elf_gnu_compat.h b/src/common/linux/elf_gnu_compat.h
index 0a3dfedb..5d56c1e9 100644
--- a/src/common/linux/elf_gnu_compat.h
+++ b/src/common/linux/elf_gnu_compat.h
@@ -1,7 +1,6 @@
// -*- mode: C++ -*-
-// Copyright (c) 2013, Google Inc.
-// All rights reserved.
+// Copyright 2013 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -13,7 +12,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/common/linux/elf_symbols_to_module.cc b/src/common/linux/elf_symbols_to_module.cc
index 562875e1..3c33be99 100644
--- a/src/common/linux/elf_symbols_to_module.cc
+++ b/src/common/linux/elf_symbols_to_module.cc
@@ -1,6 +1,6 @@
// -*- mode: c++ -*-
-// Copyright (c) 2011 Google Inc. All Rights Reserved.
+// Copyright 2011 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -12,7 +12,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -36,6 +36,9 @@
#include <elf.h>
#include <string.h>
+#include <memory>
+#include <utility>
+
#include "common/byte_cursor.h"
#include "common/module.h"
@@ -69,7 +72,7 @@ public:
// otherwise. Assume each symbol has a 'value' field whose size is
// VALUE_SIZE.
//
- ELFSymbolIterator(const ByteBuffer *buffer, bool big_endian,
+ ELFSymbolIterator(const ByteBuffer* buffer, bool big_endian,
size_t value_size)
: value_size_(value_size), cursor_(buffer, big_endian) {
// Actually, weird sizes could be handled just fine, but they're
@@ -81,13 +84,13 @@ public:
// Move to the next symbol. This function's behavior is undefined if
// at_end() is true when it is called.
- ELFSymbolIterator &operator++() { Fetch(); symbol_.index++; return *this; }
+ ELFSymbolIterator& operator++() { Fetch(); symbol_.index++; return *this; }
// Dereferencing this iterator produces a reference to an Symbol structure
// that holds the current symbol's values. The symbol is owned by this
// SymbolIterator, and will be invalidated at the next call to operator++.
- const Symbol &operator*() const { return symbol_; }
- const Symbol *operator->() const { return &symbol_; }
+ const Symbol& operator*() const { return symbol_; }
+ const Symbol* operator->() const { return &symbol_; }
private:
// Read the symbol at cursor_, and set symbol_ appropriately.
@@ -126,21 +129,21 @@ private:
Symbol symbol_;
};
-const char *SymbolString(ptrdiff_t offset, ByteBuffer& strings) {
+const char* SymbolString(ptrdiff_t offset, ByteBuffer& strings) {
if (offset < 0 || (size_t) offset >= strings.Size()) {
// Return the null string.
offset = 0;
}
- return reinterpret_cast<const char *>(strings.start + offset);
+ return reinterpret_cast<const char*>(strings.start + offset);
}
-bool ELFSymbolsToModule(const uint8_t *symtab_section,
+bool ELFSymbolsToModule(const uint8_t* symtab_section,
size_t symtab_size,
- const uint8_t *string_section,
+ const uint8_t* string_section,
size_t string_size,
const bool big_endian,
size_t value_size,
- Module *module) {
+ Module* module) {
ByteBuffer symbols(symtab_section, symtab_size);
// Ensure that the string section is null-terminated.
if (string_section[string_size - 1] != '\0') {
@@ -156,7 +159,7 @@ bool ELFSymbolsToModule(const uint8_t *symtab_section,
while(!iterator->at_end) {
if (ELF32_ST_TYPE(iterator->info) == STT_FUNC &&
iterator->shndx != SHN_UNDEF) {
- Module::Extern *ext = new Module::Extern(iterator->value);
+ auto ext = std::make_unique<Module::Extern>(iterator->value);
ext->name = SymbolString(iterator->name_offset, strings);
#if !defined(__ANDROID__) // Android NDK doesn't provide abi::__cxa_demangle.
int status = 0;
@@ -168,7 +171,7 @@ bool ELFSymbolsToModule(const uint8_t *symtab_section,
free(demangled);
}
#endif
- module->AddExtern(ext);
+ module->AddExtern(std::move(ext));
}
++iterator;
}
diff --git a/src/common/linux/elf_symbols_to_module.h b/src/common/linux/elf_symbols_to_module.h
index 2e7c0971..ab27ef6b 100644
--- a/src/common/linux/elf_symbols_to_module.h
+++ b/src/common/linux/elf_symbols_to_module.h
@@ -1,6 +1,6 @@
// -*- mode: c++ -*-
-// Copyright (c) 2011 Google Inc. All Rights Reserved.
+// Copyright 2011 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -12,7 +12,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -44,13 +44,13 @@ namespace google_breakpad {
class Module;
-bool ELFSymbolsToModule(const uint8_t *symtab_section,
+bool ELFSymbolsToModule(const uint8_t* symtab_section,
size_t symtab_size,
- const uint8_t *string_section,
+ const uint8_t* string_section,
size_t string_size,
const bool big_endian,
size_t value_size,
- Module *module);
+ Module* module);
} // namespace google_breakpad
diff --git a/src/common/linux/elf_symbols_to_module_unittest.cc b/src/common/linux/elf_symbols_to_module_unittest.cc
index 8984449a..17eb670f 100644
--- a/src/common/linux/elf_symbols_to_module_unittest.cc
+++ b/src/common/linux/elf_symbols_to_module_unittest.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2011 Google Inc.
-// All rights reserved.
+// Copyright 2011 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -86,7 +85,7 @@ public:
// 4 or 8 (bytes)
size_t value_size;
- vector<Module::Extern *> externs;
+ vector<Module::Extern*> externs;
};
class ELFSymbolsToModuleTest32 : public ELFSymbolsToModuleTestFixture,
@@ -248,9 +247,9 @@ TEST_P(ELFSymbolsToModuleTest32, SkipStuff) {
}
// Run all the 32-bit tests with both endianness
-INSTANTIATE_TEST_CASE_P(Endian,
- ELFSymbolsToModuleTest32,
- ::testing::Values(kLittleEndian, kBigEndian));
+INSTANTIATE_TEST_SUITE_P(Endian,
+ ELFSymbolsToModuleTest32,
+ ::testing::Values(kLittleEndian, kBigEndian));
// Similar tests, but with 64-bit values. Ostensibly this could be
// shoehorned into the parameterization by using ::testing::Combine,
@@ -365,6 +364,6 @@ TEST_P(ELFSymbolsToModuleTest64, SkipStuff) {
}
// Run all the 64-bit tests with both endianness
-INSTANTIATE_TEST_CASE_P(Endian,
- ELFSymbolsToModuleTest64,
- ::testing::Values(kLittleEndian, kBigEndian));
+INSTANTIATE_TEST_SUITE_P(Endian,
+ ELFSymbolsToModuleTest64,
+ ::testing::Values(kLittleEndian, kBigEndian));
diff --git a/src/common/linux/elfutils-inl.h b/src/common/linux/elfutils-inl.h
index e56b37a9..5fcc9c44 100644
--- a/src/common/linux/elfutils-inl.h
+++ b/src/common/linux/elfutils-inl.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2012, Google Inc.
-// All rights reserved.
+// Copyright 2012 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/common/linux/elfutils.cc b/src/common/linux/elfutils.cc
index 9532d5ad..a68cc0af 100644
--- a/src/common/linux/elfutils.cc
+++ b/src/common/linux/elfutils.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2012, Google Inc.
-// All rights reserved.
+// Copyright 2012 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -40,11 +39,11 @@ namespace google_breakpad {
namespace {
template<typename ElfClass>
-void FindElfClassSection(const char *elf_base,
- const char *section_name,
+void FindElfClassSection(const char* elf_base,
+ const char* section_name,
typename ElfClass::Word section_type,
- const void **section_start,
- size_t *section_size) {
+ const void** section_start,
+ size_t* section_size) {
typedef typename ElfClass::Ehdr Ehdr;
typedef typename ElfClass::Shdr Shdr;
@@ -57,12 +56,18 @@ void FindElfClassSection(const char *elf_base,
const Ehdr* elf_header = reinterpret_cast<const Ehdr*>(elf_base);
assert(elf_header->e_ident[EI_CLASS] == ElfClass::kClass);
+ if (elf_header->e_shoff == 0) {
+ *section_start = NULL;
+ *section_size = 0;
+ return;
+ }
+
const Shdr* sections =
GetOffset<ElfClass, Shdr>(elf_header, elf_header->e_shoff);
const Shdr* section_names = sections + elf_header->e_shstrndx;
const char* names =
GetOffset<ElfClass, char>(elf_header, section_names->sh_offset);
- const char *names_end = names + section_names->sh_size;
+ const char* names_end = names + section_names->sh_size;
const Shdr* section =
FindElfSectionByName<ElfClass>(section_name, section_type,
@@ -76,9 +81,9 @@ void FindElfClassSection(const char *elf_base,
}
template<typename ElfClass>
-void FindElfClassSegment(const char *elf_base,
+void FindElfClassSegment(const char* elf_base,
typename ElfClass::Word segment_type,
- wasteful_vector<ElfSegment> *segments) {
+ wasteful_vector<ElfSegment>* segments) {
typedef typename ElfClass::Ehdr Ehdr;
typedef typename ElfClass::Phdr Phdr;
@@ -117,11 +122,11 @@ int ElfClass(const void* elf_base) {
return elf_header->e_ident[EI_CLASS];
}
-bool FindElfSection(const void *elf_mapped_base,
- const char *section_name,
+bool FindElfSection(const void* elf_mapped_base,
+ const char* section_name,
uint32_t section_type,
- const void **section_start,
- size_t *section_size) {
+ const void** section_start,
+ size_t* section_size) {
assert(elf_mapped_base);
assert(section_start);
assert(section_size);
diff --git a/src/common/linux/elfutils.h b/src/common/linux/elfutils.h
index aefb6cf5..130a8ac1 100644
--- a/src/common/linux/elfutils.h
+++ b/src/common/linux/elfutils.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2012, Google Inc.
-// All rights reserved.
+// Copyright 2012 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -41,6 +40,39 @@
namespace google_breakpad {
+typedef struct Elf32_Chdr {
+ typedef Elf32_Word Type;
+ typedef Elf32_Word Size;
+ typedef Elf32_Addr Addr;
+
+ static_assert(sizeof (Type) == 4);
+ static_assert(sizeof (Size) == 4);
+ static_assert(sizeof (Addr) == 4);
+
+ Type ch_type; // Compression type
+ Size ch_size; // Uncompressed data size in bytes
+ Addr ch_addralign; // Uncompressed data alignment
+} Elf32_Chdr;
+
+static_assert(sizeof (Elf32_Chdr) == 12);
+
+typedef struct Elf64_Chdr {
+ typedef Elf64_Word Type;
+ typedef Elf64_Xword Size;
+ typedef Elf64_Addr Addr;
+
+ static_assert(sizeof (Type) == 4);
+ static_assert(sizeof (Size) == 8);
+ static_assert(sizeof (Addr) == 8);
+
+ Type ch_type; // Compression type
+ Type ch_reserved; // Padding
+ Size ch_size; // Uncompressed data size in bytes
+ Addr ch_addralign; // Uncompressed data alignment
+} Elf64_Chdr;
+
+static_assert(sizeof (Elf64_Chdr) == 24);
+
// Traits classes so consumers can write templatized code to deal
// with specific ELF bits.
struct ElfClass32 {
@@ -50,6 +82,7 @@ struct ElfClass32 {
typedef Elf32_Nhdr Nhdr;
typedef Elf32_Phdr Phdr;
typedef Elf32_Shdr Shdr;
+ typedef Elf32_Chdr Chdr;
typedef Elf32_Half Half;
typedef Elf32_Off Off;
typedef Elf32_Sym Sym;
@@ -68,6 +101,7 @@ struct ElfClass64 {
typedef Elf64_Nhdr Nhdr;
typedef Elf64_Phdr Phdr;
typedef Elf64_Shdr Shdr;
+ typedef Elf64_Chdr Chdr;
typedef Elf64_Half Half;
typedef Elf64_Off Off;
typedef Elf64_Sym Sym;
@@ -86,11 +120,11 @@ int ElfClass(const void* elf_base);
// in the ELF binary data at |elf_mapped_base|. On success, returns true
// and sets |*section_start| to point to the start of the section data,
// and |*section_size| to the size of the section's data.
-bool FindElfSection(const void *elf_mapped_base,
- const char *section_name,
+bool FindElfSection(const void* elf_mapped_base,
+ const char* section_name,
uint32_t section_type,
- const void **section_start,
- size_t *section_size);
+ const void** section_start,
+ size_t* section_size);
// Internal helper method, exposed for convenience for callers
// that already have more info.
diff --git a/src/common/linux/file_id.cc b/src/common/linux/file_id.cc
index 67921c45..0bd2a759 100644
--- a/src/common/linux/file_id.cc
+++ b/src/common/linux/file_id.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2006, Google Inc.
-// All rights reserved.
+// Copyright 2006 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -49,6 +48,7 @@
#include "third_party/lss/linux_syscall_support.h"
namespace google_breakpad {
+namespace elf {
// Used in a few places for backwards-compatibility.
const size_t kMDGUIDSize = sizeof(MDGUID);
@@ -61,7 +61,7 @@ FileID::FileID(const char* path) : path_(path) {}
// These functions are also used inside the crashed process, so be safe
// and use the syscall/libc wrappers instead of direct syscalls or libc.
-static bool ElfClassBuildIDNoteIdentifier(const void *section, size_t length,
+static bool ElfClassBuildIDNoteIdentifier(const void* section, size_t length,
wasteful_vector<uint8_t>& identifier) {
static_assert(sizeof(ElfClass32::Nhdr) == sizeof(ElfClass64::Nhdr),
"Elf32_Nhdr and Elf64_Nhdr should be the same");
@@ -69,7 +69,7 @@ static bool ElfClassBuildIDNoteIdentifier(const void *section, size_t length,
const void* section_end = reinterpret_cast<const char*>(section) + length;
const Nhdr* note_header = reinterpret_cast<const Nhdr*>(section);
- while (reinterpret_cast<const void *>(note_header) < section_end) {
+ while (reinterpret_cast<const void*>(note_header) < section_end) {
if (note_header->n_type == NT_GNU_BUILD_ID)
break;
note_header = reinterpret_cast<const Nhdr*>(
@@ -77,7 +77,7 @@ static bool ElfClassBuildIDNoteIdentifier(const void *section, size_t length,
NOTE_PADDING(note_header->n_namesz) +
NOTE_PADDING(note_header->n_descsz));
}
- if (reinterpret_cast<const void *>(note_header) >= section_end ||
+ if (reinterpret_cast<const void*>(note_header) >= section_end ||
note_header->n_descsz == 0) {
return false;
}
@@ -198,4 +198,5 @@ string FileID::ConvertIdentifierToString(
return bytes_to_hex_string(&identifier[0], identifier.size());
}
+} // elf
} // namespace google_breakpad
diff --git a/src/common/linux/file_id.h b/src/common/linux/file_id.h
index 4aff021d..8e58d56e 100644
--- a/src/common/linux/file_id.h
+++ b/src/common/linux/file_id.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2006, Google Inc.
-// All rights reserved.
+// Copyright 2006 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -41,6 +40,7 @@
#include "common/using_std_string.h"
namespace google_breakpad {
+namespace elf {
// GNU binutils' ld defaults to 'sha1', which is 160 bits == 20 bytes,
// so this is enough to fit that, which most binaries will use.
@@ -83,6 +83,7 @@ class FileID {
string path_;
};
+} // namespace elf
} // namespace google_breakpad
#endif // COMMON_LINUX_FILE_ID_H__
diff --git a/src/common/linux/file_id_unittest.cc b/src/common/linux/file_id_unittest.cc
index f4f9ac45..74bf9e1b 100644
--- a/src/common/linux/file_id_unittest.cc
+++ b/src/common/linux/file_id_unittest.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2010, Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -30,7 +29,10 @@
// Unit tests for FileID
#include <elf.h>
+#include <spawn.h>
#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/wait.h>
#include <string>
#include <vector>
@@ -42,10 +44,13 @@
#include "common/linux/synth_elf.h"
#include "common/test_assembler.h"
#include "common/tests/auto_tempdir.h"
+#include "common/tests/file_utils.h"
#include "common/using_std_string.h"
#include "breakpad_googletest_includes.h"
using namespace google_breakpad;
+using google_breakpad::elf::FileID;
+using google_breakpad::elf::kDefaultBuildIdSize;
using google_breakpad::synth_elf::ELF;
using google_breakpad::synth_elf::Notes;
using google_breakpad::test_assembler::kLittleEndian;
@@ -80,13 +85,18 @@ TEST(FileIDStripTest, StripSelf) {
// copy our binary to a temp file, and strip it
AutoTempDir temp_dir;
string templ = temp_dir.path() + "/file-id-unittest";
- char cmdline[4096];
- sprintf(cmdline, "cp \"%s\" \"%s\"", exe_name, templ.c_str());
- ASSERT_EQ(0, system(cmdline)) << "Failed to execute: " << cmdline;
- sprintf(cmdline, "chmod u+w \"%s\"", templ.c_str());
- ASSERT_EQ(0, system(cmdline)) << "Failed to execute: " << cmdline;
- sprintf(cmdline, "strip \"%s\"", templ.c_str());
- ASSERT_EQ(0, system(cmdline)) << "Failed to execute: " << cmdline;
+ ASSERT_TRUE(CopyFile(exe_name, templ));
+ pid_t pid;
+ char* argv[] = {
+ const_cast<char*>("strip"),
+ const_cast<char*>(templ.c_str()),
+ nullptr,
+ };
+ ASSERT_EQ(0, posix_spawnp(&pid, argv[0], nullptr, nullptr, argv, nullptr));
+ int status;
+ ASSERT_EQ(pid, waitpid(pid, &status, 0));
+ ASSERT_TRUE(WIFEXITED(status));
+ ASSERT_EQ(0, WEXITSTATUS(status));
PageAllocator allocator;
id_vector identifier1(&allocator, kDefaultBuildIdSize);
@@ -261,7 +271,7 @@ TYPED_TEST(FileIDTest, BuildIDPH) {
elf.AddSection(".text", text, SHT_PROGBITS);
Notes notes(kLittleEndian);
notes.AddNote(0, "Linux",
- reinterpret_cast<const uint8_t *>("\0x42\0x02\0\0"), 4);
+ reinterpret_cast<const uint8_t*>("\0x42\0x02\0\0"), 4);
notes.AddNote(NT_GNU_BUILD_ID, "GNU", kExpectedIdentifierBytes,
sizeof(kExpectedIdentifierBytes));
int note_idx = elf.AddSection(".note", notes, SHT_NOTE);
@@ -292,7 +302,7 @@ TYPED_TEST(FileIDTest, BuildIDMultiplePH) {
elf.AddSection(".text", text, SHT_PROGBITS);
Notes notes1(kLittleEndian);
notes1.AddNote(0, "Linux",
- reinterpret_cast<const uint8_t *>("\0x42\0x02\0\0"), 4);
+ reinterpret_cast<const uint8_t*>("\0x42\0x02\0\0"), 4);
Notes notes2(kLittleEndian);
notes2.AddNote(NT_GNU_BUILD_ID, "GNU", kExpectedIdentifierBytes,
sizeof(kExpectedIdentifierBytes));
diff --git a/src/common/linux/google_crashdump_uploader.cc b/src/common/linux/google_crashdump_uploader.cc
index a0d940b6..6242e6d2 100644
--- a/src/common/linux/google_crashdump_uploader.cc
+++ b/src/common/linux/google_crashdump_uploader.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2009, Google Inc.
-// All rights reserved.
+// Copyright 2009 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -35,6 +34,7 @@
#include <unistd.h>
#include <iostream>
+#include <utility>
#include "common/using_std_string.h"
@@ -51,7 +51,7 @@ GoogleCrashdumpUploader::GoogleCrashdumpUploader(const string& product,
const string& crash_server,
const string& proxy_host,
const string& proxy_userpassword) {
- LibcurlWrapper* http_layer = new LibcurlWrapper();
+ std::unique_ptr<LibcurlWrapper> http_layer{new LibcurlWrapper()};
Init(product,
version,
guid,
@@ -63,21 +63,22 @@ GoogleCrashdumpUploader::GoogleCrashdumpUploader(const string& product,
crash_server,
proxy_host,
proxy_userpassword,
- http_layer);
+ std::move(http_layer));
}
-GoogleCrashdumpUploader::GoogleCrashdumpUploader(const string& product,
- const string& version,
- const string& guid,
- const string& ptime,
- const string& ctime,
- const string& email,
- const string& comments,
- const string& minidump_pathname,
- const string& crash_server,
- const string& proxy_host,
- const string& proxy_userpassword,
- LibcurlWrapper* http_layer) {
+GoogleCrashdumpUploader::GoogleCrashdumpUploader(
+ const string& product,
+ const string& version,
+ const string& guid,
+ const string& ptime,
+ const string& ctime,
+ const string& email,
+ const string& comments,
+ const string& minidump_pathname,
+ const string& crash_server,
+ const string& proxy_host,
+ const string& proxy_userpassword,
+ std::unique_ptr<LibcurlWrapper> http_layer) {
Init(product,
version,
guid,
@@ -89,7 +90,7 @@ GoogleCrashdumpUploader::GoogleCrashdumpUploader(const string& product,
crash_server,
proxy_host,
proxy_userpassword,
- http_layer);
+ std::move(http_layer));
}
void GoogleCrashdumpUploader::Init(const string& product,
@@ -103,7 +104,7 @@ void GoogleCrashdumpUploader::Init(const string& product,
const string& crash_server,
const string& proxy_host,
const string& proxy_userpassword,
- LibcurlWrapper* http_layer) {
+ std::unique_ptr<LibcurlWrapper> http_layer) {
product_ = product;
version_ = version;
guid_ = guid;
@@ -111,7 +112,7 @@ void GoogleCrashdumpUploader::Init(const string& product,
ctime_ = ctime;
email_ = email;
comments_ = comments;
- http_layer_.reset(http_layer);
+ http_layer_ = std::move(http_layer);
crash_server_ = crash_server;
proxy_host_ = proxy_host;
diff --git a/src/common/linux/google_crashdump_uploader.h b/src/common/linux/google_crashdump_uploader.h
index a2d0575b..74b5e1be 100644
--- a/src/common/linux/google_crashdump_uploader.h
+++ b/src/common/linux/google_crashdump_uploader.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2009, Google Inc.
-// All rights reserved.
+// Copyright 2009 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -31,11 +30,11 @@
#ifndef COMMON_LINUX_GOOGLE_CRASHDUMP_UPLOADER_H_
#define COMMON_LINUX_GOOGLE_CRASHDUMP_UPLOADER_H_
-#include <string>
#include <map>
+#include <memory>
+#include <string>
#include "common/linux/libcurl_wrapper.h"
-#include "common/scoped_ptr.h"
#include "common/using_std_string.h"
namespace google_breakpad {
@@ -65,7 +64,7 @@ class GoogleCrashdumpUploader {
const string& crash_server,
const string& proxy_host,
const string& proxy_userpassword,
- LibcurlWrapper* http_layer);
+ std::unique_ptr<LibcurlWrapper> http_layer);
void Init(const string& product,
const string& version,
@@ -78,7 +77,7 @@ class GoogleCrashdumpUploader {
const string& crash_server,
const string& proxy_host,
const string& proxy_userpassword,
- LibcurlWrapper* http_layer);
+ std::unique_ptr<LibcurlWrapper> http_layer);
bool Upload(int* http_status_code,
string* http_response_header,
string* http_response_body);
@@ -86,7 +85,7 @@ class GoogleCrashdumpUploader {
private:
bool CheckRequiredParametersArePresent();
- scoped_ptr<LibcurlWrapper> http_layer_;
+ std::unique_ptr<LibcurlWrapper> http_layer_;
string product_;
string version_;
string guid_;
diff --git a/src/common/linux/google_crashdump_uploader_test.cc b/src/common/linux/google_crashdump_uploader_test.cc
index 3d6612e8..39aab65d 100644
--- a/src/common/linux/google_crashdump_uploader_test.cc
+++ b/src/common/linux/google_crashdump_uploader_test.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2009, Google Inc.
-// All rights reserved.
+// Copyright 2009 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -59,21 +58,12 @@ class GoogleCrashdumpUploaderTest : public ::testing::Test {
};
TEST_F(GoogleCrashdumpUploaderTest, InitFailsCausesUploadFailure) {
- MockLibcurlWrapper m;
- EXPECT_CALL(m, Init()).Times(1).WillOnce(Return(false));
- GoogleCrashdumpUploader *uploader = new GoogleCrashdumpUploader("foobar",
- "1.0",
- "AAA-BBB",
- "",
- "",
- "test@test.com",
- "none",
- "/tmp/foo.dmp",
- "http://foo.com",
- "",
- "",
- &m);
- ASSERT_FALSE(uploader->Upload(NULL, NULL, NULL));
+ std::unique_ptr<MockLibcurlWrapper> m{new MockLibcurlWrapper()};
+ EXPECT_CALL(*m, Init()).Times(1).WillOnce(Return(false));
+ GoogleCrashdumpUploader uploader("foobar", "1.0", "AAA-BBB", "", "",
+ "test@test.com", "none", "/tmp/foo.dmp",
+ "http://foo.com", "", "", std::move(m));
+ ASSERT_FALSE(uploader.Upload(NULL, NULL, NULL));
}
TEST_F(GoogleCrashdumpUploaderTest, TestSendRequestHappensWithValidParameters) {
@@ -83,44 +73,27 @@ TEST_F(GoogleCrashdumpUploaderTest, TestSendRequestHappensWithValidParameters) {
ASSERT_NE(fd, -1);
close(fd);
- MockLibcurlWrapper m;
- EXPECT_CALL(m, Init()).Times(1).WillOnce(Return(true));
- EXPECT_CALL(m, AddFile(tempfn, _)).WillOnce(Return(true));
- EXPECT_CALL(m,
- SendRequest("http://foo.com",_,_,_,_)).Times(1).WillOnce(Return(true));
- GoogleCrashdumpUploader *uploader = new GoogleCrashdumpUploader("foobar",
- "1.0",
- "AAA-BBB",
- "",
- "",
- "test@test.com",
- "none",
- tempfn,
- "http://foo.com",
- "",
- "",
- &m);
- ASSERT_TRUE(uploader->Upload(NULL, NULL, NULL));
+ std::unique_ptr<MockLibcurlWrapper> m{new MockLibcurlWrapper()};
+ EXPECT_CALL(*m, Init()).Times(1).WillOnce(Return(true));
+ EXPECT_CALL(*m, AddFile(tempfn, _)).WillOnce(Return(true));
+ EXPECT_CALL(*m, SendRequest("http://foo.com", _, _, _, _))
+ .Times(1)
+ .WillOnce(Return(true));
+ GoogleCrashdumpUploader uploader("foobar", "1.0", "AAA-BBB", "", "",
+ "test@test.com", "none", tempfn,
+ "http://foo.com", "", "", std::move(m));
+ ASSERT_TRUE(uploader.Upload(NULL, NULL, NULL));
}
TEST_F(GoogleCrashdumpUploaderTest, InvalidPathname) {
- MockLibcurlWrapper m;
- EXPECT_CALL(m, Init()).Times(1).WillOnce(Return(true));
- EXPECT_CALL(m, SendRequest(_,_,_,_,_)).Times(0);
- GoogleCrashdumpUploader *uploader = new GoogleCrashdumpUploader("foobar",
- "1.0",
- "AAA-BBB",
- "",
- "",
- "test@test.com",
- "none",
- "/tmp/foo.dmp",
- "http://foo.com",
- "",
- "",
- &m);
- ASSERT_FALSE(uploader->Upload(NULL, NULL, NULL));
+ std::unique_ptr<MockLibcurlWrapper> m{new MockLibcurlWrapper()};
+ EXPECT_CALL(*m, Init()).Times(1).WillOnce(Return(true));
+ EXPECT_CALL(*m, SendRequest(_,_,_,_,_)).Times(0);
+ GoogleCrashdumpUploader uploader("foobar", "1.0", "AAA-BBB", "", "",
+ "test@test.com", "none", "/tmp/foo.dmp",
+ "http://foo.com", "", "", std::move(m));
+ ASSERT_FALSE(uploader.Upload(NULL, NULL, NULL));
}
TEST_F(GoogleCrashdumpUploaderTest, TestRequiredParametersMustBePresent) {
diff --git a/src/common/linux/guid_creator.cc b/src/common/linux/guid_creator.cc
index 03e3d781..31a326c7 100644
--- a/src/common/linux/guid_creator.cc
+++ b/src/common/linux/guid_creator.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2006, Google Inc.
-// All rights reserved.
+// Copyright 2006 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -105,7 +104,7 @@ class GUIDGenerator {
private:
#ifdef HAVE_ARC4RANDOM
static void CreateGuidFromArc4Random(GUID *guid) {
- char *buf = reinterpret_cast<char *>(guid);
+ char *buf = reinterpret_cast<char*>(guid);
for (size_t i = 0; i < sizeof(GUID); i += sizeof(uint32_t)) {
uint32_t random_data = arc4random();
@@ -129,7 +128,7 @@ class GUIDGenerator {
#if defined(HAVE_SYS_RANDOM_H) && defined(HAVE_GETRANDOM)
static bool CreateGUIDFromGetrandom(GUID *guid) {
- char *buf = reinterpret_cast<char *>(guid);
+ char *buf = reinterpret_cast<char*>(guid);
int read_bytes = getrandom(buf, sizeof(GUID), GRND_NONBLOCK);
return (read_bytes == static_cast<int>(sizeof(GUID)));
@@ -139,7 +138,7 @@ class GUIDGenerator {
// Populate the GUID using random bytes read from /dev/urandom, returns false
// if the GUID wasn't fully populated with random data.
static bool CreateGUIDFromDevUrandom(GUID *guid) {
- char *buf = reinterpret_cast<char *>(guid);
+ char *buf = reinterpret_cast<char*>(guid);
int fd = open("/dev/urandom", O_RDONLY | O_CLOEXEC);
if (fd == -1) {
@@ -154,7 +153,7 @@ class GUIDGenerator {
// Populate the GUID using a stream of random bytes obtained from rand().
static void CreateGUIDFromRand(GUID *guid) {
- char *buf = reinterpret_cast<char *>(guid);
+ char *buf = reinterpret_cast<char*>(guid);
InitOnce();
diff --git a/src/common/linux/guid_creator.h b/src/common/linux/guid_creator.h
index c86d856c..c02f5552 100644
--- a/src/common/linux/guid_creator.h
+++ b/src/common/linux/guid_creator.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2006, Google Inc.
-// All rights reserved.
+// Copyright 2006 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/common/linux/http_upload.cc b/src/common/linux/http_upload.cc
index 702526af..1b576ea6 100644
--- a/src/common/linux/http_upload.cc
+++ b/src/common/linux/http_upload.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2006, Google Inc.
-// All rights reserved.
+// Copyright 2006 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -36,14 +35,14 @@
namespace {
// Callback to get the response data from server.
-static size_t WriteCallback(void *ptr, size_t size,
- size_t nmemb, void *userp) {
+static size_t WriteCallback(void* ptr, size_t size,
+ size_t nmemb, void* userp) {
if (!userp)
return 0;
- string *response = reinterpret_cast<string *>(userp);
+ string* response = reinterpret_cast<string*>(userp);
size_t real_size = size * nmemb;
- response->append(reinterpret_cast<char *>(ptr), real_size);
+ response->append(reinterpret_cast<char*>(ptr), real_size);
return real_size;
}
@@ -54,15 +53,15 @@ namespace google_breakpad {
static const char kUserAgent[] = "Breakpad/1.0 (Linux)";
// static
-bool HTTPUpload::SendRequest(const string &url,
- const map<string, string> &parameters,
- const map<string, string> &files,
- const string &proxy,
- const string &proxy_user_pwd,
- const string &ca_certificate_file,
- string *response_body,
- long *response_code,
- string *error_description) {
+bool HTTPUpload::SendRequest(const string& url,
+ const map<string, string>& parameters,
+ const map<string, string>& files,
+ const string& proxy,
+ const string& proxy_user_pwd,
+ const string& ca_certificate_file,
+ string* response_body,
+ long* response_code,
+ string* error_description) {
if (response_code != NULL)
*response_code = 0;
@@ -101,7 +100,7 @@ bool HTTPUpload::SendRequest(const string &url,
CURL* (*curl_easy_init)(void);
*(void**) (&curl_easy_init) = dlsym(curl_lib, "curl_easy_init");
- CURL *curl = (*curl_easy_init)();
+ CURL* curl = (*curl_easy_init)();
if (error_description != NULL)
*error_description = "No Error";
@@ -111,7 +110,7 @@ bool HTTPUpload::SendRequest(const string &url,
}
CURLcode err_code = CURLE_OK;
- CURLcode (*curl_easy_setopt)(CURL *, CURLoption, ...);
+ CURLcode (*curl_easy_setopt)(CURL*, CURLoption, ...);
*(void**) (&curl_easy_setopt) = dlsym(curl_lib, "curl_easy_setopt");
(*curl_easy_setopt)(curl, CURLOPT_URL, url.c_str());
(*curl_easy_setopt)(curl, CURLOPT_USERAGENT, kUserAgent);
@@ -128,10 +127,10 @@ bool HTTPUpload::SendRequest(const string &url,
if (!ca_certificate_file.empty())
(*curl_easy_setopt)(curl, CURLOPT_CAINFO, ca_certificate_file.c_str());
- struct curl_httppost *formpost = NULL;
- struct curl_httppost *lastptr = NULL;
+ struct curl_httppost* formpost = NULL;
+ struct curl_httppost* lastptr = NULL;
// Add form data.
- CURLFORMcode (*curl_formadd)(struct curl_httppost **, struct curl_httppost **, ...);
+ CURLFORMcode (*curl_formadd)(struct curl_httppost**, struct curl_httppost**, ...);
*(void**) (&curl_formadd) = dlsym(curl_lib, "curl_formadd");
map<string, string>::const_iterator iter = parameters.begin();
for (; iter != parameters.end(); ++iter)
@@ -151,9 +150,9 @@ bool HTTPUpload::SendRequest(const string &url,
(*curl_easy_setopt)(curl, CURLOPT_HTTPPOST, formpost);
// Disable 100-continue header.
- struct curl_slist *headerlist = NULL;
+ struct curl_slist* headerlist = NULL;
char buf[] = "Expect:";
- struct curl_slist* (*curl_slist_append)(struct curl_slist *, const char *);
+ struct curl_slist* (*curl_slist_append)(struct curl_slist*, const char*);
*(void**) (&curl_slist_append) = dlsym(curl_lib, "curl_slist_append");
headerlist = (*curl_slist_append)(headerlist, buf);
(*curl_easy_setopt)(curl, CURLOPT_HTTPHEADER, headerlist);
@@ -161,17 +160,17 @@ bool HTTPUpload::SendRequest(const string &url,
if (response_body != NULL) {
(*curl_easy_setopt)(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
(*curl_easy_setopt)(curl, CURLOPT_WRITEDATA,
- reinterpret_cast<void *>(response_body));
+ reinterpret_cast<void*>(response_body));
}
// Fail if 400+ is returned from the web server.
(*curl_easy_setopt)(curl, CURLOPT_FAILONERROR, 1);
- CURLcode (*curl_easy_perform)(CURL *);
+ CURLcode (*curl_easy_perform)(CURL*);
*(void**) (&curl_easy_perform) = dlsym(curl_lib, "curl_easy_perform");
err_code = (*curl_easy_perform)(curl);
if (response_code != NULL) {
- CURLcode (*curl_easy_getinfo)(CURL *, CURLINFO, ...);
+ CURLcode (*curl_easy_getinfo)(CURL*, CURLINFO, ...);
*(void**) (&curl_easy_getinfo) = dlsym(curl_lib, "curl_easy_getinfo");
(*curl_easy_getinfo)(curl, CURLINFO_RESPONSE_CODE, response_code);
}
@@ -186,16 +185,16 @@ bool HTTPUpload::SendRequest(const string &url,
if (error_description != NULL)
*error_description = (*curl_easy_strerror)(err_code);
- void (*curl_easy_cleanup)(CURL *);
+ void (*curl_easy_cleanup)(CURL*);
*(void**) (&curl_easy_cleanup) = dlsym(curl_lib, "curl_easy_cleanup");
(*curl_easy_cleanup)(curl);
if (formpost != NULL) {
- void (*curl_formfree)(struct curl_httppost *);
+ void (*curl_formfree)(struct curl_httppost*);
*(void**) (&curl_formfree) = dlsym(curl_lib, "curl_formfree");
(*curl_formfree)(formpost);
}
if (headerlist != NULL) {
- void (*curl_slist_free_all)(struct curl_slist *);
+ void (*curl_slist_free_all)(struct curl_slist*);
*(void**) (&curl_slist_free_all) = dlsym(curl_lib, "curl_slist_free_all");
(*curl_slist_free_all)(headerlist);
}
@@ -211,10 +210,10 @@ bool HTTPUpload::CheckCurlLib(void* curl_lib) {
}
// static
-bool HTTPUpload::CheckParameters(const map<string, string> &parameters) {
+bool HTTPUpload::CheckParameters(const map<string, string>& parameters) {
for (map<string, string>::const_iterator pos = parameters.begin();
pos != parameters.end(); ++pos) {
- const string &str = pos->first;
+ const string& str = pos->first;
if (str.size() == 0)
return false; // disallow empty parameter names
for (unsigned int i = 0; i < str.size(); ++i) {
diff --git a/src/common/linux/http_upload.h b/src/common/linux/http_upload.h
index bc1d5d57..b7e557a0 100644
--- a/src/common/linux/http_upload.h
+++ b/src/common/linux/http_upload.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2006, Google Inc.
-// All rights reserved.
+// Copyright 2006 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -58,21 +57,21 @@ class HTTPUpload {
// received (or 0 if the request failed before getting an HTTP response).
// If the send fails, a description of the error will be
// returned in error_description.
- static bool SendRequest(const string &url,
- const map<string, string> &parameters,
- const map<string, string> &files,
- const string &proxy,
- const string &proxy_user_pwd,
- const string &ca_certificate_file,
- string *response_body,
- long *response_code,
- string *error_description);
+ static bool SendRequest(const string& url,
+ const map<string, string>& parameters,
+ const map<string, string>& files,
+ const string& proxy,
+ const string& proxy_user_pwd,
+ const string& ca_certificate_file,
+ string* response_body,
+ long* response_code,
+ string* error_description);
private:
// Checks that the given list of parameters has only printable
// ASCII characters in the parameter name, and does not contain
// any quote (") characters. Returns true if so.
- static bool CheckParameters(const map<string, string> &parameters);
+ static bool CheckParameters(const map<string, string>& parameters);
// Checks the curl_lib parameter points to a valid curl lib.
static bool CheckCurlLib(void* curl_lib);
@@ -80,8 +79,8 @@ class HTTPUpload {
// No instances of this class should be created.
// Disallow all constructors, destructors, and operator=.
HTTPUpload();
- explicit HTTPUpload(const HTTPUpload &);
- void operator=(const HTTPUpload &);
+ explicit HTTPUpload(const HTTPUpload&);
+ void operator=(const HTTPUpload&);
~HTTPUpload();
};
diff --git a/src/common/linux/ignore_ret.h b/src/common/linux/ignore_ret.h
index efd274c2..1f879e8f 100644
--- a/src/common/linux/ignore_ret.h
+++ b/src/common/linux/ignore_ret.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2012 Google Inc.
-// All rights reserved.
+// Copyright 2012 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/common/linux/libcurl_wrapper.cc b/src/common/linux/libcurl_wrapper.cc
index e96c2038..a53087d9 100644
--- a/src/common/linux/libcurl_wrapper.cc
+++ b/src/common/linux/libcurl_wrapper.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2009, Google Inc.
-// All rights reserved.
+// Copyright 2009 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -48,6 +47,7 @@ LibcurlWrapper::LibcurlWrapper()
LibcurlWrapper::~LibcurlWrapper() {
if (init_ok_) {
(*easy_cleanup_)(curl_);
+ (*global_cleanup_)();
dlclose(curl_lib_);
}
}
@@ -88,14 +88,14 @@ bool LibcurlWrapper::AddFile(const string& upload_file_path,
}
// Callback to get the response data from server.
-static size_t WriteCallback(void *ptr, size_t size,
- size_t nmemb, void *userp) {
+static size_t WriteCallback(void* ptr, size_t size,
+ size_t nmemb, void* userp) {
if (!userp)
return 0;
- string *response = reinterpret_cast<string *>(userp);
+ string* response = reinterpret_cast<string*>(userp);
size_t real_size = size * nmemb;
- response->append(reinterpret_cast<char *>(ptr), real_size);
+ response->append(reinterpret_cast<char*>(ptr), real_size);
return real_size;
}
@@ -250,7 +250,7 @@ bool LibcurlWrapper::SetFunctionPointers() {
SET_AND_CHECK_FUNCTION_POINTER(easy_getinfo_,
"curl_easy_getinfo",
- CURLcode(*)(CURL *, CURLINFO info, ...));
+ CURLcode(*)(CURL*, CURLINFO info, ...));
SET_AND_CHECK_FUNCTION_POINTER(easy_reset_,
"curl_easy_reset",
@@ -263,6 +263,10 @@ bool LibcurlWrapper::SetFunctionPointers() {
SET_AND_CHECK_FUNCTION_POINTER(formfree_,
"curl_formfree",
void(*)(curl_httppost*));
+
+ SET_AND_CHECK_FUNCTION_POINTER(global_cleanup_,
+ "curl_global_cleanup",
+ void(*)(void));
return true;
}
diff --git a/src/common/linux/libcurl_wrapper.h b/src/common/linux/libcurl_wrapper.h
index 77aa6cbb..f8f961c1 100644
--- a/src/common/linux/libcurl_wrapper.h
+++ b/src/common/linux/libcurl_wrapper.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2009, Google Inc.
-// All rights reserved.
+// Copyright 2009 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -40,6 +39,9 @@
#include "third_party/curl/curl.h"
namespace google_breakpad {
+
+// This class is only safe to be used on single-threaded code because of its
+// usage of libcurl's curl_global_cleanup().
class LibcurlWrapper {
public:
LibcurlWrapper();
@@ -91,27 +93,28 @@ class LibcurlWrapper {
// dealing
// with CURL.
- CURL *curl_; // Pointer for handle for CURL calls.
+ CURL* curl_; // Pointer for handle for CURL calls.
CURL* (*easy_init_)(void);
// Stateful pointers for calling into curl_formadd()
- struct curl_httppost *formpost_;
- struct curl_httppost *lastptr_;
- struct curl_slist *headerlist_;
+ struct curl_httppost* formpost_;
+ struct curl_httppost* lastptr_;
+ struct curl_slist* headerlist_;
// Function pointers into CURL library
- CURLcode (*easy_setopt_)(CURL *, CURLoption, ...);
- CURLFORMcode (*formadd_)(struct curl_httppost **,
- struct curl_httppost **, ...);
- struct curl_slist* (*slist_append_)(struct curl_slist *, const char *);
- void (*slist_free_all_)(struct curl_slist *);
- CURLcode (*easy_perform_)(CURL *);
+ CURLcode (*easy_setopt_)(CURL*, CURLoption, ...);
+ CURLFORMcode (*formadd_)(struct curl_httppost**,
+ struct curl_httppost**, ...);
+ struct curl_slist* (*slist_append_)(struct curl_slist*, const char*);
+ void (*slist_free_all_)(struct curl_slist*);
+ CURLcode (*easy_perform_)(CURL*);
const char* (*easy_strerror_)(CURLcode);
- void (*easy_cleanup_)(CURL *);
- CURLcode (*easy_getinfo_)(CURL *, CURLINFO info, ...);
+ void (*easy_cleanup_)(CURL*);
+ CURLcode (*easy_getinfo_)(CURL*, CURLINFO info, ...);
void (*easy_reset_)(CURL*);
- void (*formfree_)(struct curl_httppost *);
+ void (*formfree_)(struct curl_httppost*);
+ void (*global_cleanup_)(void);
};
}
diff --git a/src/common/linux/linux_libc_support.cc b/src/common/linux/linux_libc_support.cc
index 08b0325e..10cbeaef 100644
--- a/src/common/linux/linux_libc_support.cc
+++ b/src/common/linux/linux_libc_support.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2012, Google Inc.
-// All rights reserved.
+// Copyright 2012 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -190,7 +189,7 @@ const char* my_read_decimal_ptr(uintptr_t* result, const char* s) {
}
void my_memset(void* ip, char c, size_t len) {
- char* p = (char *) ip;
+ char* p = (char*) ip;
while (len--)
*p++ = c;
}
diff --git a/src/common/linux/linux_libc_support.h b/src/common/linux/linux_libc_support.h
index ec5a8d6b..05e2aa24 100644
--- a/src/common/linux/linux_libc_support.h
+++ b/src/common/linux/linux_libc_support.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2009, Google Inc.
-// All rights reserved.
+// Copyright 2009 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/common/linux/linux_libc_support_unittest.cc b/src/common/linux/linux_libc_support_unittest.cc
index adadfed4..449f995f 100644
--- a/src/common/linux/linux_libc_support_unittest.cc
+++ b/src/common/linux/linux_libc_support_unittest.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2009, Google Inc.
-// All rights reserved.
+// Copyright 2009 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/common/linux/memory_mapped_file.cc b/src/common/linux/memory_mapped_file.cc
index 4e938269..7e444607 100644
--- a/src/common/linux/memory_mapped_file.cc
+++ b/src/common/linux/memory_mapped_file.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2011, Google Inc.
-// All rights reserved.
+// Copyright 2011 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -65,7 +64,8 @@ bool MemoryMappedFile::Map(const char* path, size_t offset) {
}
#if defined(__x86_64__) || defined(__aarch64__) || \
- (defined(__mips__) && _MIPS_SIM == _ABI64)
+ (defined(__mips__) && _MIPS_SIM == _ABI64) || \
+ (defined(__riscv) && __riscv_xlen == 64)
struct kernel_stat st;
if (sys_fstat(fd, &st) == -1 || st.st_size < 0) {
@@ -87,13 +87,14 @@ bool MemoryMappedFile::Map(const char* path, size_t offset) {
return true;
}
- void* data = sys_mmap(NULL, file_len, PROT_READ, MAP_PRIVATE, fd, offset);
+ size_t content_len = file_len - offset;
+ void* data = sys_mmap(NULL, content_len, PROT_READ, MAP_PRIVATE, fd, offset);
sys_close(fd);
if (data == MAP_FAILED) {
return false;
}
- content_.Set(data, file_len - offset);
+ content_.Set(data, content_len);
return true;
}
diff --git a/src/common/linux/memory_mapped_file.h b/src/common/linux/memory_mapped_file.h
index fa660cc9..d4a85051 100644
--- a/src/common/linux/memory_mapped_file.h
+++ b/src/common/linux/memory_mapped_file.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2011, Google Inc.
-// All rights reserved.
+// Copyright 2011 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/common/linux/memory_mapped_file_unittest.cc b/src/common/linux/memory_mapped_file_unittest.cc
index fad59f40..5ed677df 100644
--- a/src/common/linux/memory_mapped_file_unittest.cc
+++ b/src/common/linux/memory_mapped_file_unittest.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2011, Google Inc.
-// All rights reserved.
+// Copyright 2011 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/common/linux/safe_readlink.cc b/src/common/linux/safe_readlink.cc
index 870c28af..97ea62c0 100644
--- a/src/common/linux/safe_readlink.cc
+++ b/src/common/linux/safe_readlink.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2011, Google Inc.
-// All rights reserved.
+// Copyright 2011 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/common/linux/safe_readlink.h b/src/common/linux/safe_readlink.h
index 4ae131b5..f3aa9332 100644
--- a/src/common/linux/safe_readlink.h
+++ b/src/common/linux/safe_readlink.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2011, Google Inc.
-// All rights reserved.
+// Copyright 2011 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/common/linux/safe_readlink_unittest.cc b/src/common/linux/safe_readlink_unittest.cc
index d346b2a8..6f5f9d75 100644
--- a/src/common/linux/safe_readlink_unittest.cc
+++ b/src/common/linux/safe_readlink_unittest.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2011, Google Inc.
-// All rights reserved.
+// Copyright 2011 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/common/linux/symbol_collector_client.cc b/src/common/linux/symbol_collector_client.cc
index 92b25ddb..1c1dc97a 100644
--- a/src/common/linux/symbol_collector_client.cc
+++ b/src/common/linux/symbol_collector_client.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2019 Google Inc.
-// All rights reserved.
+// Copyright 2019 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/common/linux/symbol_collector_client.h b/src/common/linux/symbol_collector_client.h
index 0e23242a..6190376f 100644
--- a/src/common/linux/symbol_collector_client.h
+++ b/src/common/linux/symbol_collector_client.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2019, Google Inc.
-// All rights reserved.
+// Copyright 2019 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/common/linux/symbol_upload.cc b/src/common/linux/symbol_upload.cc
index 87741a0a..c080533a 100644
--- a/src/common/linux/symbol_upload.cc
+++ b/src/common/linux/symbol_upload.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2011 Google Inc.
-// All rights reserved.
+// Copyright 2011 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -46,8 +45,8 @@
namespace google_breakpad {
namespace sym_upload {
-void TokenizeByChar(const string &source_string, int c,
- std::vector<string> *results) {
+void TokenizeByChar(const string& source_string, int c,
+ std::vector<string>* results) {
assert(results);
string::size_type cur_pos = 0, next_pos = 0;
while ((next_pos = source_string.find(c, cur_pos)) != string::npos) {
@@ -62,8 +61,8 @@ void TokenizeByChar(const string &source_string, int c,
//=============================================================================
// Parse out the module line which have 5 parts.
// MODULE <os> <cpu> <uuid> <module-name>
-bool ModuleDataForSymbolFile(const string &file,
- std::vector<string> *module_parts) {
+bool ModuleDataForSymbolFile(const string& file,
+ std::vector<string>* module_parts) {
assert(module_parts);
const size_t kModulePartNumber = 5;
FILE* fp = fopen(file.c_str(), "r");
@@ -90,7 +89,7 @@ bool ModuleDataForSymbolFile(const string &file,
}
//=============================================================================
-string CompactIdentifier(const string &uuid) {
+string CompactIdentifier(const string& uuid) {
std::vector<string> components;
TokenizeByChar(uuid, '-', &components);
string result;
diff --git a/src/common/linux/symbol_upload.h b/src/common/linux/symbol_upload.h
index 9033152b..a9d30e7b 100644
--- a/src/common/linux/symbol_upload.h
+++ b/src/common/linux/symbol_upload.h
@@ -1,7 +1,6 @@
// -*- mode: c++ -*-
-// Copyright (c) 2011 Google Inc.
-// All rights reserved.
+// Copyright 2011 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -13,7 +12,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/common/linux/synth_elf.cc b/src/common/linux/synth_elf.cc
index 98e81dab..2ba25e61 100644
--- a/src/common/linux/synth_elf.cc
+++ b/src/common/linux/synth_elf.cc
@@ -118,7 +118,7 @@ int ELF::AddSection(const string& name, const Section& section,
return index;
}
-void ELF::AppendSection(ElfSection &section) {
+void ELF::AppendSection(ElfSection& section) {
// NULL and NOBITS sections have no content, so they
// don't need to be written to the file.
if (section.type_ == SHT_NULL) {
@@ -242,7 +242,7 @@ void SymbolTable::AddSymbol(const string& name, uint64_t value,
D64(size);
}
-void Notes::AddNote(int type, const string &name, const uint8_t* desc_bytes,
+void Notes::AddNote(int type, const string& name, const uint8_t* desc_bytes,
size_t desc_size) {
// Elf32_Nhdr and Elf64_Nhdr are exactly the same.
Elf32_Nhdr note_header;
diff --git a/src/common/linux/synth_elf.h b/src/common/linux/synth_elf.h
index 1d2a20ca..bf22081b 100644
--- a/src/common/linux/synth_elf.h
+++ b/src/common/linux/synth_elf.h
@@ -1,7 +1,6 @@
// -*- mode: C++ -*-
-// Copyright (c) 2011, Google Inc.
-// All rights reserved.
+// Copyright 2011 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -13,7 +12,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -154,7 +153,7 @@ class ELF : public Section {
vector<ElfSection> sections_;
- void AppendSection(ElfSection &section);
+ void AppendSection(ElfSection& section);
};
// A class to build .symtab or .dynsym sections.
@@ -187,7 +186,7 @@ public:
}
// Add a note.
- void AddNote(int type, const string &name, const uint8_t* desc_bytes,
+ void AddNote(int type, const string& name, const uint8_t* desc_bytes,
size_t desc_size);
};
diff --git a/src/common/linux/synth_elf_unittest.cc b/src/common/linux/synth_elf_unittest.cc
index cd74c286..44ef6ef3 100644
--- a/src/common/linux/synth_elf_unittest.cc
+++ b/src/common/linux/synth_elf_unittest.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2011 Google Inc.
-// All rights reserved.
+// Copyright 2011 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -381,9 +380,9 @@ TEST_F(ElfNotesTest, Empty) {
TEST_F(ElfNotesTest, Notes) {
Notes notes(kLittleEndian);
- notes.AddNote(1, "Linux", reinterpret_cast<const uint8_t *>("\x42\x02\0\0"),
+ notes.AddNote(1, "Linux", reinterpret_cast<const uint8_t*>("\x42\x02\0\0"),
4);
- notes.AddNote(2, "a", reinterpret_cast<const uint8_t *>("foobar"),
+ notes.AddNote(2, "a", reinterpret_cast<const uint8_t*>("foobar"),
sizeof("foobar") - 1);
const uint8_t kExpectedNotesContents[] = {
diff --git a/src/common/linux/tests/auto_testfile.h b/src/common/linux/tests/auto_testfile.h
index 92fe017b..e2d2ff23 100644
--- a/src/common/linux/tests/auto_testfile.h
+++ b/src/common/linux/tests/auto_testfile.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2013, Google Inc.
-// All rights reserved.
+// Copyright 2013 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/common/linux/tests/crash_generator.cc b/src/common/linux/tests/crash_generator.cc
index 6896a688..0db0c4a2 100644
--- a/src/common/linux/tests/crash_generator.cc
+++ b/src/common/linux/tests/crash_generator.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2011, Google Inc.
-// All rights reserved.
+// Copyright 2011 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -79,7 +78,7 @@ int tkill(pid_t tid, int sig) {
// Core file size limit set to 1 MB, which is big enough for test purposes.
const rlim_t kCoreSizeLimit = 1024 * 1024;
-void *thread_function(void *data) {
+void* thread_function(void* data) {
ThreadData* thread_data = reinterpret_cast<ThreadData*>(data);
volatile pid_t thread_id = gettid();
*(thread_data->thread_id_ptr) = thread_id;
@@ -169,6 +168,15 @@ bool CrashGenerator::SetCoreFileSizeLimit(rlim_t limit) const {
return true;
}
+bool CrashGenerator::HasResourceLimitsAmenableToCrashCollection() const {
+ struct rlimit limits;
+ if (getrlimit(RLIMIT_CORE, &limits) == -1) {
+ perror("CrashGenerator: Failed to get core file size limit");
+ return false;
+ }
+ return limits.rlim_max >= kCoreSizeLimit;
+}
+
bool CrashGenerator::CreateChildCrash(
unsigned num_threads, unsigned crash_thread, int crash_signal,
pid_t* child_pid) {
diff --git a/src/common/linux/tests/crash_generator.h b/src/common/linux/tests/crash_generator.h
index 7e2fcbf9..71c05d27 100644
--- a/src/common/linux/tests/crash_generator.h
+++ b/src/common/linux/tests/crash_generator.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2011, Google Inc.
-// All rights reserved.
+// Copyright 2011 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -65,6 +64,10 @@ class CrashGenerator {
// Returns the directory of a copy of proc files of the child process.
string GetDirectoryOfProcFilesCopy() const;
+ // Returns whether current resource limits would prevent `CreateChildCrash`
+ // from operating.
+ bool HasResourceLimitsAmenableToCrashCollection() const;
+
// Creates a crash (and a core dump file) by creating a child process with
// |num_threads| threads, and the terminating the child process by sending
// a signal with number |crash_signal| to the |crash_thread|-th thread.
diff --git a/src/common/linux/ucontext_constants.h b/src/common/linux/ucontext_constants.h
index c390508a..3dcdecb0 100644
--- a/src/common/linux/ucontext_constants.h
+++ b/src/common/linux/ucontext_constants.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2012, Google Inc.
-// All rights reserved.
+// Copyright 2012 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -146,8 +145,107 @@
#endif
#define FPREGS_OFFSET_MXCSR 24
+#elif defined(__riscv)
+
+#if __riscv_xlen == 32
+#define UCONTEXT_SIGMASK_OFFSET 20
+#define MCONTEXT_GREGS_OFFSET 148
+#define MCONTEXT_GREGS_SIZE 4
+#define REG_S sw
+#elif __riscv_xlen == 64
+#define UCONTEXT_SIGMASK_OFFSET 40
+#define MCONTEXT_GREGS_OFFSET 168
+#define MCONTEXT_GREGS_SIZE 8
+#define REG_S sd
#else
-#error "This header has not been ported for your CPU"
+#error "Unexpected __riscv_xlen"
+#endif
+
+#define MCONTEXT_GREGS_PC MCONTEXT_GREGS_OFFSET + 0*MCONTEXT_GREGS_SIZE
+#define MCONTEXT_GREGS_RA MCONTEXT_GREGS_OFFSET + 1*MCONTEXT_GREGS_SIZE
+#define MCONTEXT_GREGS_SP MCONTEXT_GREGS_OFFSET + 2*MCONTEXT_GREGS_SIZE
+#define MCONTEXT_GREGS_GP MCONTEXT_GREGS_OFFSET + 3*MCONTEXT_GREGS_SIZE
+#define MCONTEXT_GREGS_TP MCONTEXT_GREGS_OFFSET + 4*MCONTEXT_GREGS_SIZE
+#define MCONTEXT_GREGS_T0 MCONTEXT_GREGS_OFFSET + 5*MCONTEXT_GREGS_SIZE
+#define MCONTEXT_GREGS_T1 MCONTEXT_GREGS_OFFSET + 6*MCONTEXT_GREGS_SIZE
+#define MCONTEXT_GREGS_T2 MCONTEXT_GREGS_OFFSET + 7*MCONTEXT_GREGS_SIZE
+#define MCONTEXT_GREGS_S0 MCONTEXT_GREGS_OFFSET + 8*MCONTEXT_GREGS_SIZE
+#define MCONTEXT_GREGS_S1 MCONTEXT_GREGS_OFFSET + 9*MCONTEXT_GREGS_SIZE
+#define MCONTEXT_GREGS_A0 MCONTEXT_GREGS_OFFSET + 10*MCONTEXT_GREGS_SIZE
+#define MCONTEXT_GREGS_A1 MCONTEXT_GREGS_OFFSET + 11*MCONTEXT_GREGS_SIZE
+#define MCONTEXT_GREGS_A2 MCONTEXT_GREGS_OFFSET + 12*MCONTEXT_GREGS_SIZE
+#define MCONTEXT_GREGS_A3 MCONTEXT_GREGS_OFFSET + 13*MCONTEXT_GREGS_SIZE
+#define MCONTEXT_GREGS_A4 MCONTEXT_GREGS_OFFSET + 14*MCONTEXT_GREGS_SIZE
+#define MCONTEXT_GREGS_A5 MCONTEXT_GREGS_OFFSET + 15*MCONTEXT_GREGS_SIZE
+#define MCONTEXT_GREGS_A6 MCONTEXT_GREGS_OFFSET + 16*MCONTEXT_GREGS_SIZE
+#define MCONTEXT_GREGS_A7 MCONTEXT_GREGS_OFFSET + 17*MCONTEXT_GREGS_SIZE
+#define MCONTEXT_GREGS_S2 MCONTEXT_GREGS_OFFSET + 18*MCONTEXT_GREGS_SIZE
+#define MCONTEXT_GREGS_S3 MCONTEXT_GREGS_OFFSET + 19*MCONTEXT_GREGS_SIZE
+#define MCONTEXT_GREGS_S4 MCONTEXT_GREGS_OFFSET + 20*MCONTEXT_GREGS_SIZE
+#define MCONTEXT_GREGS_S5 MCONTEXT_GREGS_OFFSET + 21*MCONTEXT_GREGS_SIZE
+#define MCONTEXT_GREGS_S6 MCONTEXT_GREGS_OFFSET + 22*MCONTEXT_GREGS_SIZE
+#define MCONTEXT_GREGS_S7 MCONTEXT_GREGS_OFFSET + 23*MCONTEXT_GREGS_SIZE
+#define MCONTEXT_GREGS_S8 MCONTEXT_GREGS_OFFSET + 24*MCONTEXT_GREGS_SIZE
+#define MCONTEXT_GREGS_S9 MCONTEXT_GREGS_OFFSET + 25*MCONTEXT_GREGS_SIZE
+#define MCONTEXT_GREGS_S10 MCONTEXT_GREGS_OFFSET + 26*MCONTEXT_GREGS_SIZE
+#define MCONTEXT_GREGS_S11 MCONTEXT_GREGS_OFFSET + 27*MCONTEXT_GREGS_SIZE
+#define MCONTEXT_GREGS_T3 MCONTEXT_GREGS_OFFSET + 28*MCONTEXT_GREGS_SIZE
+#define MCONTEXT_GREGS_T4 MCONTEXT_GREGS_OFFSET + 29*MCONTEXT_GREGS_SIZE
+#define MCONTEXT_GREGS_T5 MCONTEXT_GREGS_OFFSET + 30*MCONTEXT_GREGS_SIZE
+#define MCONTEXT_GREGS_T6 MCONTEXT_GREGS_OFFSET + 31*MCONTEXT_GREGS_SIZE
+
+#define MCONTEXT_FPREGS_OFFSET MCONTEXT_GREGS_OFFSET + 32*MCONTEXT_GREGS_SIZE
+
+#if __riscv_flen == 32
+#define MCONTEXT_FPREGS_SIZE 4
+#define FREG_S fsw
+#elif __riscv_flen == 64
+#define MCONTEXT_FPREGS_SIZE 8
+#define FREG_S fsd
+#elif __riscv_flen == 128
+#define MCONTEXT_FPREGS_SIZE 16
+#define FREG_S fsq
+#else
+#error "Unexpected __riscv_flen"
+#endif
+
+#define MCONTEXT_FPREGS_FT0 MCONTEXT_FPREGS_OFFSET + 0*MCONTEXT_FPREGS_SIZE
+#define MCONTEXT_FPREGS_FT1 MCONTEXT_FPREGS_OFFSET + 1*MCONTEXT_FPREGS_SIZE
+#define MCONTEXT_FPREGS_FT2 MCONTEXT_FPREGS_OFFSET + 2*MCONTEXT_FPREGS_SIZE
+#define MCONTEXT_FPREGS_FT3 MCONTEXT_FPREGS_OFFSET + 3*MCONTEXT_FPREGS_SIZE
+#define MCONTEXT_FPREGS_FT4 MCONTEXT_FPREGS_OFFSET + 4*MCONTEXT_FPREGS_SIZE
+#define MCONTEXT_FPREGS_FT5 MCONTEXT_FPREGS_OFFSET + 5*MCONTEXT_FPREGS_SIZE
+#define MCONTEXT_FPREGS_FT6 MCONTEXT_FPREGS_OFFSET + 6*MCONTEXT_FPREGS_SIZE
+#define MCONTEXT_FPREGS_FT7 MCONTEXT_FPREGS_OFFSET + 7*MCONTEXT_FPREGS_SIZE
+#define MCONTEXT_FPREGS_FS0 MCONTEXT_FPREGS_OFFSET + 8*MCONTEXT_FPREGS_SIZE
+#define MCONTEXT_FPREGS_FS1 MCONTEXT_FPREGS_OFFSET + 9*MCONTEXT_FPREGS_SIZE
+#define MCONTEXT_FPREGS_FA0 MCONTEXT_FPREGS_OFFSET + 10*MCONTEXT_FPREGS_SIZE
+#define MCONTEXT_FPREGS_FA1 MCONTEXT_FPREGS_OFFSET + 11*MCONTEXT_FPREGS_SIZE
+#define MCONTEXT_FPREGS_FA2 MCONTEXT_FPREGS_OFFSET + 12*MCONTEXT_FPREGS_SIZE
+#define MCONTEXT_FPREGS_FA3 MCONTEXT_FPREGS_OFFSET + 13*MCONTEXT_FPREGS_SIZE
+#define MCONTEXT_FPREGS_FA4 MCONTEXT_FPREGS_OFFSET + 14*MCONTEXT_FPREGS_SIZE
+#define MCONTEXT_FPREGS_FA5 MCONTEXT_FPREGS_OFFSET + 15*MCONTEXT_FPREGS_SIZE
+#define MCONTEXT_FPREGS_FA6 MCONTEXT_FPREGS_OFFSET + 16*MCONTEXT_FPREGS_SIZE
+#define MCONTEXT_FPREGS_FA7 MCONTEXT_FPREGS_OFFSET + 17*MCONTEXT_FPREGS_SIZE
+#define MCONTEXT_FPREGS_FS2 MCONTEXT_FPREGS_OFFSET + 18*MCONTEXT_FPREGS_SIZE
+#define MCONTEXT_FPREGS_FS3 MCONTEXT_FPREGS_OFFSET + 19*MCONTEXT_FPREGS_SIZE
+#define MCONTEXT_FPREGS_FS4 MCONTEXT_FPREGS_OFFSET + 20*MCONTEXT_FPREGS_SIZE
+#define MCONTEXT_FPREGS_FS5 MCONTEXT_FPREGS_OFFSET + 21*MCONTEXT_FPREGS_SIZE
+#define MCONTEXT_FPREGS_FS6 MCONTEXT_FPREGS_OFFSET + 22*MCONTEXT_FPREGS_SIZE
+#define MCONTEXT_FPREGS_FS7 MCONTEXT_FPREGS_OFFSET + 23*MCONTEXT_FPREGS_SIZE
+#define MCONTEXT_FPREGS_FS8 MCONTEXT_FPREGS_OFFSET + 24*MCONTEXT_FPREGS_SIZE
+#define MCONTEXT_FPREGS_FS9 MCONTEXT_FPREGS_OFFSET + 25*MCONTEXT_FPREGS_SIZE
+#define MCONTEXT_FPREGS_FS10 MCONTEXT_FPREGS_OFFSET + 26*MCONTEXT_FPREGS_SIZE
+#define MCONTEXT_FPREGS_FS11 MCONTEXT_FPREGS_OFFSET + 27*MCONTEXT_FPREGS_SIZE
+#define MCONTEXT_FPREGS_FT8 MCONTEXT_FPREGS_OFFSET + 28*MCONTEXT_FPREGS_SIZE
+#define MCONTEXT_FPREGS_FT9 MCONTEXT_FPREGS_OFFSET + 29*MCONTEXT_FPREGS_SIZE
+#define MCONTEXT_FPREGS_FT10 MCONTEXT_FPREGS_OFFSET + 30*MCONTEXT_FPREGS_SIZE
+#define MCONTEXT_FPREGS_FT11 MCONTEXT_FPREGS_OFFSET + 31*MCONTEXT_FPREGS_SIZE
+
+#define MCONTEXT_FPC_CSR MCONTEXT_FPREGS_OFFSET + 32*MCONTEXT_FPREGS_SIZE
+
+#else
+# error "This header has not been ported for your CPU"
#endif
#endif // GOOGLEBREAKPAD_COMMON_ANDROID_UCONTEXT_CONSTANTS_H
diff --git a/src/common/long_string_dictionary.cc b/src/common/long_string_dictionary.cc
index 46bbf613..f504aa42 100644
--- a/src/common/long_string_dictionary.cc
+++ b/src/common/long_string_dictionary.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2017, Google Inc.
-// All rights reserved.
+// Copyright 2017 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/common/long_string_dictionary.h b/src/common/long_string_dictionary.h
index 68bf03de..9319b27f 100644
--- a/src/common/long_string_dictionary.h
+++ b/src/common/long_string_dictionary.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2017, Google Inc.
-// All rights reserved.
+// Copyright 2017 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/common/long_string_dictionary_unittest.cc b/src/common/long_string_dictionary_unittest.cc
index f9b645ba..be34efdf 100644
--- a/src/common/long_string_dictionary_unittest.cc
+++ b/src/common/long_string_dictionary_unittest.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2017, Google Inc.
-// All rights reserved.
+// Copyright 2017 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/common/mac/Breakpad.xcconfig b/src/common/mac/Breakpad.xcconfig
index f0913690..fd28d3ce 100644
--- a/src/common/mac/Breakpad.xcconfig
+++ b/src/common/mac/Breakpad.xcconfig
@@ -1,5 +1,4 @@
-// Copyright (c) 2010, Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/common/mac/BreakpadDebug.xcconfig b/src/common/mac/BreakpadDebug.xcconfig
index 94cdd8cf..6ec7c00e 100644
--- a/src/common/mac/BreakpadDebug.xcconfig
+++ b/src/common/mac/BreakpadDebug.xcconfig
@@ -1,5 +1,4 @@
-// Copyright (c) 2010, Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/common/mac/BreakpadRelease.xcconfig b/src/common/mac/BreakpadRelease.xcconfig
index 920f277d..9121b0d0 100644
--- a/src/common/mac/BreakpadRelease.xcconfig
+++ b/src/common/mac/BreakpadRelease.xcconfig
@@ -1,5 +1,4 @@
-// Copyright (c) 2010, Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/common/mac/GTMDefines.h b/src/common/mac/GTMDefines.h
index 04fcf6d0..ae5368cd 100644
--- a/src/common/mac/GTMDefines.h
+++ b/src/common/mac/GTMDefines.h
@@ -1,7 +1,7 @@
//
// GTMDefines.h
//
-// Copyright 2008 Google Inc.
+// Copyright 2008 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not
// use this file except in compliance with the License. You may obtain a copy
diff --git a/src/common/mac/GTMLogger.h b/src/common/mac/GTMLogger.h
index c4fd1402..dcc7da44 100644
--- a/src/common/mac/GTMLogger.h
+++ b/src/common/mac/GTMLogger.h
@@ -1,7 +1,7 @@
//
// GTMLogger.h
//
-// Copyright 2007-2008 Google Inc.
+// Copyright 2007-2008 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not
// use this file except in compliance with the License. You may obtain a copy
diff --git a/src/common/mac/GTMLogger.m b/src/common/mac/GTMLogger.m
index ebc5836a..17db83d6 100644
--- a/src/common/mac/GTMLogger.m
+++ b/src/common/mac/GTMLogger.m
@@ -1,7 +1,7 @@
//
// GTMLogger.m
//
-// Copyright 2007-2008 Google Inc.
+// Copyright 2007-2008 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not
// use this file except in compliance with the License. You may obtain a copy
diff --git a/src/common/mac/HTTPGetRequest.h b/src/common/mac/HTTPGetRequest.h
new file mode 100644
index 00000000..9c3cb3f9
--- /dev/null
+++ b/src/common/mac/HTTPGetRequest.h
@@ -0,0 +1,41 @@
+// Copyright 2020 Google LLC
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google LLC nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#import <Foundation/Foundation.h>
+
+#import "HTTPRequest.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+/**
+ Represents a HTTP GET request
+ */
+@interface HTTPGetRequest : HTTPRequest
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/src/common/mac/HTTPGetRequest.m b/src/common/mac/HTTPGetRequest.m
new file mode 100644
index 00000000..e151cfd8
--- /dev/null
+++ b/src/common/mac/HTTPGetRequest.m
@@ -0,0 +1,38 @@
+// Copyright 2020 Google LLC
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google LLC nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#import "HTTPGetRequest.h"
+
+@implementation HTTPGetRequest
+
+//=============================================================================
+- (NSString*)HTTPMethod {
+ return @"GET";
+}
+
+@end
diff --git a/src/common/mac/HTTPMultipartUpload.h b/src/common/mac/HTTPMultipartUpload.h
index 42e8fed3..27b9cf86 100644
--- a/src/common/mac/HTTPMultipartUpload.h
+++ b/src/common/mac/HTTPMultipartUpload.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2006, Google Inc.
-// All rights reserved.
+// Copyright 2006 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -27,35 +26,37 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-// HTTPMultipartUpload: A multipart/form-data HTTP uploader.
-// Each parameter pair is sent as a boundary
-// Each file is sent with a name field in addition to the filename and data
-// The data will be sent synchronously.
-
#import <Foundation/Foundation.h>
-@interface HTTPMultipartUpload : NSObject {
+#import "HTTPRequest.h"
+/**
+ Represents a multipart/form-data HTTP upload (POST request).
+ Each parameter pair is sent as a boundary.
+ Each file is sent with a name field in addition to the filename and data.
+ */
+@interface HTTPMultipartUpload : HTTPRequest {
@protected
- NSURL *url_; // The destination URL (STRONG)
- NSDictionary *parameters_; // The key/value pairs for sending data (STRONG)
- NSMutableDictionary *files_; // Dictionary of name/file-path (STRONG)
- NSString *boundary_; // The boundary string (STRONG)
- NSHTTPURLResponse *response_; // The response from the send (STRONG)
+ NSDictionary* parameters_; // The key/value pairs for sending data (STRONG)
+ NSMutableDictionary* files_; // Dictionary of name/file-path (STRONG)
+ NSString* boundary_; // The boundary string (STRONG)
}
-- (id)initWithURL:(NSURL *)url;
-
-- (NSURL *)URL;
-
-- (void)setParameters:(NSDictionary *)parameters;
-- (NSDictionary *)parameters;
-
-- (void)addFileAtPath:(NSString *)path name:(NSString *)name;
-- (void)addFileContents:(NSData *)data name:(NSString *)name;
-- (NSDictionary *)files;
-
-// Set the data and return the response
-- (NSData *)send:(NSError **)error;
-- (NSHTTPURLResponse *)response;
+/**
+ Sets the parameters that will be sent in the multipart POST request.
+ */
+- (void)setParameters:(NSDictionary*)parameters;
+- (NSDictionary*)parameters;
+
+/**
+ Adds a file to be uploaded in the multipart POST request, by its file path.
+ */
+- (void)addFileAtPath:(NSString*)path name:(NSString*)name;
+
+/**
+ Adds a file to be uploaded in the multipart POST request, by its name and
+ contents.
+ */
+- (void)addFileContents:(NSData*)data name:(NSString*)name;
+- (NSDictionary*)files;
@end
diff --git a/src/common/mac/HTTPMultipartUpload.m b/src/common/mac/HTTPMultipartUpload.m
index a3677f25..b3a084a9 100644
--- a/src/common/mac/HTTPMultipartUpload.m
+++ b/src/common/mac/HTTPMultipartUpload.m
@@ -1,5 +1,4 @@
-// Copyright (c) 2006, Google Inc.
-// All rights reserved.
+// Copyright 2006 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -28,74 +27,17 @@
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#import "HTTPMultipartUpload.h"
-#import "GTMDefines.h"
-// As -[NSString stringByAddingPercentEscapesUsingEncoding:] has been
-// deprecated with iOS 9.0 / OS X 10.11 SDKs, this function re-implements it
-// using -[NSString stringByAddingPercentEncodingWithAllowedCharacters:] when
-// using those SDKs.
-static NSString *PercentEncodeNSString(NSString *key) {
-#if (defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && defined(__IPHONE_9_0) && \
- __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_9_0) || \
- (defined(MAC_OS_X_VERSION_MIN_REQUIRED) && \
- defined(MAC_OS_X_VERSION_10_11) && \
- MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_11)
- return [key stringByAddingPercentEncodingWithAllowedCharacters:
- [NSCharacterSet URLQueryAllowedCharacterSet]];
-#else
- return [key stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
-#endif
-}
+#import "GTMDefines.h"
+#import "encoding_util.h"
-// As -[NSURLConnection sendSynchronousRequest:returningResponse:error:] has
-// been deprecated with iOS 9.0 / OS X 10.11 SDKs, this function re-implements
-// it using -[NSURLSession dataTaskWithRequest:completionHandler:] which is
-// available on iOS 7+.
-static NSData *SendSynchronousNSURLRequest(NSURLRequest *req,
- NSURLResponse **out_response,
- NSError **out_error) {
-#if (defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && defined(__IPHONE_7_0) && \
- __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_7_0) || \
- (defined(MAC_OS_X_VERSION_MIN_REQUIRED) && \
- defined(MAC_OS_X_VERSION_10_11) && \
- MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_11)
- __block NSData* result = nil;
- __block NSError* error = nil;
- __block NSURLResponse* response = nil;
- dispatch_semaphore_t wait_semaphone = dispatch_semaphore_create(0);
- [[[NSURLSession sharedSession]
- dataTaskWithRequest:req
- completionHandler:^(NSData *data,
- NSURLResponse *resp,
- NSError *err) {
- if (out_error)
- error = [err retain];
- if (out_response)
- response = [resp retain];
- if (err == nil)
- result = [data retain];
- dispatch_semaphore_signal(wait_semaphone);
- }] resume];
- dispatch_semaphore_wait(wait_semaphone, DISPATCH_TIME_FOREVER);
- dispatch_release(wait_semaphone);
- if (out_error)
- *out_error = [error autorelease];
- if (out_response)
- *out_response = [response autorelease];
- return [result autorelease];
-#else
- return [NSURLConnection sendSynchronousRequest:req
- returningResponse:out_response
- error:out_error];
-#endif
-}
-@interface HTTPMultipartUpload(PrivateMethods)
-- (NSString *)multipartBoundary;
+@interface HTTPMultipartUpload (PrivateMethods)
+- (NSString*)multipartBoundary;
// Each of the following methods will append the starting multipart boundary,
// but not the ending one.
-- (NSData *)formDataForKey:(NSString *)key value:(NSString *)value;
-- (NSData *)formDataForFileContents:(NSData *)contents name:(NSString *)name;
-- (NSData *)formDataForFile:(NSString *)file name:(NSString *)name;
+- (NSData*)formDataForKey:(NSString*)key value:(NSString*)value;
+- (NSData*)formDataForFileContents:(NSData*)contents name:(NSString*)name;
+- (NSData*)formDataForFile:(NSString*)file name:(NSString*)name;
@end
@implementation HTTPMultipartUpload
@@ -103,50 +45,39 @@ static NSData *SendSynchronousNSURLRequest(NSURLRequest *req,
#pragma mark -
#pragma mark || Private ||
//=============================================================================
-- (NSString *)multipartBoundary {
+- (NSString*)multipartBoundary {
// The boundary has 27 '-' characters followed by 16 hex digits
- return [NSString stringWithFormat:@"---------------------------%08X%08X",
- rand(), rand()];
-}
-
-//=============================================================================
-- (NSData *)formDataForKey:(NSString *)key value:(NSString *)value {
- NSString *escaped = PercentEncodeNSString(key);
- NSString *fmt =
- @"--%@\r\nContent-Disposition: form-data; name=\"%@\"\r\n\r\n%@\r\n";
- NSString *form = [NSString stringWithFormat:fmt, boundary_, escaped, value];
-
- return [form dataUsingEncoding:NSUTF8StringEncoding];
+ return [NSString
+ stringWithFormat:@"---------------------------%08X%08X", rand(), rand()];
}
//=============================================================================
-- (NSData *)formDataForFileContents:(NSData *)contents name:(NSString *)name {
- NSMutableData *data = [NSMutableData data];
- NSString *escaped = PercentEncodeNSString(name);
- NSString *fmt = @"--%@\r\nContent-Disposition: form-data; name=\"%@\"; "
- "filename=\"minidump.dmp\"\r\nContent-Type: application/octet-stream\r\n\r\n";
- NSString *pre = [NSString stringWithFormat:fmt, boundary_, escaped];
+- (NSData*)formDataForKey:(NSString*)key value:(NSString*)value {
+ NSMutableData* data = [NSMutableData data];
+ [self appendBoundaryData:data];
- [data appendData:[pre dataUsingEncoding:NSUTF8StringEncoding]];
- [data appendData:contents];
+ NSString* escaped = PercentEncodeNSString(key);
+ NSString* fmt = @"Content-Disposition: form-data; name=\"%@\"\r\n\r\n%@\r\n";
+ NSString *form = [NSString stringWithFormat:fmt, escaped, value];
+ [data appendData:[form dataUsingEncoding:NSUTF8StringEncoding]];
return data;
}
//=============================================================================
-- (NSData *)formDataForFile:(NSString *)file name:(NSString *)name {
- NSData *contents = [NSData dataWithContentsOfFile:file];
+- (void)appendBoundaryData:(NSMutableData*)data {
+ NSString* fmt = @"--%@\r\n";
+ NSString* pre = [NSString stringWithFormat:fmt, boundary_];
- return [self formDataForFileContents:contents name:name];
+ [data appendData:[pre dataUsingEncoding:NSUTF8StringEncoding]];
}
//=============================================================================
#pragma mark -
#pragma mark || Public ||
//=============================================================================
-- (id)initWithURL:(NSURL *)url {
- if ((self = [super init])) {
- url_ = [url copy];
+- (id)initWithURL:(NSURL*)url {
+ if ((self = [super initWithURL:url])) {
boundary_ = [[self multipartBoundary] retain];
files_ = [[NSMutableDictionary alloc] init];
}
@@ -156,22 +87,15 @@ static NSData *SendSynchronousNSURLRequest(NSURLRequest *req,
//=============================================================================
- (void)dealloc {
- [url_ release];
[parameters_ release];
[files_ release];
[boundary_ release];
- [response_ release];
[super dealloc];
}
//=============================================================================
-- (NSURL *)URL {
- return url_;
-}
-
-//=============================================================================
-- (void)setParameters:(NSDictionary *)parameters {
+- (void)setParameters:(NSDictionary*)parameters {
if (parameters != parameters_) {
[parameters_ release];
parameters_ = [parameters copy];
@@ -179,40 +103,43 @@ static NSData *SendSynchronousNSURLRequest(NSURLRequest *req,
}
//=============================================================================
-- (NSDictionary *)parameters {
+- (NSDictionary*)parameters {
return parameters_;
}
//=============================================================================
-- (void)addFileAtPath:(NSString *)path name:(NSString *)name {
+- (void)addFileAtPath:(NSString*)path name:(NSString*)name {
[files_ setObject:path forKey:name];
}
//=============================================================================
-- (void)addFileContents:(NSData *)data name:(NSString *)name {
+- (void)addFileContents:(NSData*)data name:(NSString*)name {
[files_ setObject:data forKey:name];
}
//=============================================================================
-- (NSDictionary *)files {
+- (NSDictionary*)files {
return files_;
}
//=============================================================================
-- (NSData *)send:(NSError **)error {
- NSMutableURLRequest *req =
- [[NSMutableURLRequest alloc]
- initWithURL:url_ cachePolicy:NSURLRequestUseProtocolCachePolicy
- timeoutInterval:60.0];
+- (NSString*)HTTPMethod {
+ return @"POST";
+}
- NSMutableData *postBody = [NSMutableData data];
+//=============================================================================
+- (NSString*)contentType {
+ return [NSString
+ stringWithFormat:@"multipart/form-data; boundary=%@", boundary_];
+}
- [req setValue:[NSString stringWithFormat:@"multipart/form-data; boundary=%@",
- boundary_] forHTTPHeaderField:@"Content-type"];
+//=============================================================================
+- (NSData*)bodyData {
+ NSMutableData* postBody = [NSMutableData data];
// Add any parameters to the message
- NSArray *parameterKeys = [parameters_ allKeys];
- NSString *key;
+ NSArray* parameterKeys = [parameters_ allKeys];
+ NSString* key;
NSInteger count = [parameterKeys count];
for (NSInteger i = 0; i < count; ++i) {
@@ -222,46 +149,21 @@ static NSData *SendSynchronousNSURLRequest(NSURLRequest *req,
}
// Add any files to the message
- NSArray *fileNames = [files_ allKeys];
- for (NSString *name in fileNames) {
+ NSArray* fileNames = [files_ allKeys];
+ for (NSString* name in fileNames) {
+ // First append boundary
+ [self appendBoundaryData:postBody];
+ // Then the formdata
id fileOrData = [files_ objectForKey:name];
- NSData *fileData;
-
- // The object can be either the path to a file (NSString) or the contents
- // of the file (NSData).
- if ([fileOrData isKindOfClass:[NSData class]])
- fileData = [self formDataForFileContents:fileOrData name:name];
- else
- fileData = [self formDataForFile:fileOrData name:name];
-
- [postBody appendData:fileData];
+ [HTTPRequest appendFileToBodyData:postBody
+ withName:name
+ withFileOrData:fileOrData];
}
- NSString *epilogue = [NSString stringWithFormat:@"\r\n--%@--\r\n", boundary_];
+ NSString* epilogue = [NSString stringWithFormat:@"\r\n--%@--\r\n", boundary_];
[postBody appendData:[epilogue dataUsingEncoding:NSUTF8StringEncoding]];
- [req setHTTPBody:postBody];
- [req setHTTPMethod:@"POST"];
-
- [response_ release];
- response_ = nil;
-
- NSData *data = nil;
- if ([[req URL] isFileURL]) {
- [[req HTTPBody] writeToURL:[req URL] options:0 error:error];
- } else {
- NSURLResponse *response = nil;
- data = SendSynchronousNSURLRequest(req, &response, error);
- response_ = (NSHTTPURLResponse *)[response retain];
- }
- [req release];
-
- return data;
-}
-
-//=============================================================================
-- (NSHTTPURLResponse *)response {
- return response_;
+ return postBody;
}
@end
diff --git a/src/common/mac/HTTPPutRequest.h b/src/common/mac/HTTPPutRequest.h
new file mode 100644
index 00000000..36d38c01
--- /dev/null
+++ b/src/common/mac/HTTPPutRequest.h
@@ -0,0 +1,50 @@
+// Copyright 2020 Google LLC
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google LLC nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#import <Foundation/Foundation.h>
+
+#import "HTTPRequest.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+/**
+ Represents an HTTP PUT request.
+ */
+@interface HTTPPutRequest : HTTPRequest {
+ @protected
+ NSString* file_;
+}
+
+/**
+ Sets the path of the file that will be sent in the PUT request.
+ */
+- (void)setFile:(NSString*)file;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/src/common/mac/HTTPPutRequest.m b/src/common/mac/HTTPPutRequest.m
new file mode 100644
index 00000000..b7c7e091
--- /dev/null
+++ b/src/common/mac/HTTPPutRequest.m
@@ -0,0 +1,55 @@
+// Copyright 2020 Google LLC
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google LLC nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#import "HTTPPutRequest.h"
+
+@implementation HTTPPutRequest
+
+//=============================================================================
+- (void)dealloc {
+ [file_ release];
+
+ [super dealloc];
+}
+
+//=============================================================================
+- (void)setFile:(NSString*)file {
+ file_ = [file copy];
+}
+
+//=============================================================================
+- (NSString*)HTTPMethod {
+ return @"PUT";
+}
+
+//=============================================================================
+- (NSData*)bodyData {
+ return [NSData dataWithContentsOfFile:file_];
+}
+
+@end
diff --git a/src/common/mac/HTTPRequest.h b/src/common/mac/HTTPRequest.h
new file mode 100644
index 00000000..49374147
--- /dev/null
+++ b/src/common/mac/HTTPRequest.h
@@ -0,0 +1,72 @@
+// Copyright 2020 Google LLC
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google LLC nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#import <Foundation/Foundation.h>
+
+NS_ASSUME_NONNULL_BEGIN
+/**
+ Represents a single HTTP request. Sending the request is synchronous.
+ Once the send is complete, the response will be set.
+
+ This is a base interface that specific HTTP requests derive from.
+ It is not intended to be instantiated directly.
+ */
+@interface HTTPRequest : NSObject {
+ @protected
+ NSURL* URL_; // The destination URL (STRONG)
+ NSHTTPURLResponse* response_; // The response from the send (STRONG)
+}
+
+/**
+ Initializes the HTTPRequest and sets its URL.
+ */
+- (id)initWithURL:(NSURL*)URL;
+
+- (NSURL*)URL;
+
+- (NSHTTPURLResponse*)response;
+
+- (NSString*)HTTPMethod; // Internal, don't call outside class hierarchy.
+
+- (NSString*)contentType; // Internal, don't call outside class hierarchy.
+
+- (NSData*)bodyData; // Internal, don't call outside class hierarchy.
+
+- (NSData*)send:(NSError**)error;
+
+/**
+ Appends a file to the HTTP request, either by filename or by file content
+ (in the form of NSData).
+ */
++ (void)appendFileToBodyData:(NSMutableData*)data
+ withName:(NSString*)name
+ withFileOrData:(id)fileOrData;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/src/common/mac/HTTPRequest.m b/src/common/mac/HTTPRequest.m
new file mode 100644
index 00000000..af21874d
--- /dev/null
+++ b/src/common/mac/HTTPRequest.m
@@ -0,0 +1,267 @@
+// Copyright 2020 Google LLC
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google LLC nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#import "HTTPRequest.h"
+
+#include <Availability.h>
+#include <AvailabilityMacros.h>
+
+#if (defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && defined(__IPHONE_7_0) && \
+ __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_7_0)
+#import <UIKit/UIKit.h>
+#define HAS_BACKGROUND_TASK_API 1
+#else
+#define HAS_BACKGROUND_TASK_API 0
+#endif
+
+#import "encoding_util.h"
+
+#if (defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && defined(__IPHONE_7_0) && \
+ __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_7_0) || \
+ (defined(MAC_OS_X_VERSION_MIN_REQUIRED) && \
+ defined(MAC_OS_X_VERSION_10_11) && \
+ MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_11)
+#define USE_NSURLSESSION 1
+#else
+#define USE_NSURLSESSION 0
+#endif
+
+// As -[NSURLConnection sendSynchronousRequest:returningResponse:error:] has
+// been deprecated with iOS 9.0 / OS X 10.11 SDKs, this function re-implements
+// it using -[NSURLSession dataTaskWithRequest:completionHandler:] which is
+// available on iOS 7+.
+static NSData* SendSynchronousNSURLRequest(NSURLRequest* req,
+ NSURLResponse** outResponse,
+ NSError** outError) {
+#if USE_NSURLSESSION
+ __block NSData* result = nil;
+ __block NSError* error = nil;
+ __block NSURLResponse* response = nil;
+ dispatch_semaphore_t waitSemaphone = dispatch_semaphore_create(0);
+
+ NSURLSessionConfiguration* config =
+ [NSURLSessionConfiguration defaultSessionConfiguration];
+ [config setTimeoutIntervalForRequest:240.0];
+ NSURLSession* session = [NSURLSession sessionWithConfiguration:config];
+ NSURLSessionDataTask *task = [session
+ dataTaskWithRequest:req
+ completionHandler:^(NSData* data, NSURLResponse* resp, NSError* err) {
+ if (outError)
+ error = [err retain];
+ if (outResponse)
+ response = [resp retain];
+ if (err == nil)
+ result = [data retain];
+ dispatch_semaphore_signal(waitSemaphone);
+ }];
+ [task resume];
+
+#if HAS_BACKGROUND_TASK_API
+ // Used to guard against ending the background task twice, which UIKit
+ // considers to be an error.
+ __block BOOL isBackgroundTaskActive = YES;
+ __block UIBackgroundTaskIdentifier backgroundTaskIdentifier =
+ UIBackgroundTaskInvalid;
+ backgroundTaskIdentifier = [UIApplication.sharedApplication
+ beginBackgroundTaskWithName:@"Breakpad Upload"
+ expirationHandler:^{
+ if (!isBackgroundTaskActive) {
+ return;
+ }
+ isBackgroundTaskActive = NO;
+
+ [task cancel];
+ [UIApplication.sharedApplication
+ endBackgroundTask:backgroundTaskIdentifier];
+ }];
+#endif // HAS_BACKGROUND_TASK_API
+
+ dispatch_semaphore_wait(waitSemaphone, DISPATCH_TIME_FOREVER);
+ dispatch_release(waitSemaphone);
+
+#if HAS_BACKGROUND_TASK_API
+ if (backgroundTaskIdentifier != UIBackgroundTaskInvalid) {
+ // Dispatch to main queue in order to synchronize access to
+ // `isBackgroundTaskActive` with the background task expiration handler,
+ // which is always run on the main thread.
+ dispatch_async(dispatch_get_main_queue(), ^{
+ if (!isBackgroundTaskActive) {
+ return;
+ }
+ isBackgroundTaskActive = NO;
+
+ [UIApplication.sharedApplication
+ endBackgroundTask:backgroundTaskIdentifier];
+ });
+ }
+#endif // HAS_BACKGROUND_TASK_API
+
+ if (outError)
+ *outError = [error autorelease];
+ if (outResponse)
+ *outResponse = [response autorelease];
+ return [result autorelease];
+#else // USE_NSURLSESSION
+ return [NSURLConnection sendSynchronousRequest:req
+ returningResponse:outResponse
+ error:outError];
+#endif // USE_NSURLSESSION
+}
+
+@implementation HTTPRequest
+
+//=============================================================================
+- (id)initWithURL:(NSURL*)URL {
+ if ((self = [super init])) {
+ URL_ = [URL copy];
+ }
+
+ return self;
+}
+
+//=============================================================================
+- (void)dealloc {
+ [URL_ release];
+ [response_ release];
+
+ [super dealloc];
+}
+
+//=============================================================================
+- (NSURL*)URL {
+ return URL_;
+}
+
+//=============================================================================
+- (NSHTTPURLResponse*)response {
+ return response_;
+}
+
+//=============================================================================
+- (NSString*)HTTPMethod {
+ @throw [NSException
+ exceptionWithName:NSInternalInconsistencyException
+ reason:[NSString stringWithFormat:@"You must"
+ "override %@ in a subclass",
+ NSStringFromSelector(_cmd)]
+ userInfo:nil];
+}
+
+//=============================================================================
+- (NSString*)contentType {
+ return nil;
+}
+
+//=============================================================================
+- (NSData*)bodyData {
+ return nil;
+}
+
+//=============================================================================
+- (NSData*)send:(NSError**)withError {
+ NSMutableURLRequest* req = [[NSMutableURLRequest alloc]
+ initWithURL:URL_
+ cachePolicy:NSURLRequestUseProtocolCachePolicy
+ timeoutInterval:60.0];
+
+ NSString* contentType = [self contentType];
+ if ([contentType length] > 0) {
+ [req setValue:contentType forHTTPHeaderField:@"Content-type"];
+ }
+
+ NSData* bodyData = [self bodyData];
+ if ([bodyData length] > 0) {
+ [req setHTTPBody:bodyData];
+ }
+
+ [req setHTTPMethod:[self HTTPMethod]];
+
+ [response_ release];
+ response_ = nil;
+
+ NSData* data = nil;
+ if ([[req URL] isFileURL]) {
+ [[req HTTPBody] writeToURL:[req URL] options:0 error:withError];
+ } else {
+ NSURLResponse* response = nil;
+ data = SendSynchronousNSURLRequest(req, &response, withError);
+ response_ = (NSHTTPURLResponse*)[response retain];
+ }
+ [req release];
+
+ return data;
+}
+
+//=============================================================================
++ (NSData*)formDataForFileContents:(NSData*)contents withName:(NSString*)name {
+ NSMutableData* data = [NSMutableData data];
+ NSString* escaped = PercentEncodeNSString(name);
+ NSString* fmt = @"Content-Disposition: form-data; name=\"%@\"; "
+ "filename=\"minidump.dmp\"\r\nContent-Type: "
+ "application/octet-stream\r\n\r\n";
+ NSString* pre = [NSString stringWithFormat:fmt, escaped];
+
+ [data appendData:[pre dataUsingEncoding:NSUTF8StringEncoding]];
+ [data appendData:contents];
+
+ return data;
+}
+
+//=============================================================================
++ (NSData*)formDataForFile:(NSString*)file withName:(NSString*)name {
+ NSData* contents = [NSData dataWithContentsOfFile:file];
+
+ return [HTTPRequest formDataForFileContents:contents withName:name];
+}
+
+//=============================================================================
++ (NSData*)formDataForKey:(NSString*)key value:(NSString*)value {
+ NSString* escaped = PercentEncodeNSString(key);
+ NSString* fmt = @"Content-Disposition: form-data; name=\"%@\"\r\n\r\n%@\r\n";
+ NSString* form = [NSString stringWithFormat:fmt, escaped, value];
+
+ return [form dataUsingEncoding:NSUTF8StringEncoding];
+}
+
+//=============================================================================
++ (void)appendFileToBodyData:(NSMutableData*)data
+ withName:(NSString*)name
+ withFileOrData:(id)fileOrData {
+ NSData* fileData;
+
+ // The object can be either the path to a file (NSString) or the contents
+ // of the file (NSData).
+ if ([fileOrData isKindOfClass:[NSData class]])
+ fileData = [self formDataForFileContents:fileOrData withName:name];
+ else
+ fileData = [HTTPRequest formDataForFile:fileOrData withName:name];
+
+ [data appendData:fileData];
+}
+
+@end
diff --git a/src/common/mac/HTTPSimplePostRequest.h b/src/common/mac/HTTPSimplePostRequest.h
new file mode 100644
index 00000000..01a1e868
--- /dev/null
+++ b/src/common/mac/HTTPSimplePostRequest.h
@@ -0,0 +1,56 @@
+// Copyright 2020 Google LLC
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google LLC nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#import <Foundation/Foundation.h>
+
+#import "HTTPRequest.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+/**
+ Represents a simple (non-multipart) HTTP POST request.
+ */
+@interface HTTPSimplePostRequest : HTTPRequest {
+ @protected
+ NSString* contentType_;
+ NSString* body_;
+}
+
+/**
+ Sets the content type of the POST request.
+ */
+- (void)setContentType:(NSString*)contentType;
+
+/**
+ Sets the contents of the POST request's body.
+ */
+- (void)setBody:(NSString*)body;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/src/common/mac/HTTPSimplePostRequest.m b/src/common/mac/HTTPSimplePostRequest.m
new file mode 100644
index 00000000..7aba94fd
--- /dev/null
+++ b/src/common/mac/HTTPSimplePostRequest.m
@@ -0,0 +1,68 @@
+// Copyright 2020 Google LLC
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google LLC nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#import "HTTPSimplePostRequest.h"
+
+@implementation HTTPSimplePostRequest
+
+//=============================================================================
+- (void)dealloc {
+ [contentType_ release];
+ [body_ release];
+
+ [super dealloc];
+}
+
+//=============================================================================
+- (void)setContentType:(NSString*)contentType {
+ contentType_ = [contentType copy];
+}
+
+//=============================================================================
+- (void)setBody:(NSString*)body {
+ body_ = [body copy];
+}
+
+//=============================================================================
+- (NSString*)HTTPMethod {
+ return @"POST";
+}
+
+//=============================================================================
+- (NSString*)contentType {
+ return contentType_;
+}
+
+//=============================================================================
+- (NSData*)bodyData {
+ NSMutableData* data = [NSMutableData data];
+ [data appendData:[body_ dataUsingEncoding:NSUTF8StringEncoding]];
+ return data;
+}
+
+@end
diff --git a/src/common/mac/MachIPC.h b/src/common/mac/MachIPC.h
index 71419be9..78b97ad9 100644
--- a/src/common/mac/MachIPC.h
+++ b/src/common/mac/MachIPC.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2007, Google Inc.
-// All rights reserved.
+// Copyright 2007 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -73,7 +72,7 @@
// mach_port_t task = message.GetTranslatedPort(0);
// mach_port_t thread = message.GetTranslatedPort(1);
//
-// char *messageString = message.GetData();
+// char* messageString = message.GetData();
//
// printf("message string = %s\n", messageString);
// }
@@ -164,7 +163,7 @@ class MachMessage {
public:
// The receiver of the message can retrieve the raw data this way
- uint8_t *GetData() {
+ uint8_t* GetData() {
return GetDataLength() > 0 ? GetDataPacket()->data : NULL;
}
@@ -181,10 +180,10 @@ class MachMessage {
// Adds a descriptor (typically a mach port) to be translated
// returns true if successful, otherwise not enough space
- bool AddDescriptor(const MachMsgPortDescriptor &desc);
+ bool AddDescriptor(const MachMsgPortDescriptor& desc);
int GetDescriptorCount() const { return body.msgh_descriptor_count; }
- MachMsgPortDescriptor *GetDescriptor(int n);
+ MachMsgPortDescriptor* GetDescriptor(int n);
// Convenience method which gets the mach port described by the descriptor
mach_port_t GetTranslatedPort(int n);
@@ -193,7 +192,7 @@ class MachMessage {
bool IsSimpleMessage() const { return GetDescriptorCount() == 0; }
// Sets raw data for the message (returns false if not enough space)
- bool SetData(void *data, int32_t data_length);
+ bool SetData(void* data, int32_t data_length);
protected:
// Consider this an abstract base class - must create an actual instance
@@ -216,7 +215,7 @@ class MachMessage {
MessageDataPacket* GetDataPacket();
void SetDescriptorCount(int n);
- void SetDescriptor(int n, const MachMsgPortDescriptor &desc);
+ void SetDescriptor(int n, const MachMsgPortDescriptor& desc);
// Returns total message size setting msgh_size in the header to this value
mach_msg_size_t CalculateSize();
@@ -250,7 +249,7 @@ class MachSendMessage : public MachMessage {
class ReceivePort {
public:
// Creates a new mach port for receiving messages and registers a name for it
- explicit ReceivePort(const char *receive_port_name);
+ explicit ReceivePort(const char* receive_port_name);
// Given an already existing mach port, use it. We take ownership of the
// port and deallocate it in our destructor.
@@ -262,7 +261,7 @@ class ReceivePort {
~ReceivePort();
// Waits on the mach port until message received or timeout
- kern_return_t WaitForMessage(MachReceiveMessage *out_message,
+ kern_return_t WaitForMessage(MachReceiveMessage* out_message,
mach_msg_timeout_t timeout);
// The underlying mach port that we wrap
@@ -280,13 +279,13 @@ class ReceivePort {
class MachPortSender {
public:
// get a port with send rights corresponding to a named registered service
- explicit MachPortSender(const char *receive_port_name);
+ explicit MachPortSender(const char* receive_port_name);
// Given an already existing mach port, use it.
explicit MachPortSender(mach_port_t send_port);
- kern_return_t SendMessage(MachSendMessage &message,
+ kern_return_t SendMessage(MachSendMessage& message,
mach_msg_timeout_t timeout);
private:
diff --git a/src/common/mac/MachIPC.mm b/src/common/mac/MachIPC.mm
index dc9773f7..62e0f6b5 100644
--- a/src/common/mac/MachIPC.mm
+++ b/src/common/mac/MachIPC.mm
@@ -1,5 +1,4 @@
-// Copyright (c) 2007, Google Inc.
-// All rights reserved.
+// Copyright 2007 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -52,7 +51,7 @@ MachSendMessage::MachSendMessage(int32_t message_id) : MachMessage() {
//==============================================================================
// returns true if successful
-bool MachMessage::SetData(void *data,
+bool MachMessage::SetData(void* data,
int32_t data_length) {
// first check to make sure we have enough space
size_t size = CalculateSize();
@@ -90,9 +89,9 @@ mach_msg_size_t MachMessage::CalculateSize() {
}
//==============================================================================
-MachMessage::MessageDataPacket *MachMessage::GetDataPacket() {
+MachMessage::MessageDataPacket* MachMessage::GetDataPacket() {
size_t desc_size = sizeof(MachMsgPortDescriptor)*GetDescriptorCount();
- MessageDataPacket *packet =
+ MessageDataPacket* packet =
reinterpret_cast<MessageDataPacket*>(padding + desc_size);
return packet;
@@ -100,15 +99,15 @@ MachMessage::MessageDataPacket *MachMessage::GetDataPacket() {
//==============================================================================
void MachMessage::SetDescriptor(int n,
- const MachMsgPortDescriptor &desc) {
- MachMsgPortDescriptor *desc_array =
+ const MachMsgPortDescriptor& desc) {
+ MachMsgPortDescriptor* desc_array =
reinterpret_cast<MachMsgPortDescriptor*>(padding);
desc_array[n] = desc;
}
//==============================================================================
// returns true if successful otherwise there was not enough space
-bool MachMessage::AddDescriptor(const MachMsgPortDescriptor &desc) {
+bool MachMessage::AddDescriptor(const MachMsgPortDescriptor& desc) {
// first check to make sure we have enough space
int size = CalculateSize();
size_t new_size = size + sizeof(MachMsgPortDescriptor);
@@ -119,7 +118,7 @@ bool MachMessage::AddDescriptor(const MachMsgPortDescriptor &desc) {
// unfortunately, we need to move the data to allow space for the
// new descriptor
- u_int8_t *p = reinterpret_cast<u_int8_t*>(GetDataPacket());
+ u_int8_t* p = reinterpret_cast<u_int8_t*>(GetDataPacket());
bcopy(p, p+sizeof(MachMsgPortDescriptor), GetDataLength()+2*sizeof(int32_t));
SetDescriptor(GetDescriptorCount(), desc);
@@ -142,9 +141,9 @@ void MachMessage::SetDescriptorCount(int n) {
}
//==============================================================================
-MachMsgPortDescriptor *MachMessage::GetDescriptor(int n) {
+MachMsgPortDescriptor* MachMessage::GetDescriptor(int n) {
if (n < GetDescriptorCount()) {
- MachMsgPortDescriptor *desc =
+ MachMsgPortDescriptor* desc =
reinterpret_cast<MachMsgPortDescriptor*>(padding);
return desc + n;
}
@@ -164,7 +163,7 @@ mach_port_t MachMessage::GetTranslatedPort(int n) {
//==============================================================================
// create a new mach port for receiving messages and register a name for it
-ReceivePort::ReceivePort(const char *receive_port_name) {
+ReceivePort::ReceivePort(const char* receive_port_name) {
mach_port_t current_task = mach_task_self();
init_result_ = mach_port_allocate(current_task,
@@ -227,7 +226,7 @@ ReceivePort::~ReceivePort() {
}
//==============================================================================
-kern_return_t ReceivePort::WaitForMessage(MachReceiveMessage *out_message,
+kern_return_t ReceivePort::WaitForMessage(MachReceiveMessage* out_message,
mach_msg_timeout_t timeout) {
if (!out_message) {
return KERN_INVALID_ARGUMENT;
@@ -261,7 +260,7 @@ kern_return_t ReceivePort::WaitForMessage(MachReceiveMessage *out_message,
//==============================================================================
// get a port with send rights corresponding to a named registered service
-MachPortSender::MachPortSender(const char *receive_port_name) {
+MachPortSender::MachPortSender(const char* receive_port_name) {
mach_port_t task_bootstrap_port = 0;
init_result_ = task_get_bootstrap_port(mach_task_self(),
&task_bootstrap_port);
@@ -281,7 +280,7 @@ MachPortSender::MachPortSender(mach_port_t send_port)
}
//==============================================================================
-kern_return_t MachPortSender::SendMessage(MachSendMessage &message,
+kern_return_t MachPortSender::SendMessage(MachSendMessage& message,
mach_msg_timeout_t timeout) {
if (message.head.msgh_size == 0) {
return KERN_INVALID_VALUE; // just for safety -- never should occur
diff --git a/src/common/mac/SymbolCollectorClient.h b/src/common/mac/SymbolCollectorClient.h
new file mode 100644
index 00000000..367753a4
--- /dev/null
+++ b/src/common/mac/SymbolCollectorClient.h
@@ -0,0 +1,103 @@
+// Copyright 2020 Google LLC
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google LLC nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#import <Foundation/Foundation.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+/**
+ Represents a response from a sym-upload-v2 server to a createUploadURLOnServer
+ call.
+ */
+@interface UploadURLResponse : NSObject {
+ @protected
+ NSString* uploadURL_;
+ NSString* uploadKey_;
+}
+
+- (id)initWithUploadURL:(NSString*)uploadURL withUploadKey:(NSString*)uploadKey;
+
+- (NSString*)uploadURL;
+- (NSString*)uploadKey;
+@end
+
+/**
+ Possible return statuses from a sym-upload-v2 server to a
+ completeUploadOnServer call.
+ */
+typedef NS_ENUM(NSInteger, CompleteUploadResult) {
+ CompleteUploadResultOk,
+ CompleteUploadResultDuplicateData,
+ CompleteUploadResultError
+};
+
+/**
+ Possible return statuses from a sym-upload-v2 server to a
+ checkSymbolStatusOnServer call.
+ */
+typedef NS_ENUM(NSInteger, SymbolStatus) {
+ SymbolStatusFound,
+ SymbolStatusMissing,
+ SymbolStatusUnknown
+};
+
+/**
+ Interface to help a client interact with a sym-upload-v2 server, over HTTP.
+ For details of the API and protocol, see :/docs/sym_upload_v2_protocol.md.
+ */
+@interface SymbolCollectorClient : NSObject
+;
+
+/**
+ Calls the /v1/symbols/{debug_file}/{debug_id}:checkStatus API on the server.
+ */
++ (SymbolStatus)checkSymbolStatusOnServer:(NSString*)APIURL
+ withAPIKey:(NSString*)APIKey
+ withDebugFile:(NSString*)debugFile
+ withDebugID:(NSString*)debugID;
+
+/**
+ Calls the /v1/uploads:create API on the server.
+ */
++ (UploadURLResponse*)createUploadURLOnServer:(NSString*)APIURL
+ withAPIKey:(NSString*)APIKey;
+
+/**
+ Calls the /v1/uploads/{key}:complete API on the server.
+ */
++ (CompleteUploadResult)completeUploadOnServer:(NSString*)APIURL
+ withAPIKey:(NSString*)APIKey
+ withUploadKey:(NSString*)uploadKey
+ withDebugFile:(NSString*)debugFile
+ withDebugID:(NSString*)debugID
+ withType:(NSString*)type
+ withProductName:(NSString*)productName;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/src/common/mac/SymbolCollectorClient.m b/src/common/mac/SymbolCollectorClient.m
new file mode 100644
index 00000000..fd33432b
--- /dev/null
+++ b/src/common/mac/SymbolCollectorClient.m
@@ -0,0 +1,271 @@
+// Copyright 2020 Google LLC
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google LLC nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#import "SymbolCollectorClient.h"
+
+#import "HTTPGetRequest.h"
+#import "HTTPSimplePostRequest.h"
+
+@implementation UploadURLResponse
+
+//=============================================================================
+- (id)initWithUploadURL:(NSString*)uploadURL
+ withUploadKey:(NSString*)uploadKey {
+ if (self = [super init]) {
+ uploadURL_ = [uploadURL copy];
+ uploadKey_ = [uploadKey copy];
+ }
+ return self;
+}
+
+//=============================================================================
+- (void)dealloc {
+ [uploadURL_ release];
+ [uploadKey_ release];
+
+ [super dealloc];
+}
+
+//=============================================================================
+- (NSString*)uploadURL {
+ return uploadURL_;
+}
+
+//=============================================================================
+- (NSString*)uploadKey {
+ return uploadKey_;
+}
+@end
+
+@implementation SymbolCollectorClient
+
+//=============================================================================
++ (SymbolStatus)checkSymbolStatusOnServer:(NSString*)APIURL
+ withAPIKey:(NSString*)APIKey
+ withDebugFile:(NSString*)debugFile
+ withDebugID:(NSString*)debugID {
+ // Note that forward-slash is listed as a character to escape here, for
+ // completeness, however it is illegal in a debugFile input.
+ NSMutableCharacterSet* allowedDebugFileCharacters = [NSMutableCharacterSet
+ characterSetWithCharactersInString:@" \"\\/#%:?@|^`{}<>[]&=;"];
+ [allowedDebugFileCharacters
+ formUnionWithCharacterSet:[NSCharacterSet controlCharacterSet]];
+ [allowedDebugFileCharacters invert];
+ NSString* escapedDebugFile =
+ [debugFile stringByAddingPercentEncodingWithAllowedCharacters:
+ allowedDebugFileCharacters];
+
+ NSURL* URL = [NSURL
+ URLWithString:[NSString
+ stringWithFormat:@"%@/v1/symbols/%@/%@:checkStatus"
+ @"?key=%@",
+ APIURL, escapedDebugFile, debugID,
+ APIKey]];
+
+ HTTPGetRequest* getRequest = [[HTTPGetRequest alloc] initWithURL:URL];
+ NSError* error = nil;
+ NSData* data = [getRequest send:&error];
+ NSString* result = [[NSString alloc] initWithData:data
+ encoding:NSUTF8StringEncoding];
+ int responseCode = [[getRequest response] statusCode];
+ [getRequest release];
+
+ if (error || responseCode != 200) {
+ fprintf(stdout, "Failed to check symbol status.\n");
+ fprintf(stdout, "Response code: %d\n", responseCode);
+ fprintf(stdout, "Response:\n");
+ fprintf(stdout, "%s\n", [result UTF8String]);
+ return SymbolStatusUnknown;
+ }
+
+ error = nil;
+ NSRegularExpression* statusRegex = [NSRegularExpression
+ regularExpressionWithPattern:@"\"status\": \"([^\"]+)\""
+ options:0
+ error:&error];
+ NSArray* matches =
+ [statusRegex matchesInString:result
+ options:0
+ range:NSMakeRange(0, [result length])];
+ if ([matches count] != 1) {
+ fprintf(stdout, "Failed to parse check symbol status response.");
+ fprintf(stdout, "Response:\n");
+ fprintf(stdout, "%s\n", [result UTF8String]);
+ return SymbolStatusUnknown;
+ }
+
+ NSString* status = [result substringWithRange:[matches[0] rangeAtIndex:1]];
+ [result release];
+
+ return [status isEqualToString:@"FOUND"] ? SymbolStatusFound
+ : SymbolStatusMissing;
+}
+
+//=============================================================================
++ (UploadURLResponse*)createUploadURLOnServer:(NSString*)APIURL
+ withAPIKey:(NSString*)APIKey {
+ NSURL* URL = [NSURL
+ URLWithString:[NSString stringWithFormat:@"%@/v1/uploads:create?key=%@",
+ APIURL, APIKey]];
+
+ HTTPSimplePostRequest* postRequest =
+ [[HTTPSimplePostRequest alloc] initWithURL:URL];
+ NSError* error = nil;
+ NSData* data = [postRequest send:&error];
+ NSString* result = [[NSString alloc] initWithData:data
+ encoding:NSUTF8StringEncoding];
+ int responseCode = [[postRequest response] statusCode];
+ [postRequest release];
+
+ if (error || responseCode != 200) {
+ fprintf(stdout, "Failed to create upload URL.\n");
+ fprintf(stdout, "Response code: %d\n", responseCode);
+ fprintf(stdout, "Response:\n");
+ fprintf(stdout, "%s\n", [result UTF8String]);
+ return nil;
+ }
+
+ // Note camel-case rather than underscores.
+ NSRegularExpression* uploadURLRegex = [NSRegularExpression
+ regularExpressionWithPattern:@"\"uploadUrl\": \"([^\"]+)\""
+ options:0
+ error:&error];
+ NSRegularExpression* uploadKeyRegex = [NSRegularExpression
+ regularExpressionWithPattern:@"\"uploadKey\": \"([^\"]+)\""
+ options:0
+ error:&error];
+
+ NSArray* uploadURLMatches =
+ [uploadURLRegex matchesInString:result
+ options:0
+ range:NSMakeRange(0, [result length])];
+ NSArray* uploadKeyMatches =
+ [uploadKeyRegex matchesInString:result
+ options:0
+ range:NSMakeRange(0, [result length])];
+ if ([uploadURLMatches count] != 1 || [uploadKeyMatches count] != 1) {
+ fprintf(stdout, "Failed to parse create url response.");
+ fprintf(stdout, "Response:\n");
+ fprintf(stdout, "%s\n", [result UTF8String]);
+ return nil;
+ }
+ NSString* uploadURL =
+ [result substringWithRange:[uploadURLMatches[0] rangeAtIndex:1]];
+ NSString* uploadKey =
+ [result substringWithRange:[uploadKeyMatches[0] rangeAtIndex:1]];
+
+ return [[UploadURLResponse alloc] initWithUploadURL:uploadURL
+ withUploadKey:uploadKey];
+}
+
+//=============================================================================
++ (CompleteUploadResult)completeUploadOnServer:(NSString*)APIURL
+ withAPIKey:(NSString*)APIKey
+ withUploadKey:(NSString*)uploadKey
+ withDebugFile:(NSString*)debugFile
+ withDebugID:(NSString*)debugID
+ withType:(NSString*)type
+ withProductName:(NSString*)productName {
+ NSURL* URL = [NSURL
+ URLWithString:[NSString
+ stringWithFormat:@"%@/v1/uploads/%@:complete?key=%@",
+ APIURL, uploadKey, APIKey]];
+
+ NSMutableDictionary* jsonDictionary = [@{
+ @"symbol_id" : @{@"debug_file" : debugFile, @"debug_id" : debugID},
+ @"symbol_upload_type" : type, @"use_async_processing" : @"true"
+ } mutableCopy];
+
+ if (productName != nil) {
+ jsonDictionary[@"metadata"] = @{@"product_name": productName};
+ }
+
+ NSError* error = nil;
+ NSData* jsonData =
+ [NSJSONSerialization dataWithJSONObject:jsonDictionary
+ options:NSJSONWritingPrettyPrinted
+ error:&error];
+ if (jsonData == nil) {
+ fprintf(stdout, "Error: %s\n", [[error localizedDescription] UTF8String]);
+ fprintf(stdout,
+ "Failed to complete upload. Could not write JSON payload.\n");
+ return CompleteUploadResultError;
+ }
+
+ NSString* body = [[NSString alloc] initWithData:jsonData
+ encoding:NSUTF8StringEncoding];
+ HTTPSimplePostRequest* postRequest =
+ [[HTTPSimplePostRequest alloc] initWithURL:URL];
+ [postRequest setBody:body];
+ [postRequest setContentType:@"application/json"];
+
+ NSData* data = [postRequest send:&error];
+ if (data == nil) {
+ fprintf(stdout, "Error: %s\n", [[error localizedDescription] UTF8String]);
+ fprintf(stdout, "Failed to complete upload URL.\n");
+ return CompleteUploadResultError;
+ }
+
+ NSString* result = [[NSString alloc] initWithData:data
+ encoding:NSUTF8StringEncoding];
+ int responseCode = [[postRequest response] statusCode];
+ [postRequest release];
+ if (responseCode != 200) {
+ fprintf(stdout, "Failed to complete upload URL.\n");
+ fprintf(stdout, "Response code: %d\n", responseCode);
+ fprintf(stdout, "Response:\n");
+ fprintf(stdout, "%s\n", [result UTF8String]);
+ return CompleteUploadResultError;
+ }
+
+ // Note camel-case rather than underscores.
+ NSRegularExpression* completeResultRegex = [NSRegularExpression
+ regularExpressionWithPattern:@"\"result\": \"([^\"]+)\""
+ options:0
+ error:&error];
+
+ NSArray* completeResultMatches =
+ [completeResultRegex matchesInString:result
+ options:0
+ range:NSMakeRange(0, [result length])];
+
+ if ([completeResultMatches count] != 1) {
+ fprintf(stdout, "Failed to parse complete upload response.");
+ fprintf(stdout, "Response:\n");
+ fprintf(stdout, "%s\n", [result UTF8String]);
+ return CompleteUploadResultError;
+ }
+ NSString* completeResult =
+ [result substringWithRange:[completeResultMatches[0] rangeAtIndex:1]];
+ [result release];
+
+ return ([completeResult isEqualToString:@"DUPLICATE_DATA"])
+ ? CompleteUploadResultDuplicateData
+ : CompleteUploadResultOk;
+}
+@end
diff --git a/src/common/mac/arch_utilities.cc b/src/common/mac/arch_utilities.cc
index c0e4bac5..392efe78 100644
--- a/src/common/mac/arch_utilities.cc
+++ b/src/common/mac/arch_utilities.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2012, Google Inc.
-// All rights reserved.
+// Copyright 2012 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -130,7 +129,10 @@ const NXArchInfo* BreakpadGetArchInfoFromCpuType(cpu_type_t cpu_type,
} // namespace google_breakpad
-#ifndef __APPLE__
+// TODO(crbug.com/1242776): The "#ifndef __APPLE__" should be here, but the
+// system version of NXGetLocalArchInfo returns incorrect information on
+// x86_64 machines (treating them as just x86), so use the Breakpad version
+// all the time for now.
namespace {
enum Architecture {
@@ -219,6 +221,8 @@ const NXArchInfo *NXGetLocalArchInfo(void) {
return &kKnownArchitectures[arch];
}
+#ifndef __APPLE__
+
const NXArchInfo *NXGetArchInfoFromName(const char *name) {
for (int arch = 0; arch < kNumArchitectures; ++arch) {
if (!strcmp(name, kKnownArchitectures[arch].name)) {
diff --git a/src/common/mac/arch_utilities.h b/src/common/mac/arch_utilities.h
index 397c1f58..d267c43b 100644
--- a/src/common/mac/arch_utilities.h
+++ b/src/common/mac/arch_utilities.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2012, Google Inc.
-// All rights reserved.
+// Copyright 2012 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/common/mac/bootstrap_compat.cc b/src/common/mac/bootstrap_compat.cc
index d875d95b..6647bae3 100644
--- a/src/common/mac/bootstrap_compat.cc
+++ b/src/common/mac/bootstrap_compat.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2012, Google Inc.
-// All rights reserved.
+// Copyright 2012 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/common/mac/bootstrap_compat.h b/src/common/mac/bootstrap_compat.h
index 8ca7357c..b57d9070 100644
--- a/src/common/mac/bootstrap_compat.h
+++ b/src/common/mac/bootstrap_compat.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2012, Google Inc.
-// All rights reserved.
+// Copyright 2012 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/common/mac/byteswap.h b/src/common/mac/byteswap.h
index b7bbc0b9..c4c7e617 100644
--- a/src/common/mac/byteswap.h
+++ b/src/common/mac/byteswap.h
@@ -1,7 +1,6 @@
// -*- mode: c++ -*-
-// Copyright (c) 2010, Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -13,7 +12,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/common/mac/dump_syms.cc b/src/common/mac/dump_syms.cc
index 3fbedd95..9658b2c6 100644
--- a/src/common/mac/dump_syms.cc
+++ b/src/common/mac/dump_syms.cc
@@ -1,7 +1,6 @@
// -*- mode: c++ -*-
-// Copyright (c) 2011, Google Inc.
-// All rights reserved.
+// Copyright 2011 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -13,7 +12,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -74,12 +73,12 @@
#define CPU_TYPE_ARM64 (static_cast<cpu_type_t>(16777228))
#endif // CPU_TYPE_ARM64
-using dwarf2reader::ByteReader;
+using google_breakpad::ByteReader;
using google_breakpad::DwarfCUToModule;
using google_breakpad::DwarfLineToModule;
using google_breakpad::DwarfRangeListHandler;
-using google_breakpad::FileID;
using google_breakpad::mach_o::FatReader;
+using google_breakpad::mach_o::FileID;
using google_breakpad::mach_o::Section;
using google_breakpad::mach_o::Segment;
using google_breakpad::Module;
@@ -120,7 +119,8 @@ vector<string> list_directory(const string& directory) {
namespace google_breakpad {
-bool DumpSymbols::Read(const string &filename) {
+bool DumpSymbols::Read(const string& filename) {
+ selected_object_file_ = nullptr;
struct stat st;
if (stat(filename.c_str(), &st) == -1) {
fprintf(stderr, "Could not access object file %s: %s\n",
@@ -128,10 +128,11 @@ bool DumpSymbols::Read(const string &filename) {
return false;
}
- input_pathname_ = filename;
+ from_disk_ = true;
// Does this filename refer to a dSYM bundle?
- string contents_path = input_pathname_ + "/Contents/Resources/DWARF";
+ string contents_path = filename + "/Contents/Resources/DWARF";
+ string object_filename;
if (S_ISDIR(st.st_mode) &&
access(contents_path.c_str(), F_OK) == 0) {
// If there's one file under Contents/Resources/DWARF then use that,
@@ -139,30 +140,31 @@ bool DumpSymbols::Read(const string &filename) {
const vector<string> entries = list_directory(contents_path);
if (entries.size() == 0) {
fprintf(stderr, "Unable to find DWARF-bearing file in bundle: %s\n",
- input_pathname_.c_str());
+ filename.c_str());
return false;
}
if (entries.size() > 1) {
fprintf(stderr, "Too many DWARF files in bundle: %s\n",
- input_pathname_.c_str());
+ filename.c_str());
return false;
}
- object_filename_ = entries[0];
+ object_filename = entries[0];
} else {
- object_filename_ = input_pathname_;
+ object_filename = filename;
}
// Read the file's contents into memory.
bool read_ok = true;
string error;
- if (stat(object_filename_.c_str(), &st) != -1) {
- FILE* f = fopen(object_filename_.c_str(), "rb");
+ scoped_array<uint8_t> contents;
+ off_t total = 0;
+ if (stat(object_filename.c_str(), &st) != -1) {
+ FILE* f = fopen(object_filename.c_str(), "rb");
if (f) {
- contents_.reset(new uint8_t[st.st_size]);
- off_t total = 0;
+ contents.reset(new uint8_t[st.st_size]);
while (total < st.st_size && !feof(f)) {
- size_t read = fread(&contents_[0] + total, 1, st.st_size - total, f);
+ size_t read = fread(&contents[0] + total, 1, st.st_size - total, f);
if (read == 0) {
if (ferror(f)) {
read_ok = false;
@@ -180,22 +182,28 @@ bool DumpSymbols::Read(const string &filename) {
if (!read_ok) {
fprintf(stderr, "Error reading object file: %s: %s\n",
- object_filename_.c_str(),
- error.c_str());
+ object_filename.c_str(), error.c_str());
return false;
}
+ return ReadData(contents.release(), total, object_filename);
+}
+
+bool DumpSymbols::ReadData(uint8_t* contents, size_t size,
+ const std::string& filename) {
+ contents_.reset(contents);
+ size_ = size;
+ object_filename_ = filename;
// Get the list of object files present in the file.
FatReader::Reporter fat_reporter(object_filename_);
FatReader fat_reader(&fat_reporter);
- if (!fat_reader.Read(&contents_[0],
- st.st_size)) {
+ if (!fat_reader.Read(contents_.get(), size)) {
return false;
}
// Get our own copy of fat_reader's object file list.
size_t object_files_count;
- const SuperFatArch *object_files =
+ const SuperFatArch* object_files =
fat_reader.object_files(&object_files_count);
if (object_files_count == 0) {
fprintf(stderr, "Fat binary file contains *no* architectures: %s\n",
@@ -212,7 +220,7 @@ bool DumpSymbols::Read(const string &filename) {
bool DumpSymbols::SetArchitecture(cpu_type_t cpu_type,
cpu_subtype_t cpu_subtype) {
// Find the best match for the architecture the user requested.
- const SuperFatArch *best_match = FindBestMatchForArchitecture(
+ const SuperFatArch* best_match = FindBestMatchForArchitecture(
cpu_type, cpu_subtype);
if (!best_match) return false;
@@ -221,9 +229,9 @@ bool DumpSymbols::SetArchitecture(cpu_type_t cpu_type,
return true;
}
-bool DumpSymbols::SetArchitecture(const std::string &arch_name) {
+bool DumpSymbols::SetArchitecture(const std::string& arch_name) {
bool arch_set = false;
- const NXArchInfo *arch_info =
+ const NXArchInfo* arch_info =
google_breakpad::BreakpadGetArchInfoFromName(arch_name.c_str());
if (arch_info) {
arch_set = SetArchitecture(arch_info->cputype, arch_info->cpusubtype);
@@ -251,7 +259,7 @@ SuperFatArch* DumpSymbols::FindBestMatchForArchitecture(
// If all the object files can be converted to struct fat_arch, use
// NXFindBestFatArch.
if (can_convert_to_fat_arch) {
- const struct fat_arch *best_match
+ const struct fat_arch* best_match
= NXFindBestFatArch(cpu_type, cpu_subtype, &fat_arch_vector[0],
static_cast<uint32_t>(fat_arch_vector.size()));
@@ -260,7 +268,8 @@ SuperFatArch* DumpSymbols::FindBestMatchForArchitecture(
return &object_files_[i];
}
assert(best_match == NULL);
- return NULL;
+ // Fall through since NXFindBestFatArch can't find arm slices on x86_64
+ // macOS 13. See FB11955188.
}
// Check for an exact match with cpu_type and cpu_subtype.
@@ -268,7 +277,8 @@ SuperFatArch* DumpSymbols::FindBestMatchForArchitecture(
it != object_files_.end();
++it) {
if (static_cast<cpu_type_t>(it->cputype) == cpu_type &&
- static_cast<cpu_subtype_t>(it->cpusubtype) == cpu_subtype)
+ (static_cast<cpu_subtype_t>(it->cpusubtype) & ~CPU_SUBTYPE_MASK) ==
+ (cpu_subtype & ~CPU_SUBTYPE_MASK))
return &*it;
}
@@ -277,17 +287,31 @@ SuperFatArch* DumpSymbols::FindBestMatchForArchitecture(
// NXFindBestFatArch, located at
// http://web.mit.edu/darwin/src/modules/cctools/libmacho/arch.c.
fprintf(stderr, "Failed to find an exact match for an object file with cpu "
- "type: %d and cpu subtype: %d. Furthermore, at least one object file is "
- "larger than 2**32.\n", cpu_type, cpu_subtype);
+ "type: %d and cpu subtype: %d.\n", cpu_type, cpu_subtype);
+ if (!can_convert_to_fat_arch) {
+ fprintf(stderr, "Furthermore, at least one object file is larger "
+ "than 2**32.\n");
+ }
return NULL;
}
string DumpSymbols::Identifier() {
- FileID file_id(object_filename_.c_str());
+ scoped_ptr<FileID> file_id;
+
+ if (from_disk_) {
+ file_id.reset(new FileID(object_filename_.c_str()));
+ } else {
+ file_id.reset(new FileID(contents_.get(), size_));
+ }
unsigned char identifier_bytes[16];
+ scoped_ptr<Module> module;
+ if (!selected_object_file_) {
+ if (!CreateEmptyModule(module))
+ return string();
+ }
cpu_type_t cpu_type = selected_object_file_->cputype;
cpu_subtype_t cpu_subtype = selected_object_file_->cpusubtype;
- if (!file_id.MachoIdentifier(cpu_type, cpu_subtype, identifier_bytes)) {
+ if (!file_id->MachoIdentifier(cpu_type, cpu_subtype, identifier_bytes)) {
fprintf(stderr, "Unable to calculate UUID of mach-o binary %s!\n",
object_filename_.c_str());
return "";
@@ -302,57 +326,67 @@ string DumpSymbols::Identifier() {
i = compacted.find('-', i))
compacted.erase(i, 1);
+ // The pdb for these IDs has an extra byte, so to make everything uniform put
+ // a 0 on the end of mac IDs.
+ compacted += "0";
+
return compacted;
}
// A range handler that accepts rangelist data parsed by
-// dwarf2reader::RangeListReader and populates a range vector (typically
+// RangeListReader and populates a range vector (typically
// owned by a function) with the results.
class DumpSymbols::DumperRangesHandler:
public DwarfCUToModule::RangesHandler {
public:
- DumperRangesHandler(const uint8_t *buffer, uint64_t size,
- dwarf2reader::ByteReader* reader)
- : buffer_(buffer), size_(size), reader_(reader) { }
-
- bool ReadRanges(uint64_t offset, Module::Address base_address,
- vector<Module::Range>* ranges) {
- DwarfRangeListHandler handler(base_address, ranges);
- dwarf2reader::RangeListReader rangelist_reader(buffer_, size_, reader_,
- &handler);
-
- return rangelist_reader.ReadRangeList(offset);
+ DumperRangesHandler(ByteReader* reader) :
+ reader_(reader) { }
+
+ bool ReadRanges(
+ enum DwarfForm form, uint64_t data,
+ RangeListReader::CURangesInfo* cu_info,
+ vector<Module::Range>* ranges) {
+ DwarfRangeListHandler handler(ranges);
+ RangeListReader range_list_reader(reader_, cu_info,
+ &handler);
+ return range_list_reader.ReadRanges(form, data);
}
private:
- const uint8_t *buffer_;
- uint64_t size_;
- dwarf2reader::ByteReader* reader_;
+ ByteReader* reader_;
};
// A line-to-module loader that accepts line number info parsed by
-// dwarf2reader::LineInfo and populates a Module and a line vector
+// LineInfo and populates a Module and a line vector
// with the results.
class DumpSymbols::DumperLineToModule:
public DwarfCUToModule::LineToModuleHandler {
public:
// Create a line-to-module converter using BYTE_READER.
- DumperLineToModule(dwarf2reader::ByteReader *byte_reader)
+ DumperLineToModule(ByteReader* byte_reader)
: byte_reader_(byte_reader) { }
void StartCompilationUnit(const string& compilation_dir) {
compilation_dir_ = compilation_dir;
}
- void ReadProgram(const uint8_t *program, uint64_t length,
- Module *module, vector<Module::Line> *lines) {
- DwarfLineToModule handler(module, compilation_dir_, lines);
- dwarf2reader::LineInfo parser(program, length, byte_reader_, &handler);
+ void ReadProgram(const uint8_t* program,
+ uint64_t length,
+ const uint8_t* string_section,
+ uint64_t string_section_length,
+ const uint8_t* line_string_section,
+ uint64_t line_string_section_length,
+ Module* module,
+ vector<Module::Line>* lines,
+ std::map<uint32_t, Module::File*>* files) {
+ DwarfLineToModule handler(module, compilation_dir_, lines, files);
+ LineInfo parser(program, length, byte_reader_, nullptr, 0,
+ nullptr, 0, &handler);
parser.Start();
}
private:
string compilation_dir_;
- dwarf2reader::ByteReader *byte_reader_; // WEAK
+ ByteReader* byte_reader_; // WEAK
};
bool DumpSymbols::CreateEmptyModule(scoped_ptr<Module>& module) {
@@ -364,7 +398,7 @@ bool DumpSymbols::CreateEmptyModule(scoped_ptr<Module>& module) {
selected_object_file_ = &object_files_[0];
else {
// Look for an object file whose architecture matches our own.
- const NXArchInfo *local_arch = NXGetLocalArchInfo();
+ const NXArchInfo* local_arch = NXGetLocalArchInfo();
if (!SetArchitecture(local_arch->cputype, local_arch->cpusubtype)) {
fprintf(stderr, "%s: object file contains more than one"
" architecture, none of which match the current"
@@ -380,11 +414,18 @@ bool DumpSymbols::CreateEmptyModule(scoped_ptr<Module>& module) {
// Find the name of the selected file's architecture, to appear in
// the MODULE record and in error messages.
- const NXArchInfo *selected_arch_info =
+ const NXArchInfo* selected_arch_info =
google_breakpad::BreakpadGetArchInfoFromCpuType(
selected_object_file_->cputype, selected_object_file_->cpusubtype);
- const char *selected_arch_name = selected_arch_info->name;
+ // In certain cases, it is possible that architecture info can't be reliably
+ // determined, e.g. new architectures that breakpad is unware of. In that
+ // case, avoid crashing and return false instead.
+ if (selected_arch_info == NULL) {
+ return false;
+ }
+
+ const char* selected_arch_name = selected_arch_info->name;
if (strcmp(selected_arch_name, "i386") == 0)
selected_arch_name = "x86";
@@ -403,31 +444,28 @@ bool DumpSymbols::CreateEmptyModule(scoped_ptr<Module>& module) {
string identifier = Identifier();
if (identifier.empty())
return false;
- identifier += "0";
// Create a module to hold the debugging information.
- module.reset(new Module(module_name,
- "mac",
- selected_arch_name,
- identifier));
+ module.reset(new Module(module_name, "mac", selected_arch_name, identifier,
+ "", enable_multiple_));
return true;
}
-void DumpSymbols::ReadDwarf(google_breakpad::Module *module,
- const mach_o::Reader &macho_reader,
- const mach_o::SectionMap &dwarf_sections,
+void DumpSymbols::ReadDwarf(google_breakpad::Module* module,
+ const mach_o::Reader& macho_reader,
+ const mach_o::SectionMap& dwarf_sections,
bool handle_inter_cu_refs) const {
// Build a byte reader of the appropriate endianness.
ByteReader byte_reader(macho_reader.big_endian()
- ? dwarf2reader::ENDIANNESS_BIG
- : dwarf2reader::ENDIANNESS_LITTLE);
+ ? ENDIANNESS_BIG
+ : ENDIANNESS_LITTLE);
// Construct a context for this file.
DwarfCUToModule::FileContext file_context(selected_object_name_,
module,
handle_inter_cu_refs);
- // Build a dwarf2reader::SectionMap from our mach_o::SectionMap.
+ // Build a SectionMap from our mach_o::SectionMap.
for (mach_o::SectionMap::const_iterator it = dwarf_sections.begin();
it != dwarf_sections.end(); ++it) {
file_context.AddSectionToSectionMap(
@@ -437,7 +475,7 @@ void DumpSymbols::ReadDwarf(google_breakpad::Module *module,
}
// Find the __debug_info section.
- dwarf2reader::SectionMap::const_iterator debug_info_entry =
+ SectionMap::const_iterator debug_info_entry =
file_context.section_map().find("__debug_info");
// There had better be a __debug_info section!
if (debug_info_entry == file_context.section_map().end()) {
@@ -451,17 +489,8 @@ void DumpSymbols::ReadDwarf(google_breakpad::Module *module,
// Build a line-to-module loader for the root handler to use.
DumperLineToModule line_to_module(&byte_reader);
- // Optional .debug_ranges reader
- scoped_ptr<DumperRangesHandler> ranges_handler;
- dwarf2reader::SectionMap::const_iterator ranges_entry =
- file_context.section_map().find("__debug_ranges");
- if (ranges_entry != file_context.section_map().end()) {
- const std::pair<const uint8_t *, uint64_t>& ranges_section =
- ranges_entry->second;
- ranges_handler.reset(
- new DumperRangesHandler(ranges_section.first, ranges_section.second,
- &byte_reader));
- }
+ // .debug_ranges and .debug_rngslists reader
+ DumperRangesHandler ranges_handler(&byte_reader);
// Walk the __debug_info section, one compilation unit at a time.
uint64_t debug_info_length = debug_info_section.second;
@@ -471,11 +500,12 @@ void DumpSymbols::ReadDwarf(google_breakpad::Module *module,
DwarfCUToModule::WarningReporter reporter(selected_object_name_,
offset);
DwarfCUToModule root_handler(&file_context, &line_to_module,
- ranges_handler.get(), &reporter);
+ &ranges_handler, &reporter,
+ symbol_data_ & INLINES);
// Make a Dwarf2Handler that drives our DIEHandler.
- dwarf2reader::DIEDispatcher die_dispatcher(&root_handler);
+ DIEDispatcher die_dispatcher(&root_handler);
// Make a DWARF parser for the compilation unit at OFFSET.
- dwarf2reader::CompilationUnit dwarf_reader(selected_object_name_,
+ CompilationUnit dwarf_reader(selected_object_name_,
file_context.section_map(),
offset,
&byte_reader,
@@ -485,9 +515,9 @@ void DumpSymbols::ReadDwarf(google_breakpad::Module *module,
}
}
-bool DumpSymbols::ReadCFI(google_breakpad::Module *module,
- const mach_o::Reader &macho_reader,
- const mach_o::Section &section,
+bool DumpSymbols::ReadCFI(google_breakpad::Module* module,
+ const mach_o::Reader& macho_reader,
+ const mach_o::Section& section,
bool eh_frame) const {
// Find the appropriate set of register names for this file's
// architecture.
@@ -506,7 +536,7 @@ bool DumpSymbols::ReadCFI(google_breakpad::Module *module,
register_names = DwarfCFIToModule::RegisterNames::ARM64();
break;
default: {
- const NXArchInfo *arch = google_breakpad::BreakpadGetArchInfoFromCpuType(
+ const NXArchInfo* arch = google_breakpad::BreakpadGetArchInfoFromCpuType(
macho_reader.cpu_type(), macho_reader.cpu_subtype());
fprintf(stderr, "%s: cannot convert DWARF call frame information for ",
selected_object_name_.c_str());
@@ -521,25 +551,25 @@ bool DumpSymbols::ReadCFI(google_breakpad::Module *module,
}
// Find the call frame information and its size.
- const uint8_t *cfi = section.contents.start;
+ const uint8_t* cfi = section.contents.start;
size_t cfi_size = section.contents.Size();
// Plug together the parser, handler, and their entourages.
DwarfCFIToModule::Reporter module_reporter(selected_object_name_,
section.section_name);
DwarfCFIToModule handler(module, register_names, &module_reporter);
- dwarf2reader::ByteReader byte_reader(macho_reader.big_endian() ?
- dwarf2reader::ENDIANNESS_BIG :
- dwarf2reader::ENDIANNESS_LITTLE);
+ ByteReader byte_reader(macho_reader.big_endian() ?
+ ENDIANNESS_BIG :
+ ENDIANNESS_LITTLE);
byte_reader.SetAddressSize(macho_reader.bits_64() ? 8 : 4);
// At the moment, according to folks at Apple and some cursory
// investigation, Mac OS X only uses DW_EH_PE_pcrel-based pointers, so
// this is the only base address the CFI parser will need.
byte_reader.SetCFIDataBase(section.address, cfi);
- dwarf2reader::CallFrameInfo::Reporter dwarf_reporter(selected_object_name_,
+ CallFrameInfo::Reporter dwarf_reporter(selected_object_name_,
section.section_name);
- dwarf2reader::CallFrameInfo parser(cfi, cfi_size,
+ CallFrameInfo parser(cfi, cfi_size,
&byte_reader, &handler, &dwarf_reporter,
eh_frame);
parser.Start();
@@ -553,9 +583,9 @@ class DumpSymbols::LoadCommandDumper:
public:
// Create a load command dumper handling load commands from READER's
// file, and adding data to MODULE.
- LoadCommandDumper(const DumpSymbols &dumper,
- google_breakpad::Module *module,
- const mach_o::Reader &reader,
+ LoadCommandDumper(const DumpSymbols& dumper,
+ google_breakpad::Module* module,
+ const mach_o::Reader& reader,
SymbolData symbol_data,
bool handle_inter_cu_refs)
: dumper_(dumper),
@@ -564,25 +594,25 @@ class DumpSymbols::LoadCommandDumper:
symbol_data_(symbol_data),
handle_inter_cu_refs_(handle_inter_cu_refs) { }
- bool SegmentCommand(const mach_o::Segment &segment);
- bool SymtabCommand(const ByteBuffer &entries, const ByteBuffer &strings);
+ bool SegmentCommand(const mach_o::Segment& segment);
+ bool SymtabCommand(const ByteBuffer& entries, const ByteBuffer& strings);
private:
- const DumpSymbols &dumper_;
- google_breakpad::Module *module_; // WEAK
- const mach_o::Reader &reader_;
+ const DumpSymbols& dumper_;
+ google_breakpad::Module* module_; // WEAK
+ const mach_o::Reader& reader_;
const SymbolData symbol_data_;
const bool handle_inter_cu_refs_;
};
-bool DumpSymbols::LoadCommandDumper::SegmentCommand(const Segment &segment) {
+bool DumpSymbols::LoadCommandDumper::SegmentCommand(const Segment& segment) {
mach_o::SectionMap section_map;
if (!reader_.MapSegmentSections(segment, &section_map))
return false;
if (segment.name == "__TEXT") {
module_->SetLoadAddress(segment.vmaddr);
- if (symbol_data_ != NO_CFI) {
+ if (symbol_data_ & CFI) {
mach_o::SectionMap::const_iterator eh_frame =
section_map.find("__eh_frame");
if (eh_frame != section_map.end()) {
@@ -594,10 +624,10 @@ bool DumpSymbols::LoadCommandDumper::SegmentCommand(const Segment &segment) {
}
if (segment.name == "__DWARF") {
- if (symbol_data_ != ONLY_CFI) {
+ if ((symbol_data_ & SYMBOLS_AND_FILES) || (symbol_data_ & INLINES)) {
dumper_.ReadDwarf(module_, reader_, section_map, handle_inter_cu_refs_);
}
- if (symbol_data_ != NO_CFI) {
+ if (symbol_data_ & CFI) {
mach_o::SectionMap::const_iterator debug_frame
= section_map.find("__debug_frame");
if (debug_frame != section_map.end()) {
@@ -610,8 +640,8 @@ bool DumpSymbols::LoadCommandDumper::SegmentCommand(const Segment &segment) {
return true;
}
-bool DumpSymbols::LoadCommandDumper::SymtabCommand(const ByteBuffer &entries,
- const ByteBuffer &strings) {
+bool DumpSymbols::LoadCommandDumper::SymtabCommand(const ByteBuffer& entries,
+ const ByteBuffer& strings) {
StabsToModule stabs_to_module(module_);
// Mac OS X STABS are never "unitized", and the size of the 'value' field
// matches the address size of the executable.
@@ -653,22 +683,10 @@ bool DumpSymbols::ReadSymbolData(Module** out_module) {
return true;
}
-bool DumpSymbols::WriteSymbolFile(std::ostream &stream) {
- Module* module = NULL;
-
- if (ReadSymbolData(&module) && module) {
- bool res = module->Write(stream, symbol_data_);
- delete module;
- return res;
- }
-
- return false;
-}
-
// Read the selected object file's debugging information, and write out the
// header only to |stream|. Return true on success; if an error occurs, report
// it and return false.
-bool DumpSymbols::WriteSymbolFileHeader(std::ostream &stream) {
+bool DumpSymbols::WriteSymbolFileHeader(std::ostream& stream) {
scoped_ptr<Module> module;
if (!CreateEmptyModule(module))
return false;
diff --git a/src/common/mac/dump_syms.h b/src/common/mac/dump_syms.h
index 1e57f86d..c2e1b40b 100644
--- a/src/common/mac/dump_syms.h
+++ b/src/common/mac/dump_syms.h
@@ -1,7 +1,6 @@
// -*- mode: c++ -*-
-// Copyright (c) 2011, Google Inc.
-// All rights reserved.
+// Copyright 2011 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -13,7 +12,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -54,23 +53,34 @@ namespace google_breakpad {
class DumpSymbols {
public:
- DumpSymbols(SymbolData symbol_data, bool handle_inter_cu_refs)
+ DumpSymbols(SymbolData symbol_data,
+ bool handle_inter_cu_refs,
+ bool enable_multiple = false)
: symbol_data_(symbol_data),
handle_inter_cu_refs_(handle_inter_cu_refs),
- input_pathname_(),
object_filename_(),
contents_(),
+ size_(0),
+ from_disk_(false),
object_files_(),
selected_object_file_(),
- selected_object_name_() { }
- ~DumpSymbols() {
- }
+ selected_object_name_(),
+ enable_multiple_(enable_multiple) {}
+ ~DumpSymbols() = default;
// Prepare to read debugging information from |filename|. |filename| may be
- // the name of a universal binary, a Mach-O file, or a dSYM bundle
- // containing either of the above. On success, return true; if there is a
- // problem reading |filename|, report it and return false.
- bool Read(const std::string &filename);
+ // the name of a fat file, a Mach-O file, or a dSYM bundle containing either
+ // of the above. On success, return true; if there is a problem reading
+ // |filename|, report it and return false.
+ bool Read(const std::string& filename);
+
+ // Prepare to read debugging information from |contents|. |contents| is
+ // expected to be the data obtained from reading a fat file, or a Mach-O file.
+ // |filename| is used to determine the object filename in the generated
+ // output; there will not be an attempt to open this file as the data
+ // is already expected to be in memory. On success, return true; if there is a
+ // problem reading |contents|, report it and return false.
+ bool ReadData(uint8_t* contents, size_t size, const std::string& filename);
// If this dumper's file includes an object file for |cpu_type| and
// |cpu_subtype|, then select that object file for dumping, and return
@@ -91,7 +101,7 @@ class DumpSymbols {
// the dumper will dump those symbols; and if it contains more than one
// object file, then the dumper will dump the object file whose
// architecture matches that of this dumper program.
- bool SetArchitecture(const std::string &arch_name);
+ bool SetArchitecture(const std::string& arch_name);
// Return a pointer to an array of SuperFatArch structures describing the
// object files contained in this dumper's file. Set *|count| to the number
@@ -100,28 +110,26 @@ class DumpSymbols {
//
// If there are no available architectures, this function
// may return NULL.
- const SuperFatArch* AvailableArchitectures(size_t *count) {
+ const SuperFatArch* AvailableArchitectures(size_t* count) {
*count = object_files_.size();
if (object_files_.size() > 0)
return &object_files_[0];
return NULL;
}
- // Read the selected object file's debugging information, and write it out to
- // |stream|. Return true on success; if an error occurs, report it and
- // return false.
- bool WriteSymbolFile(std::ostream &stream);
-
// Read the selected object file's debugging information, and write out the
// header only to |stream|. Return true on success; if an error occurs, report
// it and return false.
- bool WriteSymbolFileHeader(std::ostream &stream);
+ bool WriteSymbolFileHeader(std::ostream& stream);
- // As above, but simply return the debugging information in module
- // instead of writing it to a stream. The caller owns the resulting
- // module object and must delete it when finished.
+ // Read the selected object file's debugging information and store it in
+ // `module`. The caller owns the resulting module object and must delete
+ // it when finished.
bool ReadSymbolData(Module** module);
+ // Return an identifier string for the file this DumpSymbols is dumping.
+ std::string Identifier();
+
private:
// Used internally.
class DumperLineToModule;
@@ -133,18 +141,14 @@ class DumpSymbols {
SuperFatArch* FindBestMatchForArchitecture(
cpu_type_t cpu_type, cpu_subtype_t cpu_subtype);
- // Return an identifier string for the file this DumpSymbols is dumping.
- std::string Identifier();
-
-
// Creates an empty module object.
bool CreateEmptyModule(scoped_ptr<Module>& module);
// Read debugging information from |dwarf_sections|, which was taken from
// |macho_reader|, and add it to |module|.
- void ReadDwarf(google_breakpad::Module *module,
- const mach_o::Reader &macho_reader,
- const mach_o::SectionMap &dwarf_sections,
+ void ReadDwarf(google_breakpad::Module* module,
+ const mach_o::Reader& macho_reader,
+ const mach_o::SectionMap& dwarf_sections,
bool handle_inter_cu_refs) const;
// Read DWARF CFI or .eh_frame data from |section|, belonging to
@@ -152,9 +156,9 @@ class DumpSymbols {
// then the data is .eh_frame-format data; otherwise, it is standard DWARF
// .debug_frame data. On success, return true; on failure, report
// the problem and return false.
- bool ReadCFI(google_breakpad::Module *module,
- const mach_o::Reader &macho_reader,
- const mach_o::Section &section,
+ bool ReadCFI(google_breakpad::Module* module,
+ const mach_o::Reader& macho_reader,
+ const mach_o::Section& section,
bool eh_frame) const;
// The selection of what type of symbol data to read/write.
@@ -163,19 +167,22 @@ class DumpSymbols {
// Whether to handle references between compilation units.
const bool handle_inter_cu_refs_;
- // The name of the file or bundle whose symbols this will dump.
- // This is the path given to Read, for use in error messages.
- std::string input_pathname_;
-
// The name of the file this DumpSymbols will actually read debugging
- // information from. Normally, this is the same as input_pathname_, but if
- // filename refers to a dSYM bundle, then this is the resource file
- // within that bundle.
+ // information from. If the filename passed to Read refers to a dSYM bundle,
+ // then this is the resource file within that bundle.
std::string object_filename_;
// The complete contents of object_filename_, mapped into memory.
scoped_array<uint8_t> contents_;
+ // The size of contents_.
+ size_t size_;
+
+ // Indicates which entry point to DumpSymbols was used, i.e. Read vs ReadData.
+ // This is used to indicate that downstream code paths can/should also read
+ // from disk or not.
+ bool from_disk_;
+
// A vector of SuperFatArch structures describing the object files
// object_filename_ contains. If object_filename_ refers to a fat binary,
// this may have more than one element; if it refers to a Mach-O file, this
@@ -184,13 +191,19 @@ class DumpSymbols {
// The object file in object_files_ selected to dump, or NULL if
// SetArchitecture hasn't been called yet.
- const SuperFatArch *selected_object_file_;
+ const SuperFatArch* selected_object_file_;
// A string that identifies the selected object file, for use in error
// messages. This is usually object_filename_, but if that refers to a
// fat binary, it includes an indication of the particular architecture
// within that binary.
string selected_object_name_;
+
+ // Whether symbols sharing an address should be collapsed into a single entry
+ // and marked with an `m` in the output.
+ // See: https://crbug.com/google-breakpad/751 and docs at
+ // docs/symbol_files.md#records-3
+ bool enable_multiple_;
};
} // namespace google_breakpad
diff --git a/src/common/mac/encoding_util.h b/src/common/mac/encoding_util.h
new file mode 100644
index 00000000..3028f2e9
--- /dev/null
+++ b/src/common/mac/encoding_util.h
@@ -0,0 +1,40 @@
+// Copyright 2020 Google LLC
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google LLC nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef GOOGLE_BREAKPAD_COMMON_MAC_ENCODING_UTIL_H
+#define GOOGLE_BREAKPAD_COMMON_MAC_ENCODING_UTIL_H
+
+#import <Foundation/Foundation.h>
+
+// As -[NSString stringByAddingPercentEscapesUsingEncoding:] has been
+// deprecated with iOS 9.0 / OS X 10.11 SDKs, this function re-implements it
+// using -[NSString stringByAddingPercentEncodingWithAllowedCharacters:] when
+// using those SDKs.
+NSString* PercentEncodeNSString(NSString* key);
+
+#endif // GOOGLE_BREAKPAD_COMMON_MAC_ENCODING_UTIL_H
diff --git a/src/common/mac/encoding_util.m b/src/common/mac/encoding_util.m
new file mode 100644
index 00000000..5cf84fc5
--- /dev/null
+++ b/src/common/mac/encoding_util.m
@@ -0,0 +1,46 @@
+// Copyright 2020 Google LLC
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google LLC nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "encoding_util.h"
+
+#include <Availability.h>
+#include <AvailabilityMacros.h>
+#import <Foundation/Foundation.h>
+
+NSString* PercentEncodeNSString(NSString* key) {
+#if (defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && defined(__IPHONE_9_0) && \
+ __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_9_0) || \
+ (defined(MAC_OS_X_VERSION_MIN_REQUIRED) && \
+ defined(MAC_OS_X_VERSION_10_11) && \
+ MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_11)
+ return [key stringByAddingPercentEncodingWithAllowedCharacters:
+ [NSCharacterSet URLQueryAllowedCharacterSet]];
+#else
+ return [key stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
+#endif
+}
diff --git a/src/common/mac/file_id.cc b/src/common/mac/file_id.cc
index 4661d5d6..a6c1d26f 100644
--- a/src/common/mac/file_id.cc
+++ b/src/common/mac/file_id.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2006, Google Inc.
-// All rights reserved.
+// Copyright 2006 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -33,53 +32,41 @@
//
// Author: Dan Waylonis
+#include "common/mac/file_id.h"
+
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
-#include <unistd.h>
-#include "common/mac/file_id.h"
#include "common/mac/macho_id.h"
+#include "common/scoped_ptr.h"
using MacFileUtilities::MachoID;
namespace google_breakpad {
-
-FileID::FileID(const char *path) {
+namespace mach_o {
+// Constructs a FileID given a path to a file
+FileID::FileID(const char* path) : memory_(nullptr), size_(0) {
snprintf(path_, sizeof(path_), "%s", path);
}
-bool FileID::FileIdentifier(unsigned char identifier[16]) {
- int fd = open(path_, O_RDONLY);
- if (fd == -1)
- return false;
-
- MD5Context md5;
- MD5Init(&md5);
-
- // Read 4k x 2 bytes at a time. This is faster than just 4k bytes, but
- // doesn't seem to be an unreasonable size for the stack.
- unsigned char buffer[4096 * 2];
- size_t buffer_size = sizeof(buffer);
- while ((buffer_size = read(fd, buffer, buffer_size) > 0)) {
- MD5Update(&md5, buffer, static_cast<unsigned>(buffer_size));
- }
-
- close(fd);
- MD5Final(identifier, &md5);
-
- return true;
-}
+// Constructs a FileID given the contents of a file and its size
+FileID::FileID(void* memory, size_t size)
+ : path_(), memory_(memory), size_(size) {}
bool FileID::MachoIdentifier(cpu_type_t cpu_type,
cpu_subtype_t cpu_subtype,
unsigned char identifier[16]) {
- MachoID macho(path_);
-
- if (macho.UUIDCommand(cpu_type, cpu_subtype, identifier))
+ scoped_ptr<MachoID> macho;
+ if (memory_) {
+ macho.reset(new MachoID(memory_, size_));
+ } else {
+ macho.reset(new MachoID(path_));
+ }
+ if (macho->UUIDCommand(cpu_type, cpu_subtype, identifier))
return true;
- return macho.MD5(cpu_type, cpu_subtype, identifier);
+ return macho->MD5(cpu_type, cpu_subtype, identifier);
}
// static
@@ -103,4 +90,5 @@ void FileID::ConvertIdentifierToString(const unsigned char identifier[16],
buffer[(buffer_idx < buffer_length) ? buffer_idx : buffer_idx - 1] = 0;
}
+} // namespace mach_o
} // namespace google_breakpad
diff --git a/src/common/mac/file_id.h b/src/common/mac/file_id.h
index 5d60e84c..a14cd137 100644
--- a/src/common/mac/file_id.h
+++ b/src/common/mac/file_id.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2006, Google Inc.
-// All rights reserved.
+// Copyright 2006 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -36,19 +35,19 @@
#include <limits.h>
#include <mach/machine.h>
+#include <stddef.h>
namespace google_breakpad {
+namespace mach_o {
class FileID {
public:
- FileID(const char *path);
- ~FileID() {}
+ // Constructs a FileID given a path to a file
+ FileID(const char* path);
- // Load the identifier for the file path specified in the constructor into
- // |identifier|. Return false if the identifier could not be created for the
- // file.
- // The current implementation will return the MD5 hash of the file's bytes.
- bool FileIdentifier(unsigned char identifier[16]);
+ // Constructs a FileID given the contents of a file and its size.
+ FileID(void* memory, size_t size);
+ ~FileID() {}
// Treat the file as a mach-o file that will contain one or more archicture.
// Accepted values for |cpu_type| and |cpu_subtype| (e.g., CPU_TYPE_X86 or
@@ -74,8 +73,19 @@ class FileID {
private:
// Storage for the path specified
char path_[PATH_MAX];
+
+ // Storage for contents of a file if this instance is used to operate on in
+ // memory file data rather than directly from a filesystem. If memory_ is
+ // null, the file represented by path_ will be opened/read. If memory_ is
+ // non-null, it is assumed to contain valid data, and no file operations will
+ // occur.
+ void* memory_;
+
+ // Size of memory_
+ size_t size_;
};
+} // namespace mach_o
} // namespace google_breakpad
#endif // COMMON_MAC_FILE_ID_H__
diff --git a/src/common/mac/launch_reporter.cc b/src/common/mac/launch_reporter.cc
index 245be826..de554ee3 100644
--- a/src/common/mac/launch_reporter.cc
+++ b/src/common/mac/launch_reporter.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2014, Google Inc.
-// All rights reserved.
+// Copyright 2014 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/common/mac/launch_reporter.h b/src/common/mac/launch_reporter.h
index 4531123c..0cf73547 100644
--- a/src/common/mac/launch_reporter.h
+++ b/src/common/mac/launch_reporter.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2014, Google Inc.
-// All rights reserved.
+// Copyright 2014 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/common/mac/macho_id.cc b/src/common/mac/macho_id.cc
index c396ad88..e67ccddb 100644
--- a/src/common/mac/macho_id.cc
+++ b/src/common/mac/macho_id.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2006, Google Inc.
-// All rights reserved.
+// Copyright 2006 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -37,11 +36,7 @@
#include <fcntl.h>
#include <mach-o/loader.h>
#include <stdio.h>
-#include <stdlib.h>
#include <string.h>
-#include <sys/time.h>
-#include <sys/types.h>
-#include <unistd.h>
#include "common/mac/macho_id.h"
#include "common/mac/macho_walker.h"
@@ -53,80 +48,25 @@ using google_breakpad::MD5Init;
using google_breakpad::MD5Update;
using google_breakpad::MD5Final;
-MachoID::MachoID(const char *path)
- : memory_(0),
- memory_size_(0),
- crc_(0),
- md5_context_(),
- update_function_(NULL) {
+MachoID::MachoID(const char* path)
+ : memory_(0), memory_size_(0), md5_context_(), update_function_(NULL) {
snprintf(path_, sizeof(path_), "%s", path);
}
-MachoID::MachoID(const char *path, void *memory, size_t size)
- : memory_(memory),
- memory_size_(size),
- crc_(0),
- md5_context_(),
- update_function_(NULL) {
- snprintf(path_, sizeof(path_), "%s", path);
-}
-
-MachoID::~MachoID() {
-}
+MachoID::MachoID(void* memory, size_t size)
+ : path_(),
+ memory_(memory),
+ memory_size_(size),
+ md5_context_(),
+ update_function_(NULL) {}
-// The CRC info is from http://en.wikipedia.org/wiki/Adler-32
-// With optimizations from http://www.zlib.net/
-
-// The largest prime smaller than 65536
-#define MOD_ADLER 65521
-// MAX_BLOCK is the largest n such that 255n(n+1)/2 + (n+1)(MAX_BLOCK-1) <= 2^32-1
-#define MAX_BLOCK 5552
-
-void MachoID::UpdateCRC(unsigned char *bytes, size_t size) {
-// Unrolled loops for summing
-#define DO1(buf,i) {sum1 += (buf)[i]; sum2 += sum1;}
-#define DO2(buf,i) DO1(buf,i); DO1(buf,i+1);
-#define DO4(buf,i) DO2(buf,i); DO2(buf,i+2);
-#define DO8(buf,i) DO4(buf,i); DO4(buf,i+4);
-#define DO16(buf) DO8(buf,0); DO8(buf,8);
- // Split up the crc
- uint32_t sum1 = crc_ & 0xFFFF;
- uint32_t sum2 = (crc_ >> 16) & 0xFFFF;
-
- // Do large blocks
- while (size >= MAX_BLOCK) {
- size -= MAX_BLOCK;
- int block_count = MAX_BLOCK / 16;
- do {
- DO16(bytes);
- bytes += 16;
- } while (--block_count);
- sum1 %= MOD_ADLER;
- sum2 %= MOD_ADLER;
- }
+MachoID::~MachoID() {}
- // Do remaining bytes
- if (size) {
- while (size >= 16) {
- size -= 16;
- DO16(bytes);
- bytes += 16;
- }
- while (size--) {
- sum1 += *bytes++;
- sum2 += sum1;
- }
- sum1 %= MOD_ADLER;
- sum2 %= MOD_ADLER;
- crc_ = (sum2 << 16) | sum1;
- }
-}
-
-void MachoID::UpdateMD5(unsigned char *bytes, size_t size) {
+void MachoID::UpdateMD5(unsigned char* bytes, size_t size) {
MD5Update(&md5_context_, bytes, static_cast<unsigned>(size));
}
-void MachoID::Update(MachoWalker *walker, off_t offset, size_t size) {
+void MachoID::Update(MachoWalker* walker, off_t offset, size_t size) {
if (!update_function_ || !size)
return;
@@ -169,59 +109,6 @@ bool MachoID::UUIDCommand(cpu_type_t cpu_type,
return false;
}
-bool MachoID::IDCommand(cpu_type_t cpu_type,
- cpu_subtype_t cpu_subtype,
- unsigned char identifier[16]) {
- struct dylib_command dylib_cmd;
- dylib_cmd.cmd = 0;
- if (!WalkHeader(cpu_type, cpu_subtype, IDWalkerCB, &dylib_cmd))
- return false;
-
- // If we found the command, we'll have initialized the dylib_command
- // structure
- if (dylib_cmd.cmd == LC_ID_DYLIB) {
- // Take the hashed filename, version, and compatability version bytes
- // to form the first 12 bytes, pad the rest with zeros
-
- // create a crude hash of the filename to generate the first 4 bytes
- identifier[0] = 0;
- identifier[1] = 0;
- identifier[2] = 0;
- identifier[3] = 0;
-
- for (int j = 0, i = (int)strlen(path_)-1; i>=0 && path_[i]!='/'; ++j, --i) {
- identifier[j%4] += path_[i];
- }
-
- identifier[4] = (dylib_cmd.dylib.current_version >> 24) & 0xFF;
- identifier[5] = (dylib_cmd.dylib.current_version >> 16) & 0xFF;
- identifier[6] = (dylib_cmd.dylib.current_version >> 8) & 0xFF;
- identifier[7] = dylib_cmd.dylib.current_version & 0xFF;
- identifier[8] = (dylib_cmd.dylib.compatibility_version >> 24) & 0xFF;
- identifier[9] = (dylib_cmd.dylib.compatibility_version >> 16) & 0xFF;
- identifier[10] = (dylib_cmd.dylib.compatibility_version >> 8) & 0xFF;
- identifier[11] = dylib_cmd.dylib.compatibility_version & 0xFF;
- identifier[12] = (cpu_type >> 24) & 0xFF;
- identifier[13] = (cpu_type >> 16) & 0xFF;
- identifier[14] = (cpu_type >> 8) & 0xFF;
- identifier[15] = cpu_type & 0xFF;
-
- return true;
- }
-
- return false;
-}
-
-uint32_t MachoID::Adler32(cpu_type_t cpu_type, cpu_subtype_t cpu_subtype) {
- update_function_ = &MachoID::UpdateCRC;
- crc_ = 0;
-
- if (!WalkHeader(cpu_type, cpu_subtype, WalkerCB, this))
- return 0;
-
- return crc_;
-}
-
bool MachoID::MD5(cpu_type_t cpu_type, cpu_subtype_t cpu_subtype, unsigned char identifier[16]) {
update_function_ = &MachoID::UpdateMD5;
@@ -237,7 +124,7 @@ bool MachoID::MD5(cpu_type_t cpu_type, cpu_subtype_t cpu_subtype, unsigned char
bool MachoID::WalkHeader(cpu_type_t cpu_type,
cpu_subtype_t cpu_subtype,
MachoWalker::LoadCommandCallback callback,
- void *context) {
+ void* context) {
if (memory_) {
MachoWalker walker(memory_, memory_size_, callback, context);
return walker.WalkHeader(cpu_type, cpu_subtype);
@@ -248,9 +135,9 @@ bool MachoID::WalkHeader(cpu_type_t cpu_type,
}
// static
-bool MachoID::WalkerCB(MachoWalker *walker, load_command *cmd, off_t offset,
- bool swap, void *context) {
- MachoID *macho_id = (MachoID *)context;
+bool MachoID::WalkerCB(MachoWalker* walker, load_command* cmd, off_t offset,
+ bool swap, void* context) {
+ MachoID* macho_id = (MachoID*)context;
if (cmd->cmd == LC_SEGMENT) {
struct segment_command seg;
@@ -327,11 +214,11 @@ bool MachoID::WalkerCB(MachoWalker *walker, load_command *cmd, off_t offset,
}
// static
-bool MachoID::UUIDWalkerCB(MachoWalker *walker, load_command *cmd, off_t offset,
- bool swap, void *context) {
+bool MachoID::UUIDWalkerCB(MachoWalker* walker, load_command* cmd, off_t offset,
+ bool swap, void* context) {
if (cmd->cmd == LC_UUID) {
- struct breakpad_uuid_command *uuid_cmd =
- (struct breakpad_uuid_command *)context;
+ struct breakpad_uuid_command* uuid_cmd =
+ (struct breakpad_uuid_command*)context;
if (!walker->ReadBytes(uuid_cmd, sizeof(struct breakpad_uuid_command),
offset))
@@ -346,24 +233,4 @@ bool MachoID::UUIDWalkerCB(MachoWalker *walker, load_command *cmd, off_t offset,
// Continue processing
return true;
}
-
-// static
-bool MachoID::IDWalkerCB(MachoWalker *walker, load_command *cmd, off_t offset,
- bool swap, void *context) {
- if (cmd->cmd == LC_ID_DYLIB) {
- struct dylib_command *dylib_cmd = (struct dylib_command *)context;
-
- if (!walker->ReadBytes(dylib_cmd, sizeof(struct dylib_command), offset))
- return false;
-
- if (swap)
- breakpad_swap_dylib_command(dylib_cmd);
-
- return false;
- }
-
- // Continue processing
- return true;
-}
-
} // namespace MacFileUtilities
diff --git a/src/common/mac/macho_id.h b/src/common/mac/macho_id.h
index 10375491..b9cbdb00 100644
--- a/src/common/mac/macho_id.h
+++ b/src/common/mac/macho_id.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2006, Google Inc.
-// All rights reserved.
+// Copyright 2006 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -45,8 +44,8 @@ namespace MacFileUtilities {
class MachoID {
public:
- MachoID(const char *path);
- MachoID(const char *path, void *memory, size_t size);
+ MachoID(const char* path);
+ MachoID(void* memory, size_t size);
~MachoID();
// For the given |cpu_type| and |cpu_subtype|, return a UUID from the LC_UUID
@@ -56,19 +55,6 @@ class MachoID {
cpu_subtype_t cpu_subtype,
unsigned char identifier[16]);
- // For the given |cpu_type| and |cpu_subtype|, return a UUID from the
- // LC_ID_DYLIB command.
- // Return false if there isn't a LC_ID_DYLIB command.
- bool IDCommand(cpu_type_t cpu_type,
- cpu_subtype_t cpu_subtype,
- unsigned char identifier[16]);
-
- // For the given |cpu_type| and |cpu_subtype|, return the Adler32 CRC for the
- // mach-o data segment(s).
- // Return 0 on error (e.g., if the file is not a mach-o file)
- uint32_t Adler32(cpu_type_t cpu_type,
- cpu_subtype_t cpu_subtype);
-
// For the given |cpu_type|, and |cpu_subtype| return the MD5 for the mach-o
// data segment(s).
// Return true on success, false otherwise
@@ -78,47 +64,36 @@ class MachoID {
private:
// Signature of class member function to be called with data read from file
- typedef void (MachoID::*UpdateFunction)(unsigned char *bytes, size_t size);
-
- // Update the CRC value by examining |size| |bytes| and applying the algorithm
- // to each byte.
- void UpdateCRC(unsigned char *bytes, size_t size);
+ typedef void (MachoID::*UpdateFunction)(unsigned char* bytes, size_t size);
// Update the MD5 value by examining |size| |bytes| and applying the algorithm
// to each byte.
- void UpdateMD5(unsigned char *bytes, size_t size);
+ void UpdateMD5(unsigned char* bytes, size_t size);
// Bottleneck for update routines
- void Update(MachoWalker *walker, off_t offset, size_t size);
+ void Update(MachoWalker* walker, off_t offset, size_t size);
// Factory for the MachoWalker
bool WalkHeader(cpu_type_t cpu_type, cpu_subtype_t cpu_subtype,
- MachoWalker::LoadCommandCallback callback, void *context);
+ MachoWalker::LoadCommandCallback callback, void* context);
// The callback from the MachoWalker for CRC and MD5
- static bool WalkerCB(MachoWalker *walker, load_command *cmd, off_t offset,
- bool swap, void *context);
+ static bool WalkerCB(MachoWalker* walker, load_command* cmd, off_t offset,
+ bool swap, void* context);
// The callback from the MachoWalker for LC_UUID
- static bool UUIDWalkerCB(MachoWalker *walker, load_command *cmd, off_t offset,
- bool swap, void *context);
-
- // The callback from the MachoWalker for LC_ID_DYLIB
- static bool IDWalkerCB(MachoWalker *walker, load_command *cmd, off_t offset,
- bool swap, void *context);
+ static bool UUIDWalkerCB(MachoWalker* walker, load_command* cmd, off_t offset,
+ bool swap, void* context);
// File path
char path_[PATH_MAX];
// Memory region to read from
- void *memory_;
+ void* memory_;
// Size of the memory region
size_t memory_size_;
- // The current crc value
- uint32_t crc_;
-
// The MD5 context
google_breakpad::MD5Context md5_context_;
diff --git a/src/common/mac/macho_reader.cc b/src/common/mac/macho_reader.cc
index 91e1fdd2..23c809c4 100644
--- a/src/common/mac/macho_reader.cc
+++ b/src/common/mac/macho_reader.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2010, Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -81,7 +80,7 @@ void FatReader::Reporter::MisplacedObjectFile() {
" to contain\n", filename_.c_str());
}
-bool FatReader::Read(const uint8_t *buffer, size_t size) {
+bool FatReader::Read(const uint8_t* buffer, size_t size) {
buffer_.start = buffer;
buffer_.end = buffer + size;
ByteCursor cursor(&buffer_);
@@ -196,19 +195,19 @@ void Reader::Reporter::LoadCommandTooShort(size_t i, LoadCommandType type) {
filename_.c_str(), i, type);
}
-void Reader::Reporter::SectionsMissing(const string &name) {
+void Reader::Reporter::SectionsMissing(const string& name) {
fprintf(stderr, "%s: the load command for segment '%s'"
" is too short to hold the section headers it claims to have\n",
filename_.c_str(), name.c_str());
}
-void Reader::Reporter::MisplacedSegmentData(const string &name) {
+void Reader::Reporter::MisplacedSegmentData(const string& name) {
fprintf(stderr, "%s: the segment '%s' claims its contents lie beyond"
" the end of the file\n", filename_.c_str(), name.c_str());
}
-void Reader::Reporter::MisplacedSectionData(const string &section,
- const string &segment) {
+void Reader::Reporter::MisplacedSectionData(const string& section,
+ const string& segment) {
fprintf(stderr, "%s: the section '%s' in segment '%s'"
" claims its contents lie outside the segment's contents\n",
filename_.c_str(), section.c_str(), segment.c_str());
@@ -225,7 +224,7 @@ void Reader::Reporter::UnsupportedCPUType(cpu_type_t cpu_type) {
filename_.c_str(), cpu_type);
}
-bool Reader::Read(const uint8_t *buffer,
+bool Reader::Read(const uint8_t* buffer,
size_t size,
cpu_type_t expected_cpu_type,
cpu_subtype_t expected_cpu_subtype) {
@@ -309,7 +308,7 @@ bool Reader::Read(const uint8_t *buffer,
return true;
}
-bool Reader::WalkLoadCommands(Reader::LoadCommandHandler *handler) const {
+bool Reader::WalkLoadCommands(Reader::LoadCommandHandler* handler) const {
ByteCursor list_cursor(&load_commands_, big_endian_);
for (size_t index = 0; index < load_command_count_; ++index) {
@@ -422,13 +421,13 @@ class Reader::SegmentFinder : public LoadCommandHandler {
public:
// Create a load command handler that looks for a segment named NAME,
// and sets SEGMENT to describe it if found.
- SegmentFinder(const string &name, Segment *segment)
+ SegmentFinder(const string& name, Segment* segment)
: name_(name), segment_(segment), found_() { }
// Return true if the traversal found the segment, false otherwise.
bool found() const { return found_; }
- bool SegmentCommand(const Segment &segment) {
+ bool SegmentCommand(const Segment& segment) {
if (segment.name == name_) {
*segment_ = segment;
found_ = true;
@@ -439,23 +438,23 @@ class Reader::SegmentFinder : public LoadCommandHandler {
private:
// The name of the segment our creator is looking for.
- const string &name_;
+ const string& name_;
// Where we should store the segment if found. (WEAK)
- Segment *segment_;
+ Segment* segment_;
// True if we found the segment.
bool found_;
};
-bool Reader::FindSegment(const string &name, Segment *segment) const {
+bool Reader::FindSegment(const string& name, Segment* segment) const {
SegmentFinder finder(name, segment);
WalkLoadCommands(&finder);
return finder.found();
}
-bool Reader::WalkSegmentSections(const Segment &segment,
- SectionHandler *handler) const {
+bool Reader::WalkSegmentSections(const Segment& segment,
+ SectionHandler* handler) const {
size_t word_size = segment.bits_64 ? 8 : 4;
ByteCursor cursor(&segment.section_list, big_endian_);
@@ -518,12 +517,21 @@ bool Reader::WalkSegmentSections(const Segment &segment,
if (offset < size_t(segment.contents.start - buffer_.start) ||
offset > size_t(segment.contents.end - buffer_.start) ||
size > size_t(segment.contents.end - buffer_.start - offset)) {
- reporter_->MisplacedSectionData(section.section_name,
- section.segment_name);
- return false;
+ if (offset > 0) {
+ reporter_->MisplacedSectionData(section.section_name,
+ section.segment_name);
+ return false;
+ } else {
+ // Mach-O files in .dSYM bundles have the contents of the loaded
+ // segments partially removed. The removed sections will have zero as
+ // their offset. MisplacedSectionData should not be called in this
+ // case.
+ section.contents.start = section.contents.end = NULL;
+ }
+ } else {
+ section.contents.start = buffer_.start + offset;
+ section.contents.end = section.contents.start + size;
}
- section.contents.start = buffer_.start + offset;
- section.contents.end = section.contents.start + size;
}
if (!handler->HandleSection(section))
return false;
@@ -537,18 +545,18 @@ class Reader::SectionMapper: public SectionHandler {
public:
// Create a SectionHandler that populates MAP with an entry for
// each section it is given.
- SectionMapper(SectionMap *map) : map_(map) { }
- bool HandleSection(const Section &section) {
+ SectionMapper(SectionMap* map) : map_(map) { }
+ bool HandleSection(const Section& section) {
(*map_)[section.section_name] = section;
return true;
}
private:
// The map under construction. (WEAK)
- SectionMap *map_;
+ SectionMap* map_;
};
-bool Reader::MapSegmentSections(const Segment &segment,
- SectionMap *section_map) const {
+bool Reader::MapSegmentSections(const Segment& segment,
+ SectionMap* section_map) const {
section_map->clear();
SectionMapper mapper(section_map);
return WalkSegmentSections(segment, &mapper);
diff --git a/src/common/mac/macho_reader.h b/src/common/mac/macho_reader.h
index 145d17d1..d3c61a06 100644
--- a/src/common/mac/macho_reader.h
+++ b/src/common/mac/macho_reader.h
@@ -1,7 +1,6 @@
// -*- mode: C++ -*-
-// Copyright (c) 2010, Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -13,7 +12,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -78,7 +77,7 @@ class FatReader {
class Reporter {
public:
// Create a reporter that attributes problems to |filename|.
- explicit Reporter(const string &filename) : filename_(filename) { }
+ explicit Reporter(const string& filename) : filename_(filename) { }
virtual ~Reporter() { }
@@ -101,7 +100,7 @@ class FatReader {
};
// Create a fat binary file reader that uses |reporter| to report problems.
- explicit FatReader(Reporter *reporter) : reporter_(reporter) { }
+ explicit FatReader(Reporter* reporter) : reporter_(reporter) { }
// Read the |size| bytes at |buffer| as a fat binary file. On success,
// return true; on failure, report the problem to reporter_ and return
@@ -110,7 +109,7 @@ class FatReader {
// If the data is a plain Mach-O file, rather than a fat binary file,
// then the reader behaves as if it had found a fat binary file whose
// single object file is the Mach-O file.
- bool Read(const uint8_t *buffer, size_t size);
+ bool Read(const uint8_t* buffer, size_t size);
// Return an array of 'SuperFatArch' structures describing the
// object files present in this fat binary file. Set |size| to the
@@ -130,7 +129,7 @@ class FatReader {
// possible to use the result with OS X functions like NXFindBestFatArch,
// so that the symbol dumper will behave consistently with other OS X
// utilities that work with fat binaries.
- const SuperFatArch* object_files(size_t *count) const {
+ const SuperFatArch* object_files(size_t* count) const {
*count = object_files_.size();
if (object_files_.size() > 0)
return &object_files_[0];
@@ -139,7 +138,7 @@ class FatReader {
private:
// We use this to report problems parsing the file's contents. (WEAK)
- Reporter *reporter_;
+ Reporter* reporter_;
// The contents of the fat binary or Mach-O file we're parsing. We do not
// own the storage it refers to.
@@ -240,7 +239,7 @@ class Reader {
class Reporter {
public:
// Create a reporter that attributes problems to |filename|.
- explicit Reporter(const string &filename) : filename_(filename) { }
+ explicit Reporter(const string& filename) : filename_(filename) { }
virtual ~Reporter() { }
// Reporter functions for fatal errors return void; the reader will
@@ -282,16 +281,16 @@ class Reader {
// The LC_SEGMENT or LC_SEGMENT_64 load command for the segment named
// |name| is too short to hold the sections that its header says it does.
// (This more specific than LoadCommandTooShort.)
- virtual void SectionsMissing(const string &name);
+ virtual void SectionsMissing(const string& name);
// The segment named |name| claims that its contents lie beyond the end
// of the file.
- virtual void MisplacedSegmentData(const string &name);
+ virtual void MisplacedSegmentData(const string& name);
// The section named |section| in the segment named |segment| claims that
// its contents do not lie entirely within the segment.
- virtual void MisplacedSectionData(const string &section,
- const string &segment);
+ virtual void MisplacedSectionData(const string& section,
+ const string& segment);
// The LC_SYMTAB command claims that symbol table contents are located
// beyond the end of the file.
@@ -315,7 +314,7 @@ class Reader {
// Called to report that the segment's section list contains |section|.
// This should return true if the iteration should continue, or false
// if it should stop.
- virtual bool HandleSection(const Section &section) = 0;
+ virtual bool HandleSection(const Section& section) = 0;
};
// A handler for the load commands in a Mach-O file.
@@ -341,20 +340,20 @@ class Reader {
// cannot parse the command type or its size, we call
// reporter_->IncompleteLoadCommand instead.)
virtual bool UnknownCommand(LoadCommandType type,
- const ByteBuffer &contents) {
+ const ByteBuffer& contents) {
return true;
}
// The load command is LC_SEGMENT or LC_SEGMENT_64, defining a segment
// with the properties given in |segment|.
- virtual bool SegmentCommand(const Segment &segment) {
+ virtual bool SegmentCommand(const Segment& segment) {
return true;
}
// The load command is LC_SYMTAB. |entries| holds the array of nlist
// entries, and |names| holds the strings the entries refer to.
- virtual bool SymtabCommand(const ByteBuffer &entries,
- const ByteBuffer &names) {
+ virtual bool SymtabCommand(const ByteBuffer& entries,
+ const ByteBuffer& names) {
return true;
}
@@ -362,7 +361,7 @@ class Reader {
};
// Create a Mach-O file reader that reports problems to |reporter|.
- explicit Reader(Reporter *reporter)
+ explicit Reader(Reporter* reporter)
: reporter_(reporter) { }
// Read the given data as a Mach-O file. The reader retains pointers
@@ -371,11 +370,11 @@ class Reader {
//
// At most one of these functions should be invoked once on each Reader
// instance.
- bool Read(const uint8_t *buffer,
+ bool Read(const uint8_t* buffer,
size_t size,
cpu_type_t expected_cpu_type,
cpu_subtype_t expected_cpu_subtype);
- bool Read(const ByteBuffer &buffer,
+ bool Read(const ByteBuffer& buffer,
cpu_type_t expected_cpu_type,
cpu_subtype_t expected_cpu_subtype) {
return Read(buffer.start,
@@ -402,25 +401,25 @@ class Reader {
// a handler function returns false. If we encounter a malformed load
// command, report it via reporter_ and return false. Return true if all
// load commands were parseable and all handlers returned true.
- bool WalkLoadCommands(LoadCommandHandler *handler) const;
+ bool WalkLoadCommands(LoadCommandHandler* handler) const;
// Set |segment| to describe the segment named |name|, if present. If
// found, |segment|'s byte buffers refer to a subregion of the bytes
// passed to Read. If we find the section, return true; otherwise,
// return false.
- bool FindSegment(const string &name, Segment *segment) const;
+ bool FindSegment(const string& name, Segment* segment) const;
// Apply |handler| to each section defined in |segment|. If |handler| returns
// false, stop iterating and return false. If all calls to |handler| return
// true and we reach the end of the section list, return true.
- bool WalkSegmentSections(const Segment &segment, SectionHandler *handler)
+ bool WalkSegmentSections(const Segment& segment, SectionHandler* handler)
const;
// Clear |section_map| and then populate it with a map of the sections
// in |segment|, from section names to Section structures.
// Each Section's contents refer to bytes in |segment|'s contents.
// On success, return true; if a problem occurs, report it and return false.
- bool MapSegmentSections(const Segment &segment, SectionMap *section_map)
+ bool MapSegmentSections(const Segment& segment, SectionMap* section_map)
const;
private:
@@ -429,7 +428,7 @@ class Reader {
class SectionMapper;
// We use this to report problems parsing the file's contents. (WEAK)
- Reporter *reporter_;
+ Reporter* reporter_;
// The contents of the Mach-O file we're parsing. We do not own the
// storage it refers to.
diff --git a/src/common/mac/macho_reader_unittest.cc b/src/common/mac/macho_reader_unittest.cc
index d8459d8c..3beec341 100644
--- a/src/common/mac/macho_reader_unittest.cc
+++ b/src/common/mac/macho_reader_unittest.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2010 Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -75,7 +74,7 @@ using testing::_;
class MockFatReaderReporter: public FatReader::Reporter {
public:
- MockFatReaderReporter(const string &filename)
+ MockFatReaderReporter(const string& filename)
: FatReader::Reporter(filename) { }
MOCK_METHOD0(BadHeader, void());
MOCK_METHOD0(MisplacedObjectFile, void());
@@ -84,7 +83,7 @@ class MockFatReaderReporter: public FatReader::Reporter {
class MockReaderReporter: public Reader::Reporter {
public:
- MockReaderReporter(const string &filename) : Reader::Reporter(filename) { }
+ MockReaderReporter(const string& filename) : Reader::Reporter(filename) { }
MOCK_METHOD0(BadHeader, void());
MOCK_METHOD4(CPUTypeMismatch, void(cpu_type_t cpu_type,
cpu_subtype_t cpu_subtype,
@@ -95,24 +94,24 @@ class MockReaderReporter: public Reader::Reporter {
MOCK_METHOD3(LoadCommandsOverrun, void(size_t claimed, size_t i,
LoadCommandType type));
MOCK_METHOD2(LoadCommandTooShort, void(size_t i, LoadCommandType type));
- MOCK_METHOD1(SectionsMissing, void(const string &name));
- MOCK_METHOD1(MisplacedSegmentData, void(const string &name));
- MOCK_METHOD2(MisplacedSectionData, void(const string &section,
- const string &segment));
+ MOCK_METHOD1(SectionsMissing, void(const string& name));
+ MOCK_METHOD1(MisplacedSegmentData, void(const string& name));
+ MOCK_METHOD2(MisplacedSectionData, void(const string& section,
+ const string& segment));
MOCK_METHOD0(MisplacedSymbolTable, void());
MOCK_METHOD1(UnsupportedCPUType, void(cpu_type_t cpu_type));
};
class MockLoadCommandHandler: public Reader::LoadCommandHandler {
public:
- MOCK_METHOD2(UnknownCommand, bool(LoadCommandType, const ByteBuffer &));
- MOCK_METHOD1(SegmentCommand, bool(const Segment &));
- MOCK_METHOD2(SymtabCommand, bool(const ByteBuffer &, const ByteBuffer &));
+ MOCK_METHOD2(UnknownCommand, bool(LoadCommandType, const ByteBuffer&));
+ MOCK_METHOD1(SegmentCommand, bool(const Segment&));
+ MOCK_METHOD2(SymtabCommand, bool(const ByteBuffer&, const ByteBuffer&));
};
class MockSectionHandler: public Reader::SectionHandler {
public:
- MOCK_METHOD1(HandleSection, bool(const Section &section));
+ MOCK_METHOD1(HandleSection, bool(const Section& section));
};
@@ -221,7 +220,7 @@ struct FatReaderFixture {
}
void ReadFat(bool expect_parse_success = true) {
ASSERT_TRUE(fat.GetContents(&contents));
- fat_bytes = reinterpret_cast<const uint8_t *>(contents.data());
+ fat_bytes = reinterpret_cast<const uint8_t*>(contents.data());
if (expect_parse_success) {
EXPECT_TRUE(reader.Read(fat_bytes, contents.size()));
size_t fat_files_count;
@@ -238,7 +237,7 @@ struct FatReaderFixture {
MockFatReaderReporter reporter;
FatReader reader;
string contents;
- const uint8_t *fat_bytes;
+ const uint8_t* fat_bytes;
vector<struct fat_arch> object_files;
};
@@ -487,16 +486,16 @@ class WithConfiguration {
private:
// The innermost WithConfiguration in whose dynamic scope we are
// currently executing.
- static WithConfiguration *current_;
+ static WithConfiguration* current_;
// The innermost WithConfiguration whose dynamic scope encloses this
// WithConfiguration.
Endianness endianness_;
size_t word_size_;
- WithConfiguration *saved_;
+ WithConfiguration* saved_;
};
-WithConfiguration *WithConfiguration::current_ = NULL;
+WithConfiguration* WithConfiguration::current_ = NULL;
// A test_assembler::Section with a size that we can cite. The start(),
// Here() and Mark() member functions of a SizedSection always represent
@@ -527,7 +526,7 @@ class SizedSection: public test_assembler::Section {
// Append SECTION to the end of this section, and call its Finish member.
// Return a reference to this section.
- SizedSection &Place(SizedSection *section) {
+ SizedSection& Place(SizedSection* section) {
assert(section->endianness() == endianness());
section->Finish();
section->start() = Here();
@@ -563,7 +562,7 @@ class LoadedSection: public SizedSection {
// Placing a loaded section within a loaded section sets the relationship
// between their addresses.
- LoadedSection &Place(LoadedSection *section) {
+ LoadedSection& Place(LoadedSection* section) {
section->address() = address() + Size();
SizedSection::Place(section);
return *this;
@@ -583,7 +582,7 @@ class SegmentLoadCommand: public SizedSection {
// The load command will refer to CONTENTS, which must be Placed in the
// file separately, at the desired position. Return a reference to this
// section.
- SegmentLoadCommand &Header(const string &name, const LoadedSection &contents,
+ SegmentLoadCommand& Header(const string& name, const LoadedSection& contents,
uint32_t maxprot, uint32_t initprot,
uint32_t flags) {
assert(contents.word_size() == word_size());
@@ -608,16 +607,16 @@ class SegmentLoadCommand: public SizedSection {
// memory. If this label is still undefined by the time we place this
// segment, it defaults to the final size of the segment's in-file
// contents. Return a reference to this load command.
- Label &vmsize() { return vmsize_; }
+ Label& vmsize() { return vmsize_; }
// Add a section entry with the given characteristics to this segment
// load command. Return a reference to this. The section entry will refer
// to CONTENTS, which must be Placed in the segment's contents
// separately, at the desired position.
- SegmentLoadCommand &AppendSectionEntry(const string &section_name,
- const string &segment_name,
+ SegmentLoadCommand& AppendSectionEntry(const string& section_name,
+ const string& segment_name,
uint32_t alignment, uint32_t flags,
- const LoadedSection &contents) {
+ const LoadedSection& contents) {
AppendCString(section_name, 16);
AppendCString(segment_name, 16);
Append(endianness(), word_size() / 8, contents.address());
@@ -671,14 +670,14 @@ class LoadCommands: public SizedSection {
Label final_command_count() const { return final_command_count_; }
// Increment the command count; return a reference to this section.
- LoadCommands &CountCommand() {
+ LoadCommands& CountCommand() {
command_count_++;
return *this;
}
// Place COMMAND, containing a load command, at the end of this section.
// Return a reference to this section.
- LoadCommands &Place(SizedSection *section) {
+ LoadCommands& Place(SizedSection* section) {
SizedSection::Place(section);
CountCommand();
return *this;
@@ -710,7 +709,7 @@ class MachOFile: public SizedSection {
// Create a Mach-O file header using the given characteristics and load
// command list. This Places COMMANDS immediately after the header.
// Return a reference to this section.
- MachOFile &Header(LoadCommands *commands,
+ MachOFile& Header(LoadCommands* commands,
cpu_type_t cpu_type = CPU_TYPE_X86,
cpu_subtype_t cpu_subtype = CPU_SUBTYPE_I386_ALL,
FileType file_type = MH_EXECUTE,
@@ -752,12 +751,12 @@ struct ReaderFixture {
EXPECT_CALL(load_command_handler, SegmentCommand(_)).Times(0);
}
- void ReadFile(MachOFile *file,
+ void ReadFile(MachOFile* file,
bool expect_parse_success,
cpu_type_t expected_cpu_type,
cpu_subtype_t expected_cpu_subtype) {
ASSERT_TRUE(file->GetContents(&file_contents));
- file_bytes = reinterpret_cast<const uint8_t *>(file_contents.data());
+ file_bytes = reinterpret_cast<const uint8_t*>(file_contents.data());
if (expect_parse_success) {
EXPECT_TRUE(reader.Read(file_bytes,
file_contents.size(),
@@ -772,7 +771,7 @@ struct ReaderFixture {
}
string file_contents;
- const uint8_t *file_bytes;
+ const uint8_t* file_bytes;
MockReaderReporter reporter;
Reader reader;
MockLoadCommandHandler load_command_handler;
@@ -1343,14 +1342,14 @@ TEST_F(LoadCommand, ThreeLoadCommands) {
EXPECT_TRUE(reader.WalkLoadCommands(&load_command_handler));
}
-static inline Matcher<const Section &> MatchSection(
+static inline Matcher<const Section&> MatchSection(
Matcher<bool> bits_64,
- Matcher<const string &> section_name,
- Matcher<const string &> segment_name,
+ Matcher<const string&> section_name,
+ Matcher<const string&> segment_name,
Matcher<uint64_t> address,
Matcher<uint32_t> alignment,
Matcher<uint32_t> flags,
- Matcher<const ByteBuffer &> contents) {
+ Matcher<const ByteBuffer&> contents) {
return AllOf(AllOf(Field(&Section::bits_64, bits_64),
Field(&Section::section_name, section_name),
Field(&Section::segment_name, segment_name),
@@ -1360,10 +1359,10 @@ static inline Matcher<const Section &> MatchSection(
Field(&Section::contents, contents)));
}
-static inline Matcher<const Section &> MatchSection(
+static inline Matcher<const Section&> MatchSection(
Matcher<bool> bits_64,
- Matcher<const string &> section_name,
- Matcher<const string &> segment_name,
+ Matcher<const string&> section_name,
+ Matcher<const string&> segment_name,
Matcher<uint64_t> address) {
return AllOf(Field(&Section::bits_64, bits_64),
Field(&Section::section_name, section_name),
@@ -1410,7 +1409,7 @@ TEST_F(LoadCommand, OneSegmentTwoSections) {
contents1.start = file_bytes + section1.start().Value();
contents1.end = contents1.start + section1.final_size().Value();
EXPECT_EQ("buddha's hand",
- string(reinterpret_cast<const char *>(contents1.start),
+ string(reinterpret_cast<const char*>(contents1.start),
contents1.Size()));
EXPECT_CALL(section_handler,
HandleSection(MatchSection(true, "mandarin", "kishu",
@@ -1422,7 +1421,7 @@ TEST_F(LoadCommand, OneSegmentTwoSections) {
contents2.start = file_bytes + section2.start().Value();
contents2.end = contents2.start + section2.final_size().Value();
EXPECT_EQ("kumquat",
- string(reinterpret_cast<const char *>(contents2.start),
+ string(reinterpret_cast<const char*>(contents2.start),
contents2.Size()));
EXPECT_CALL(section_handler,
HandleSection(MatchSection(true, "bergamot", "cara cara",
@@ -1529,6 +1528,51 @@ TEST_F(LoadCommand, MisplacedSectionTooBig) {
// to set all their labels by hand to get the (impossible)
// configurations we want.
+ // A section with 0 as is start address.
+ LoadedSection empty;
+ empty.Append(10, '4');
+ empty.start() = 0;
+ empty.address() = segment.address() + 1;
+ empty.final_size() = empty.Size();
+
+ SegmentLoadCommand command;
+ command.Header("segment", segment, 0x173baa29, 0x8407275d, 0xed8f7057)
+ .AppendSectionEntry("empty", "segment", 0, 0x8b53ae5c, empty);
+
+ LoadCommands commands;
+ commands.Place(&command);
+
+ MachOFile file;
+ file.Header(&commands).Place(&segment);
+
+ ReadFile(&file, true, CPU_TYPE_ANY, 0);
+
+ Segment actual_segment;
+ EXPECT_TRUE(reader.FindSegment("segment", &actual_segment));
+
+ EXPECT_CALL(reporter, MisplacedSectionData("empty", "segment")).Times(0);
+
+ EXPECT_CALL(section_handler,
+ HandleSection(MatchSection(true, "empty", "segment",
+ empty.address().Value())))
+ .WillOnce(Return(true));
+
+ EXPECT_TRUE(reader.WalkSegmentSections(actual_segment, &section_handler));
+}
+
+TEST_F(LoadCommand, MisplacedSectionButSectionIsEmpty) {
+ WithConfiguration config(kLittleEndian, 64);
+
+ // The segment.
+ LoadedSection segment;
+ segment.address() = 0x696d83cc;
+ segment.Append(10, '0');
+
+ // The contents of the following sections don't matter, because
+ // we're not really going to Place them in segment; we're just going
+ // to set all their labels by hand to get the (impossible)
+ // configurations we want.
+
// A section that extends beyond the end of its section.
LoadedSection too_big;
too_big.Append(10, '3');
@@ -1716,7 +1760,7 @@ class StringAssembler: public SizedSection {
public:
// Add the string S to this StringAssembler, and return the string's
// offset within this compilation unit's strings.
- size_t Add(const string &s) {
+ size_t Add(const string& s) {
size_t offset = Size();
AppendCString(s);
return offset;
@@ -1728,7 +1772,7 @@ class StringAssembler: public SizedSection {
class SymbolAssembler: public SizedSection {
public:
// Create a SymbolAssembler that uses StringAssembler for its strings.
- explicit SymbolAssembler(StringAssembler *string_assembler)
+ explicit SymbolAssembler(StringAssembler* string_assembler)
: string_assembler_(string_assembler),
entry_count_(0) { }
@@ -1737,7 +1781,7 @@ class SymbolAssembler: public SizedSection {
// its compilation unit's portion of the .stabstr section; this can be a
// value generated by a StringAssembler. Return a reference to this
// SymbolAssembler.
- SymbolAssembler &Symbol(uint8_t type, uint8_t other, Label descriptor,
+ SymbolAssembler& Symbol(uint8_t type, uint8_t other, Label descriptor,
Label value, Label name) {
D32(name);
D8(type);
@@ -1749,14 +1793,14 @@ class SymbolAssembler: public SizedSection {
}
// As above, but automatically add NAME to our StringAssembler.
- SymbolAssembler &Symbol(uint8_t type, uint8_t other, Label descriptor,
- Label value, const string &name) {
+ SymbolAssembler& Symbol(uint8_t type, uint8_t other, Label descriptor,
+ Label value, const string& name) {
return Symbol(type, other, descriptor, value, string_assembler_->Add(name));
}
private:
// The strings for our STABS entries.
- StringAssembler *string_assembler_;
+ StringAssembler* string_assembler_;
// The number of entries in this compilation unit so far.
size_t entry_count_;
diff --git a/src/common/mac/macho_utilities.cc b/src/common/mac/macho_utilities.cc
index f56fe768..16e430df 100644
--- a/src/common/mac/macho_utilities.cc
+++ b/src/common/mac/macho_utilities.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2006, Google Inc.
-// All rights reserved.
+// Copyright 2006 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/common/mac/macho_utilities.h b/src/common/mac/macho_utilities.h
index 00563a77..470cb5d2 100644
--- a/src/common/mac/macho_utilities.h
+++ b/src/common/mac/macho_utilities.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2006, Google Inc.
-// All rights reserved.
+// Copyright 2006 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/common/mac/macho_walker.cc b/src/common/mac/macho_walker.cc
index 1acd8665..505a4df1 100644
--- a/src/common/mac/macho_walker.cc
+++ b/src/common/mac/macho_walker.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2006, Google Inc.
-// All rights reserved.
+// Copyright 2006 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -47,8 +46,8 @@
namespace MacFileUtilities {
-MachoWalker::MachoWalker(const char *path, LoadCommandCallback callback,
- void *context)
+MachoWalker::MachoWalker(const char* path, LoadCommandCallback callback,
+ void* context)
: file_(-1),
memory_(NULL),
memory_size_(0),
@@ -60,8 +59,8 @@ MachoWalker::MachoWalker(const char *path, LoadCommandCallback callback,
file_ = open(path, O_RDONLY);
}
-MachoWalker::MachoWalker(void *memory, size_t size,
- LoadCommandCallback callback, void *context)
+MachoWalker::MachoWalker(void* memory, size_t size,
+ LoadCommandCallback callback, void* context)
: file_(-1),
memory_(memory),
memory_size_(size),
@@ -82,7 +81,7 @@ bool MachoWalker::WalkHeader(cpu_type_t cpu_type, cpu_subtype_t cpu_subtype) {
cpu_subtype_t valid_cpu_subtype = cpu_subtype;
// if |cpu_type| is 0, use the native cpu type.
if (cpu_type == 0) {
- const NXArchInfo *arch = NXGetLocalArchInfo();
+ const NXArchInfo* arch = NXGetLocalArchInfo();
assert(arch);
valid_cpu_type = arch->cputype;
valid_cpu_subtype = CPU_SUBTYPE_MULTIPLE;
@@ -98,7 +97,7 @@ bool MachoWalker::WalkHeader(cpu_type_t cpu_type, cpu_subtype_t cpu_subtype) {
return false;
}
-bool MachoWalker::ReadBytes(void *buffer, size_t size, off_t offset) {
+bool MachoWalker::ReadBytes(void* buffer, size_t size, off_t offset) {
if (memory_) {
if (offset < 0)
return false;
@@ -109,14 +108,14 @@ bool MachoWalker::ReadBytes(void *buffer, size_t size, off_t offset) {
size = memory_size_ - static_cast<size_t>(offset);
result = false;
}
- memcpy(buffer, static_cast<char *>(memory_) + offset, size);
+ memcpy(buffer, static_cast<char*>(memory_) + offset, size);
return result;
} else {
return pread(file_, buffer, size, offset) == (ssize_t)size;
}
}
-bool MachoWalker::CurrentHeader(struct mach_header_64 *header, off_t *offset) {
+bool MachoWalker::CurrentHeader(struct mach_header_64* header, off_t* offset) {
if (current_header_) {
memcpy(header, current_header_, sizeof(mach_header_64));
*offset = current_header_offset_;
@@ -128,7 +127,7 @@ bool MachoWalker::CurrentHeader(struct mach_header_64 *header, off_t *offset) {
bool MachoWalker::FindHeader(cpu_type_t cpu_type,
cpu_subtype_t cpu_subtype,
- off_t &offset) {
+ off_t& offset) {
// Read the magic bytes that's common amongst all mach-o files
uint32_t magic;
if (!ReadBytes(&magic, sizeof(magic), 0))
@@ -211,7 +210,7 @@ bool MachoWalker::WalkHeaderAtOffset(off_t offset) {
// Copy the data into the mach_header_64 structure. Since the 32-bit and
// 64-bit only differ in the last field (reserved), this is safe to do.
struct mach_header_64 header64;
- memcpy((void *)&header64, (const void *)&header, sizeof(header));
+ memcpy((void*)&header64, (const void*)&header, sizeof(header));
header64.reserved = 0;
current_header_ = &header64;
diff --git a/src/common/mac/macho_walker.h b/src/common/mac/macho_walker.h
index dd535814..13e8232e 100644
--- a/src/common/mac/macho_walker.h
+++ b/src/common/mac/macho_walker.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2006, Google Inc.
-// All rights reserved.
+// Copyright 2006 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -49,12 +48,12 @@ class MachoWalker {
// beginning of the file (not header) where the command was read. If |swap|
// is set, then any command data (other than the returned load_command) should
// be swapped when read
- typedef bool (*LoadCommandCallback)(MachoWalker *walker, load_command *cmd,
- off_t offset, bool swap, void *context);
+ typedef bool (*LoadCommandCallback)(MachoWalker* walker, load_command* cmd,
+ off_t offset, bool swap, void* context);
- MachoWalker(const char *path, LoadCommandCallback callback, void *context);
- MachoWalker(void *memory, size_t size, LoadCommandCallback callback,
- void *context);
+ MachoWalker(const char* path, LoadCommandCallback callback, void* context);
+ MachoWalker(void* memory, size_t size, LoadCommandCallback callback,
+ void* context);
~MachoWalker();
// Begin walking the header for |cpu_type| and |cpu_subtype|. If |cpu_type|
@@ -67,17 +66,17 @@ class MachoWalker {
bool WalkHeader(cpu_type_t cpu_type, cpu_subtype_t cpu_subtype);
// Read |size| bytes from the opened file at |offset| into |buffer|
- bool ReadBytes(void *buffer, size_t size, off_t offset);
+ bool ReadBytes(void* buffer, size_t size, off_t offset);
// Return the current header and header offset
- bool CurrentHeader(struct mach_header_64 *header, off_t *offset);
+ bool CurrentHeader(struct mach_header_64* header, off_t* offset);
private:
// Locate (if any) the header offset for |cpu_type| and return in |offset|.
// Return true if found, false otherwise.
bool FindHeader(cpu_type_t cpu_type,
cpu_subtype_t cpu_subtype,
- off_t &offset);
+ off_t& offset);
// Process an individual header starting at |offset| from the start of the
// file. Return true if successful, false otherwise.
@@ -91,27 +90,27 @@ class MachoWalker {
int file_;
// Memory location to read from.
- void *memory_;
+ void* memory_;
// Size of the memory segment we can read from.
size_t memory_size_;
// User specified callback & context
LoadCommandCallback callback_;
- void *callback_context_;
+ void* callback_context_;
// Current header, size, and offset. The mach_header_64 is used for both
// 32-bit and 64-bit headers because they only differ in their last field
// (reserved). By adding the |current_header_size_| and the
// |current_header_offset_|, you can determine the offset in the file just
// after the header.
- struct mach_header_64 *current_header_;
+ struct mach_header_64* current_header_;
unsigned long current_header_size_;
off_t current_header_offset_;
private:
- MachoWalker(const MachoWalker &);
- MachoWalker &operator=(const MachoWalker &);
+ MachoWalker(const MachoWalker&);
+ MachoWalker& operator=(const MachoWalker&);
};
} // namespace MacFileUtilities
diff --git a/src/tools/mac/symupload/minidump_upload.m b/src/common/mac/minidump_upload.m
index 741ad765..d8e2b24a 100644
--- a/src/tools/mac/symupload/minidump_upload.m
+++ b/src/common/mac/minidump_upload.m
@@ -1,5 +1,4 @@
-// Copyright (c) 2006, Google Inc.
-// All rights reserved.
+// Copyright 2006 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -40,18 +39,18 @@
#import "common/mac/HTTPMultipartUpload.h"
typedef struct {
- NSString *minidumpPath;
- NSString *uploadURLStr;
- NSString *product;
- NSString *version;
+ NSString* minidumpPath;
+ NSString* uploadURLStr;
+ NSString* product;
+ NSString* version;
BOOL success;
} Options;
//=============================================================================
-static void Start(Options *options) {
- NSURL *url = [NSURL URLWithString:options->uploadURLStr];
- HTTPMultipartUpload *ul = [[HTTPMultipartUpload alloc] initWithURL:url];
- NSMutableDictionary *parameters = [NSMutableDictionary dictionary];
+static void Start(Options* options) {
+ NSURL* url = [NSURL URLWithString:options->uploadURLStr];
+ HTTPMultipartUpload* ul = [[HTTPMultipartUpload alloc] initWithURL:url];
+ NSMutableDictionary* parameters = [NSMutableDictionary dictionary];
// Add parameters
[parameters setObject:options->product forKey:@"prod"];
@@ -62,9 +61,9 @@ static void Start(Options *options) {
[ul addFileAtPath:options->minidumpPath name:@"upload_file_minidump"];
// Send it
- NSError *error = nil;
- NSData *data = [ul send:&error];
- NSString *result = [[NSString alloc] initWithData:data
+ NSError* error = nil;
+ NSData* data = [ul send:&error];
+ NSString* result = [[NSString alloc] initWithData:data
encoding:NSUTF8StringEncoding];
NSLog(@"Send: %@", error ? [error description] : @"No Error");
@@ -77,11 +76,12 @@ static void Start(Options *options) {
}
//=============================================================================
-static void
-Usage(int argc, const char *argv[]) {
+static void Usage(int argc, const char* argv[]) {
fprintf(stderr, "Submit minidump information.\n");
- fprintf(stderr, "Usage: %s -p <product> -v <version> <minidump> "
- "<upload-URL>\n", argv[0]);
+ fprintf(stderr,
+ "Usage: %s -p <product> -v <version> <minidump> "
+ "<upload-URL>\n",
+ argv[0]);
fprintf(stderr, "<minidump> should be a minidump.\n");
fprintf(stderr, "<upload-URL> is the destination for the upload\n");
@@ -90,12 +90,11 @@ Usage(int argc, const char *argv[]) {
}
//=============================================================================
-static void
-SetupOptions(int argc, const char *argv[], Options *options) {
+static void SetupOptions(int argc, const char* argv[], Options* options) {
extern int optind;
char ch;
- while ((ch = getopt(argc, (char * const *)argv, "p:v:h?")) != -1) {
+ while ((ch = getopt(argc, (char* const*)argv, "p:v:h?")) != -1) {
switch (ch) {
case 'p':
options->product = [NSString stringWithUTF8String:optarg];
@@ -122,8 +121,8 @@ SetupOptions(int argc, const char *argv[], Options *options) {
}
//=============================================================================
-int main (int argc, const char * argv[]) {
- NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+int main(int argc, const char* argv[]) {
+ NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
Options options;
bzero(&options, sizeof(Options));
diff --git a/src/common/mac/scoped_task_suspend-inl.h b/src/common/mac/scoped_task_suspend-inl.h
index d6d1bef9..a4957d7a 100644
--- a/src/common/mac/scoped_task_suspend-inl.h
+++ b/src/common/mac/scoped_task_suspend-inl.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2010 Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/common/mac/string_utilities.cc b/src/common/mac/string_utilities.cc
index 07c0f426..861029d4 100644
--- a/src/common/mac/string_utilities.cc
+++ b/src/common/mac/string_utilities.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2006, Google Inc.
-// All rights reserved.
+// Copyright 2006 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -48,12 +47,12 @@ std::string ConvertToString(CFStringRef str) {
CFStringGetBytes(str, CFRangeMake(0, length), kCFStringEncodingUTF8, 0,
false, buffer.get(), maxUTF8Length, &actualUTF8Length);
buffer[actualUTF8Length] = 0;
- result.assign((const char *)buffer.get());
+ result.assign((const char*)buffer.get());
return result;
}
-unsigned int IntegerValueAtIndex(string &str, unsigned int idx) {
+unsigned int IntegerValueAtIndex(string& str, unsigned int idx) {
string digits("0123456789"), temp;
size_t start = 0;
size_t end;
diff --git a/src/common/mac/string_utilities.h b/src/common/mac/string_utilities.h
index 6d89c834..de282a94 100644
--- a/src/common/mac/string_utilities.h
+++ b/src/common/mac/string_utilities.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2006, Google Inc.
-// All rights reserved.
+// Copyright 2006 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -45,7 +44,7 @@ string ConvertToString(CFStringRef str);
// Return the idx'th decimal integer in str, separated by non-decimal-digits
// E.g., str = 10.4.8, idx = 1 -> 4
-unsigned int IntegerValueAtIndex(string &str, unsigned int idx);
+unsigned int IntegerValueAtIndex(string& str, unsigned int idx);
} // namespace MacStringUtils
diff --git a/src/common/mac/super_fat_arch.h b/src/common/mac/super_fat_arch.h
index 501c8652..046fe166 100644
--- a/src/common/mac/super_fat_arch.h
+++ b/src/common/mac/super_fat_arch.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2015, Google Inc.
-// All rights reserved.
+// Copyright 2015 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -57,7 +56,7 @@ class SuperFatArch {
align(0) {
}
- explicit SuperFatArch(const struct fat_arch &arch) :
+ explicit SuperFatArch(const struct fat_arch& arch) :
cputype(arch.cputype),
cpusubtype(arch.cpusubtype),
offset(arch.offset),
diff --git a/src/common/mac/testing/GTMSenTestCase.h b/src/common/mac/testing/GTMSenTestCase.h
index ce3d9022..cfef3ef1 100644
--- a/src/common/mac/testing/GTMSenTestCase.h
+++ b/src/common/mac/testing/GTMSenTestCase.h
@@ -1,7 +1,7 @@
//
// GTMSenTestCase.h
//
-// Copyright 2007-2008 Google Inc.
+// Copyright 2007-2008 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not
// use this file except in compliance with the License. You may obtain a copy
diff --git a/src/common/mac/testing/GTMSenTestCase.m b/src/common/mac/testing/GTMSenTestCase.m
index 162f01e9..eb9351bf 100644
--- a/src/common/mac/testing/GTMSenTestCase.m
+++ b/src/common/mac/testing/GTMSenTestCase.m
@@ -1,7 +1,7 @@
//
// GTMSenTestCase.m
//
-// Copyright 2007-2008 Google Inc.
+// Copyright 2007-2008 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not
// use this file except in compliance with the License. You may obtain a copy
diff --git a/src/common/macros.h b/src/common/macros.h
index 14bb3f7b..828d49d1 100644
--- a/src/common/macros.h
+++ b/src/common/macros.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2019, Google Inc.
-// All rights reserved.
+// Copyright 2019 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/common/md5.cc b/src/common/md5.cc
index 4f1ac8ca..b6e710da 100644
--- a/src/common/md5.cc
+++ b/src/common/md5.cc
@@ -31,7 +31,7 @@ static void byteReverse(unsigned char *buf, unsigned longs)
do {
t = (u32) ((unsigned) buf[3] << 8 | buf[2]) << 16 |
((unsigned) buf[1] << 8 | buf[0]);
- *(u32 *) buf = t;
+ *(u32*) buf = t;
buf += 4;
} while (--longs);
}
@@ -74,7 +74,7 @@ void MD5Update(struct MD5Context *ctx, unsigned char const *buf, size_t len)
/* Handle any leading odd-sized chunks */
if (t) {
- unsigned char *p = (unsigned char *) ctx->in + t;
+ unsigned char *p = (unsigned char*) ctx->in + t;
t = 64 - t;
if (len < t) {
@@ -83,7 +83,7 @@ void MD5Update(struct MD5Context *ctx, unsigned char const *buf, size_t len)
}
memcpy(p, buf, t);
byteReverse(ctx->in, 16);
- MD5Transform(ctx->buf, (u32 *) ctx->in);
+ MD5Transform(ctx->buf, (u32*) ctx->in);
buf += t;
len -= t;
}
@@ -92,7 +92,7 @@ void MD5Update(struct MD5Context *ctx, unsigned char const *buf, size_t len)
while (len >= 64) {
memcpy(ctx->in, buf, 64);
byteReverse(ctx->in, 16);
- MD5Transform(ctx->buf, (u32 *) ctx->in);
+ MD5Transform(ctx->buf, (u32*) ctx->in);
buf += 64;
len -= 64;
}
@@ -127,7 +127,7 @@ void MD5Final(unsigned char digest[16], struct MD5Context *ctx)
/* Two lots of padding: Pad the first block to 64 bytes */
memset(p, 0, count);
byteReverse(ctx->in, 16);
- MD5Transform(ctx->buf, (u32 *) ctx->in);
+ MD5Transform(ctx->buf, (u32*) ctx->in);
/* Now fill the next block with 56 bytes */
memset(ctx->in, 0, 56);
@@ -141,8 +141,8 @@ void MD5Final(unsigned char digest[16], struct MD5Context *ctx)
memcpy(&ctx->in[14], &ctx->bits[0], sizeof(u32));
memcpy(&ctx->in[15], &ctx->bits[1], sizeof(u32));
- MD5Transform(ctx->buf, (u32 *) ctx->in);
- byteReverse((unsigned char *) ctx->buf, 4);
+ MD5Transform(ctx->buf, (u32*) ctx->in);
+ byteReverse((unsigned char*) ctx->buf, 4);
memcpy(digest, ctx->buf, 16);
memset(ctx, 0, sizeof(*ctx)); /* In case it's sensitive */
}
diff --git a/src/common/md5.h b/src/common/md5.h
index 2ab0ab95..9d1f59b5 100644
--- a/src/common/md5.h
+++ b/src/common/md5.h
@@ -1,8 +1,9 @@
-// Copyright 2007 Google Inc. All Rights Reserved.
+// Copyright 2007 Google LLC
// Author: liuli@google.com (Liu Li)
#ifndef COMMON_MD5_H__
#define COMMON_MD5_H__
+#include <stddef.h>
#include <stdint.h>
namespace google_breakpad {
diff --git a/src/common/memory_allocator.h b/src/common/memory_allocator.h
index a3159ea4..1c99913a 100644
--- a/src/common/memory_allocator.h
+++ b/src/common/memory_allocator.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2009, Google Inc.
-// All rights reserved.
+// Copyright 2009 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -71,12 +70,12 @@ class PageAllocator {
FreeAll();
}
- void *Alloc(size_t bytes) {
+ void* Alloc(size_t bytes) {
if (!bytes)
return NULL;
if (current_page_ && page_size_ - page_offset_ >= bytes) {
- uint8_t *const ret = current_page_ + page_offset_;
+ uint8_t* const ret = current_page_ + page_offset_;
page_offset_ += bytes;
if (page_offset_ == page_size_) {
page_offset_ = 0;
@@ -88,7 +87,7 @@ class PageAllocator {
const size_t pages =
(bytes + sizeof(PageHeader) + page_size_ - 1) / page_size_;
- uint8_t *const ret = GetNPages(pages);
+ uint8_t* const ret = GetNPages(pages);
if (!ret)
return NULL;
@@ -115,8 +114,8 @@ class PageAllocator {
unsigned long pages_allocated() { return pages_allocated_; }
private:
- uint8_t *GetNPages(size_t num_pages) {
- void *a = sys_mmap(NULL, page_size_ * num_pages, PROT_READ | PROT_WRITE,
+ uint8_t* GetNPages(size_t num_pages) {
+ void* a = sys_mmap(NULL, page_size_ * num_pages, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if (a == MAP_FAILED)
return NULL;
@@ -127,7 +126,7 @@ class PageAllocator {
__msan_unpoison(a, page_size_ * num_pages);
#endif
- struct PageHeader *header = reinterpret_cast<PageHeader*>(a);
+ struct PageHeader* header = reinterpret_cast<PageHeader*>(a);
header->next = last_;
header->num_pages = num_pages;
last_ = header;
@@ -138,31 +137,34 @@ class PageAllocator {
}
void FreeAll() {
- PageHeader *next;
+ PageHeader* next;
- for (PageHeader *cur = last_; cur; cur = next) {
+ for (PageHeader* cur = last_; cur; cur = next) {
next = cur->next;
sys_munmap(cur, cur->num_pages * page_size_);
}
}
struct PageHeader {
- PageHeader *next; // pointer to the start of the next set of pages.
+ PageHeader* next; // pointer to the start of the next set of pages.
size_t num_pages; // the number of pages in this set.
};
const size_t page_size_;
- PageHeader *last_;
- uint8_t *current_page_;
+ PageHeader* last_;
+ uint8_t* current_page_;
size_t page_offset_;
unsigned long pages_allocated_;
};
// Wrapper to use with STL containers
template <typename T>
-struct PageStdAllocator : public std::allocator<T> {
- typedef typename std::allocator<T>::pointer pointer;
- typedef typename std::allocator<T>::size_type size_type;
+struct PageStdAllocator {
+ using AllocatorTraits = std::allocator_traits<std::allocator<T>>;
+ using value_type = typename AllocatorTraits::value_type;
+ using pointer = typename AllocatorTraits::pointer;
+ using difference_type = typename AllocatorTraits::difference_type;
+ using size_type = typename AllocatorTraits::size_type;
explicit PageStdAllocator(PageAllocator& allocator) : allocator_(allocator),
stackdata_(NULL),
diff --git a/src/common/memory_allocator_unittest.cc b/src/common/memory_allocator_unittest.cc
index 43c86314..6ca625bb 100644
--- a/src/common/memory_allocator_unittest.cc
+++ b/src/common/memory_allocator_unittest.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2009, Google Inc.
-// All rights reserved.
+// Copyright 2009 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -46,7 +45,7 @@ TEST(PageAllocatorTest, SmallObjects) {
EXPECT_EQ(0U, allocator.pages_allocated());
for (unsigned i = 1; i < 1024; ++i) {
- uint8_t *p = reinterpret_cast<uint8_t*>(allocator.Alloc(i));
+ uint8_t* p = reinterpret_cast<uint8_t*>(allocator.Alloc(i));
ASSERT_FALSE(p == NULL);
memset(p, 0, i);
}
@@ -56,11 +55,11 @@ TEST(PageAllocatorTest, LargeObject) {
PageAllocator allocator;
EXPECT_EQ(0U, allocator.pages_allocated());
- uint8_t *p = reinterpret_cast<uint8_t*>(allocator.Alloc(10000));
+ uint8_t* p = reinterpret_cast<uint8_t*>(allocator.Alloc(10000));
ASSERT_FALSE(p == NULL);
EXPECT_EQ(3U, allocator.pages_allocated());
for (unsigned i = 1; i < 10; ++i) {
- uint8_t *p = reinterpret_cast<uint8_t*>(allocator.Alloc(i));
+ uint8_t* p = reinterpret_cast<uint8_t*>(allocator.Alloc(i));
ASSERT_FALSE(p == NULL);
memset(p, 0, i);
}
diff --git a/src/common/memory_range.h b/src/common/memory_range.h
index 41dd2da6..e2ab61d5 100644
--- a/src/common/memory_range.h
+++ b/src/common/memory_range.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2011, Google Inc.
-// All rights reserved.
+// Copyright 2011 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/common/memory_range_unittest.cc b/src/common/memory_range_unittest.cc
index f6cf8c8b..f112e761 100644
--- a/src/common/memory_range_unittest.cc
+++ b/src/common/memory_range_unittest.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2011, Google Inc.
-// All rights reserved.
+// Copyright 2011 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/common/minidump_type_helper.h b/src/common/minidump_type_helper.h
index 5a7d5a6a..04bafe7e 100644
--- a/src/common/minidump_type_helper.h
+++ b/src/common/minidump_type_helper.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2014, Google Inc.
-// All rights reserved.
+// Copyright 2014 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/common/module.cc b/src/common/module.cc
index aff22127..75782ab1 100644
--- a/src/common/module.cc
+++ b/src/common/module.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2011 Google Inc.
-// All rights reserved.
+// Copyright 2011 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -32,30 +31,84 @@
// module.cc: Implement google_breakpad::Module. See module.h.
#include "common/module.h"
+#include "common/string_view.h"
#include <assert.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
+#include <functional>
#include <iostream>
+#include <memory>
#include <utility>
namespace google_breakpad {
using std::dec;
using std::hex;
+using std::unique_ptr;
+
+Module::InlineOrigin* Module::InlineOriginMap::GetOrCreateInlineOrigin(
+ uint64_t offset,
+ StringView name) {
+ uint64_t specification_offset = references_[offset];
+ // Find the root offset.
+ auto iter = references_.find(specification_offset);
+ while (iter != references_.end() &&
+ specification_offset != references_[specification_offset]) {
+ specification_offset = references_[specification_offset];
+ iter = references_.find(specification_offset);
+ }
+ if (inline_origins_.find(specification_offset) != inline_origins_.end()) {
+ if (inline_origins_[specification_offset]->name == "<name omitted>") {
+ inline_origins_[specification_offset]->name = name;
+ }
+ return inline_origins_[specification_offset];
+ }
+ inline_origins_[specification_offset] = new Module::InlineOrigin(name);
+ return inline_origins_[specification_offset];
+}
+
+void Module::InlineOriginMap::SetReference(uint64_t offset,
+ uint64_t specification_offset) {
+ // If we haven't seen this doesn't exist in reference map, always add it.
+ if (references_.find(offset) == references_.end()) {
+ references_[offset] = specification_offset;
+ return;
+ }
+ // If offset equals specification_offset and offset exists in
+ // references_, there is no need to update the references_ map.
+ // This early return is necessary because the call to erase in following if
+ // will remove the entry of specification_offset in inline_origins_. If
+ // specification_offset equals to references_[offset], it might be
+ // duplicate debug info.
+ if (offset == specification_offset ||
+ specification_offset == references_[offset])
+ return;
+ // Fix up mapping in inline_origins_.
+ auto remove = inline_origins_.find(references_[offset]);
+ if (remove != inline_origins_.end()) {
+ inline_origins_[specification_offset] = std::move(remove->second);
+ inline_origins_.erase(remove);
+ }
+ references_[offset] = specification_offset;
+}
-Module::Module(const string &name, const string &os,
- const string &architecture, const string &id,
- const string &code_id /* = "" */) :
- name_(name),
- os_(os),
- architecture_(architecture),
- id_(id),
- code_id_(code_id),
- load_address_(0) { }
+Module::Module(const string& name,
+ const string& os,
+ const string& architecture,
+ const string& id,
+ const string& code_id /* = "" */,
+ bool enable_multiple_field /* = false*/)
+ : name_(name),
+ os_(os),
+ architecture_(architecture),
+ id_(id),
+ code_id_(code_id),
+ load_address_(0),
+ enable_multiple_field_(enable_multiple_field) {}
Module::~Module() {
for (FileByNameMap::iterator it = files_.begin(); it != files_.end(); ++it)
@@ -64,12 +117,6 @@ Module::~Module() {
it != functions_.end(); ++it) {
delete *it;
}
- for (vector<StackFrameEntry *>::iterator it = stack_frame_entries_.begin();
- it != stack_frame_entries_.end(); ++it) {
- delete *it;
- }
- for (ExternSet::iterator it = externs_.begin(); it != externs_.end(); ++it)
- delete *it;
}
void Module::SetLoadAddress(Address address) {
@@ -80,13 +127,13 @@ void Module::SetAddressRanges(const vector<Range>& ranges) {
address_ranges_ = ranges;
}
-void Module::AddFunction(Function *function) {
+bool Module::AddFunction(Function* function) {
// FUNC lines must not hold an empty name, so catch the problem early if
// callers try to add one.
assert(!function->name.empty());
if (!AddressIsInModule(function->address)) {
- return;
+ return false;
}
// FUNCs are better than PUBLICs as they come with sizes, so remove an extern
@@ -101,7 +148,12 @@ void Module::AddFunction(Function *function) {
it_ext = externs_.find(&arm_thumb_ext);
}
if (it_ext != externs_.end()) {
- delete *it_ext;
+ if (enable_multiple_field_) {
+ Extern* found_ext = it_ext->get();
+ // If the PUBLIC is for the same symbol as the FUNC, don't mark multiple.
+ function->is_multiple |=
+ found_ext->name != function->name || found_ext->is_multiple;
+ }
externs_.erase(it_ext);
}
#if _DEBUG
@@ -115,53 +167,60 @@ void Module::AddFunction(Function *function) {
}
}
#endif
-
- std::pair<FunctionSet::iterator,bool> ret = functions_.insert(function);
+ if (enable_multiple_field_ && function_addresses_.count(function->address)) {
+ FunctionSet::iterator existing_function = std::find_if(
+ functions_.begin(), functions_.end(),
+ [&](Function* other) { return other->address == function->address; });
+ assert(existing_function != functions_.end());
+ (*existing_function)->is_multiple = true;
+ // Free the duplicate that was not inserted because this Module
+ // now owns it.
+ return false;
+ }
+ function_addresses_.emplace(function->address);
+ std::pair<FunctionSet::iterator, bool> ret = functions_.insert(function);
if (!ret.second && (*ret.first != function)) {
// Free the duplicate that was not inserted because this Module
// now owns it.
- delete function;
+ return false;
}
+ return true;
}
-void Module::AddFunctions(vector<Function *>::iterator begin,
- vector<Function *>::iterator end) {
- for (vector<Function *>::iterator it = begin; it != end; ++it)
- AddFunction(*it);
-}
-
-void Module::AddStackFrameEntry(StackFrameEntry *stack_frame_entry) {
+void Module::AddStackFrameEntry(std::unique_ptr<StackFrameEntry> stack_frame_entry) {
if (!AddressIsInModule(stack_frame_entry->address)) {
return;
}
- stack_frame_entries_.push_back(stack_frame_entry);
+ stack_frame_entries_.push_back(std::move(stack_frame_entry));
}
-void Module::AddExtern(Extern *ext) {
+void Module::AddExtern(std::unique_ptr<Extern> ext) {
if (!AddressIsInModule(ext->address)) {
return;
}
- std::pair<ExternSet::iterator,bool> ret = externs_.insert(ext);
- if (!ret.second) {
- // Free the duplicate that was not inserted because this Module
- // now owns it.
- delete ext;
+ std::pair<ExternSet::iterator,bool> ret = externs_.emplace(std::move(ext));
+ if (!ret.second && enable_multiple_field_) {
+ (*ret.first)->is_multiple = true;
}
}
-void Module::GetFunctions(vector<Function *> *vec,
- vector<Function *>::iterator i) {
+void Module::GetFunctions(vector<Function*>* vec,
+ vector<Function*>::iterator i) {
vec->insert(i, functions_.begin(), functions_.end());
}
-void Module::GetExterns(vector<Extern *> *vec,
- vector<Extern *>::iterator i) {
- vec->insert(i, externs_.begin(), externs_.end());
+void Module::GetExterns(vector<Extern*>* vec,
+ vector<Extern*>::iterator i) {
+ auto pos = vec->insert(i, externs_.size(), nullptr);
+ for (const std::unique_ptr<Extern>& ext : externs_) {
+ *pos = ext.get();
+ ++pos;
+ }
}
-Module::File *Module::FindFile(const string &name) {
+Module::File* Module::FindFile(const string& name) {
// A tricky bit here. The key of each map entry needs to be a
// pointer to the entry's File's name string. This means that we
// can't do the initial lookup with any operation that would create
@@ -175,7 +234,7 @@ Module::File *Module::FindFile(const string &name) {
FileByNameMap::iterator destiny = files_.lower_bound(&name);
if (destiny == files_.end()
|| *destiny->first != name) { // Repeated string comparison, boo hoo.
- File *file = new File(name);
+ File* file = new File(name);
file->source_id = -1;
destiny = files_.insert(destiny,
FileByNameMap::value_type(&file->name, file));
@@ -183,27 +242,32 @@ Module::File *Module::FindFile(const string &name) {
return destiny->second;
}
-Module::File *Module::FindFile(const char *name) {
+Module::File* Module::FindFile(const char* name) {
string name_string = name;
return FindFile(name_string);
}
-Module::File *Module::FindExistingFile(const string &name) {
+Module::File* Module::FindExistingFile(const string& name) {
FileByNameMap::iterator it = files_.find(&name);
return (it == files_.end()) ? NULL : it->second;
}
-void Module::GetFiles(vector<File *> *vec) {
+void Module::GetFiles(vector<File*>* vec) {
vec->clear();
for (FileByNameMap::iterator it = files_.begin(); it != files_.end(); ++it)
vec->push_back(it->second);
}
-void Module::GetStackFrameEntries(vector<StackFrameEntry *> *vec) const {
- *vec = stack_frame_entries_;
+void Module::GetStackFrameEntries(vector<StackFrameEntry*>* vec) const {
+ vec->clear();
+ vec->reserve(stack_frame_entries_.size());
+ for (const auto& ent : stack_frame_entries_) {
+ vec->push_back(ent.get());
+ }
}
-void Module::AssignSourceIds() {
+void Module::AssignSourceIds(
+ set<InlineOrigin*, InlineOriginCompare>& inline_origins) {
// First, give every source file an id of -1.
for (FileByNameMap::iterator file_it = files_.begin();
file_it != files_.end(); ++file_it) {
@@ -214,12 +278,25 @@ void Module::AssignSourceIds() {
// info, by setting each one's source id to zero.
for (FunctionSet::const_iterator func_it = functions_.begin();
func_it != functions_.end(); ++func_it) {
- Function *func = *func_it;
+ Function* func = *func_it;
for (vector<Line>::iterator line_it = func->lines.begin();
line_it != func->lines.end(); ++line_it)
line_it->file->source_id = 0;
}
+ // Also mark all files cited by inline callsite by setting each one's source
+ // id to zero.
+ auto markInlineFiles = [](unique_ptr<Inline>& in) {
+ // There are some artificial inline functions which don't belong to
+ // any file. Those will have file id -1.
+ if (in->call_site_file) {
+ in->call_site_file->source_id = 0;
+ }
+ };
+ for (auto func : functions_) {
+ Inline::InlineDFS(func->inlines, markInlineFiles);
+ }
+
// Finally, assign source ids to those files that have been marked.
// We could have just assigned source id numbers while traversing
// the line numbers, but doing it this way numbers the files in
@@ -232,13 +309,32 @@ void Module::AssignSourceIds() {
}
}
+void Module::CreateInlineOrigins(
+ set<InlineOrigin*, InlineOriginCompare>& inline_origins) {
+ // Only add origins that have file and deduplicate origins with same name and
+ // file id by doing a DFS.
+ auto addInlineOrigins = [&](unique_ptr<Inline>& in) {
+ auto it = inline_origins.find(in->origin);
+ if (it == inline_origins.end())
+ inline_origins.insert(in->origin);
+ else
+ in->origin = *it;
+ };
+ for (Function* func : functions_)
+ Module::Inline::InlineDFS(func->inlines, addInlineOrigins);
+ int next_id = 0;
+ for (InlineOrigin* origin : inline_origins) {
+ origin->id = next_id++;
+ }
+}
+
bool Module::ReportError() {
fprintf(stderr, "error writing symbol file: %s\n",
strerror(errno));
return false;
}
-bool Module::WriteRuleMap(const RuleMap &rule_map, std::ostream &stream) {
+bool Module::WriteRuleMap(const RuleMap& rule_map, std::ostream& stream) {
for (RuleMap::const_iterator it = rule_map.begin();
it != rule_map.end(); ++it) {
if (it != rule_map.begin())
@@ -261,7 +357,7 @@ bool Module::AddressIsInModule(Address address) const {
return false;
}
-bool Module::Write(std::ostream &stream, SymbolData symbol_data) {
+bool Module::Write(std::ostream& stream, SymbolData symbol_data) {
stream << "MODULE " << os_ << " " << architecture_ << " "
<< id_ << " " << name_ << "\n";
if (!stream.good())
@@ -271,33 +367,54 @@ bool Module::Write(std::ostream &stream, SymbolData symbol_data) {
stream << "INFO CODE_ID " << code_id_ << "\n";
}
- if (symbol_data != ONLY_CFI) {
- AssignSourceIds();
+ if (symbol_data & SYMBOLS_AND_FILES) {
+ // Get all referenced inline origins.
+ set<InlineOrigin*, InlineOriginCompare> inline_origins;
+ CreateInlineOrigins(inline_origins);
+ AssignSourceIds(inline_origins);
// Write out files.
for (FileByNameMap::iterator file_it = files_.begin();
file_it != files_.end(); ++file_it) {
- File *file = file_it->second;
+ File* file = file_it->second;
if (file->source_id >= 0) {
stream << "FILE " << file->source_id << " " << file->name << "\n";
if (!stream.good())
return ReportError();
}
}
+ // Write out inline origins.
+ for (InlineOrigin* origin : inline_origins) {
+ stream << "INLINE_ORIGIN " << origin->id << " " << origin->name << "\n";
+ if (!stream.good())
+ return ReportError();
+ }
- // Write out functions and their lines.
+ // Write out functions and their inlines and lines.
for (FunctionSet::const_iterator func_it = functions_.begin();
func_it != functions_.end(); ++func_it) {
- Function *func = *func_it;
+ Function* func = *func_it;
vector<Line>::iterator line_it = func->lines.begin();
for (auto range_it = func->ranges.cbegin();
range_it != func->ranges.cend(); ++range_it) {
- stream << "FUNC " << hex
- << (range_it->address - load_address_) << " "
- << range_it->size << " "
- << func->parameter_size << " "
- << func->name << dec << "\n";
+ stream << "FUNC " << (func->is_multiple ? "m " : "") << hex
+ << (range_it->address - load_address_) << " " << range_it->size
+ << " " << func->parameter_size << " " << func->name << dec
+ << "\n";
+
+ if (!stream.good())
+ return ReportError();
+ // Write out inlines.
+ auto write_inline = [&](unique_ptr<Inline>& in) {
+ stream << "INLINE ";
+ stream << in->inline_nest_level << " " << in->call_site_line << " "
+ << in->getCallSiteFileID() << " " << in->origin->id << hex;
+ for (const Range& r : in->ranges)
+ stream << " " << (r.address - load_address_) << " " << r.size;
+ stream << dec << "\n";
+ };
+ Module::Inline::InlineDFS(func->inlines, write_inline);
if (!stream.good())
return ReportError();
@@ -322,19 +439,18 @@ bool Module::Write(std::ostream &stream, SymbolData symbol_data) {
// Write out 'PUBLIC' records.
for (ExternSet::const_iterator extern_it = externs_.begin();
extern_it != externs_.end(); ++extern_it) {
- Extern *ext = *extern_it;
- stream << "PUBLIC " << hex
- << (ext->address - load_address_) << " 0 "
- << ext->name << dec << "\n";
+ Extern* ext = extern_it->get();
+ stream << "PUBLIC " << (ext->is_multiple ? "m " : "") << hex
+ << (ext->address - load_address_) << " 0 " << ext->name << dec
+ << "\n";
}
}
- if (symbol_data != NO_CFI) {
+ if (symbol_data & CFI) {
// Write out 'STACK CFI INIT' and 'STACK CFI' records.
- vector<StackFrameEntry *>::const_iterator frame_it;
- for (frame_it = stack_frame_entries_.begin();
+ for (auto frame_it = stack_frame_entries_.begin();
frame_it != stack_frame_entries_.end(); ++frame_it) {
- StackFrameEntry *entry = *frame_it;
+ StackFrameEntry* entry = frame_it->get();
stream << "STACK CFI INIT " << hex
<< (entry->address - load_address_) << " "
<< entry->size << " " << dec;
diff --git a/src/common/module.h b/src/common/module.h
index 7309cedd..c1fd9f59 100644
--- a/src/common/module.h
+++ b/src/common/module.h
@@ -1,7 +1,6 @@
// -*- mode: c++ -*-
-// Copyright (c) 2010 Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -13,7 +12,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -38,13 +37,18 @@
#ifndef COMMON_LINUX_MODULE_H__
#define COMMON_LINUX_MODULE_H__
+#include <functional>
#include <iostream>
+#include <limits>
#include <map>
+#include <memory>
#include <set>
#include <string>
#include <vector>
+#include "common/string_view.h"
#include "common/symbol_data.h"
+#include "common/unordered.h"
#include "common/using_std_string.h"
#include "google_breakpad/common/breakpad_types.h"
@@ -62,8 +66,11 @@ class Module {
public:
// The type of addresses and sizes in a symbol table.
typedef uint64_t Address;
+ static constexpr uint64_t kMaxAddress = std::numeric_limits<Address>::max();
struct File;
struct Function;
+ struct InlineOrigin;
+ struct Inline;
struct Line;
struct Extern;
@@ -74,7 +81,7 @@ class Module {
// A source file.
struct File {
- explicit File(const string &name_input) : name(name_input), source_id(0) {}
+ explicit File(const string& name_input) : name(name_input), source_id(0) {}
// The name of the source file.
const string name;
@@ -96,17 +103,17 @@ class Module {
// A function.
struct Function {
- Function(const string &name_input, const Address &address_input) :
+ Function(StringView name_input, const Address& address_input) :
name(name_input), address(address_input), parameter_size(0) {}
// For sorting by address. (Not style-guide compliant, but it's
// stupid not to put this in the struct.)
- static bool CompareByAddress(const Function *x, const Function *y) {
+ static bool CompareByAddress(const Function* x, const Function* y) {
return x->address < y->address;
}
// The function's name.
- string name;
+ StringView name;
// The start address and the address ranges covered by the function.
const Address address;
@@ -118,26 +125,127 @@ class Module {
// Source lines belonging to this function, sorted by increasing
// address.
vector<Line> lines;
+
+ // Inlined call sites belonging to this functions.
+ vector<std::unique_ptr<Inline>> inlines;
+
+ // If this symbol has been folded with other symbols in the linked binary.
+ bool is_multiple = false;
+ };
+
+ struct InlineOrigin {
+ explicit InlineOrigin(StringView name) : id(-1), name(name) {}
+
+ // A unique id for each InlineOrigin object. INLINE records use the id to
+ // refer to its INLINE_ORIGIN record.
+ int id;
+
+ // The inlined function's name.
+ StringView name;
+
+ File* file;
+
+ int getFileID() const { return file ? file->source_id : -1; }
+ };
+
+ // A inlined call site.
+ struct Inline {
+ Inline(InlineOrigin* origin,
+ const vector<Range>& ranges,
+ int call_site_line,
+ int call_site_file_id,
+ int inline_nest_level,
+ vector<std::unique_ptr<Inline>> child_inlines)
+ : origin(origin),
+ ranges(ranges),
+ call_site_line(call_site_line),
+ call_site_file_id(call_site_file_id),
+ call_site_file(nullptr),
+ inline_nest_level(inline_nest_level),
+ child_inlines(std::move(child_inlines)) {}
+
+ InlineOrigin* origin;
+
+ // The list of addresses and sizes.
+ vector<Range> ranges;
+
+ int call_site_line;
+
+ // The id is only meanful inside a CU. It's only used for looking up real
+ // File* after scanning a CU.
+ int call_site_file_id;
+
+ File* call_site_file;
+
+ int inline_nest_level;
+
+ // A list of inlines which are children of this inline.
+ vector<std::unique_ptr<Inline>> child_inlines;
+
+ int getCallSiteFileID() const {
+ return call_site_file ? call_site_file->source_id : -1;
+ }
+
+ static void InlineDFS(
+ vector<std::unique_ptr<Module::Inline>>& inlines,
+ std::function<void(std::unique_ptr<Module::Inline>&)> const& forEach) {
+ for (std::unique_ptr<Module::Inline>& in : inlines) {
+ forEach(in);
+ InlineDFS(in->child_inlines, forEach);
+ }
+ }
+ };
+
+ typedef map<uint64_t, InlineOrigin*> InlineOriginByOffset;
+
+ class InlineOriginMap {
+ public:
+ // Add INLINE ORIGIN to the module. Return a pointer to origin .
+ InlineOrigin* GetOrCreateInlineOrigin(uint64_t offset, StringView name);
+
+ // offset is the offset of a DW_TAG_subprogram. specification_offset is the
+ // value of its DW_AT_specification or equals to offset if
+ // DW_AT_specification doesn't exist in that DIE.
+ void SetReference(uint64_t offset, uint64_t specification_offset);
+
+ ~InlineOriginMap() {
+ for (const auto& iter : inline_origins_) {
+ delete iter.second;
+ }
+ }
+
+ private:
+ // A map from a DW_TAG_subprogram's offset to the DW_TAG_subprogram.
+ InlineOriginByOffset inline_origins_;
+
+ // A map from a DW_TAG_subprogram's offset to the offset of its
+ // specification or abstract origin subprogram. The set of values in this
+ // map should always be the same set of keys in inline_origins_.
+ map<uint64_t, uint64_t> references_;
};
+ InlineOriginMap inline_origin_map;
+
// A source line.
struct Line {
// For sorting by address. (Not style-guide compliant, but it's
// stupid not to put this in the struct.)
- static bool CompareByAddress(const Module::Line &x, const Module::Line &y) {
+ static bool CompareByAddress(const Module::Line& x, const Module::Line& y) {
return x.address < y.address;
}
Address address, size; // The address and size of the line's code.
- File *file; // The source file.
+ File* file; // The source file.
int number; // The source line number.
};
// An exported symbol.
struct Extern {
- explicit Extern(const Address &address_input) : address(address_input) {}
+ explicit Extern(const Address& address_input) : address(address_input) {}
const Address address;
string name;
+ // If this symbol has been folded with other symbols in the linked binary.
+ bool is_multiple = false;
};
// A map from register names to postfix expressions that recover
@@ -170,25 +278,46 @@ class Module {
};
struct FunctionCompare {
- bool operator() (const Function *lhs,
- const Function *rhs) const {
+ bool operator() (const Function* lhs, const Function* rhs) const {
if (lhs->address == rhs->address)
return lhs->name < rhs->name;
return lhs->address < rhs->address;
}
};
+ struct InlineOriginCompare {
+ bool operator()(const InlineOrigin* lhs, const InlineOrigin* rhs) const {
+ return lhs->name < rhs->name;
+ }
+ };
+
struct ExternCompare {
- bool operator() (const Extern *lhs,
- const Extern *rhs) const {
+ // Defining is_transparent allows
+ // std::set<std::unique_ptr<Extern>, ExternCompare>::find() to be called
+ // with an Extern* and have set use the overloads below.
+ using is_transparent = void;
+ bool operator() (const std::unique_ptr<Extern>& lhs,
+ const std::unique_ptr<Extern>& rhs) const {
+ return lhs->address < rhs->address;
+ }
+ bool operator() (const Extern* lhs, const std::unique_ptr<Extern>& rhs) const {
+ return lhs->address < rhs->address;
+ }
+ bool operator() (const std::unique_ptr<Extern>& lhs, const Extern* rhs) const {
return lhs->address < rhs->address;
}
};
// Create a new module with the given name, operating system,
// architecture, and ID string.
- Module(const string &name, const string &os, const string &architecture,
- const string &id, const string &code_id = "");
+ // NB: `enable_multiple_field` is temporary while transitioning to enabling
+ // writing the multiple field permanently.
+ Module(const string& name,
+ const string& os,
+ const string& architecture,
+ const string& id,
+ const string& code_id = "",
+ bool enable_multiple_field = false);
~Module();
// Set the module's load address to LOAD_ADDRESS; addresses given
@@ -216,83 +345,90 @@ class Module {
// Add FUNCTION to the module. FUNCTION's name must not be empty.
// This module owns all Function objects added with this function:
// destroying the module destroys them as well.
- void AddFunction(Function *function);
-
- // Add all the functions in [BEGIN,END) to the module.
- // This module owns all Function objects added with this function:
- // destroying the module destroys them as well.
- void AddFunctions(vector<Function *>::iterator begin,
- vector<Function *>::iterator end);
+ // Return false if the function is duplicate and needs to be freed.
+ bool AddFunction(Function* function);
// Add STACK_FRAME_ENTRY to the module.
// This module owns all StackFrameEntry objects added with this
// function: destroying the module destroys them as well.
- void AddStackFrameEntry(StackFrameEntry *stack_frame_entry);
+ void AddStackFrameEntry(std::unique_ptr<StackFrameEntry> stack_frame_entry);
// Add PUBLIC to the module.
// This module owns all Extern objects added with this function:
// destroying the module destroys them as well.
- void AddExtern(Extern *ext);
+ void AddExtern(std::unique_ptr<Extern> ext);
// If this module has a file named NAME, return a pointer to it. If
// it has none, then create one and return a pointer to the new
// file. This module owns all File objects created using these
// functions; destroying the module destroys them as well.
- File *FindFile(const string &name);
- File *FindFile(const char *name);
+ File* FindFile(const string& name);
+ File* FindFile(const char* name);
// If this module has a file named NAME, return a pointer to it.
// Otherwise, return NULL.
- File *FindExistingFile(const string &name);
+ File* FindExistingFile(const string& name);
// Insert pointers to the functions added to this module at I in
// VEC. The pointed-to Functions are still owned by this module.
// (Since this is effectively a copy of the function list, this is
// mostly useful for testing; other uses should probably get a more
// appropriate interface.)
- void GetFunctions(vector<Function *> *vec, vector<Function *>::iterator i);
+ void GetFunctions(vector<Function*>* vec, vector<Function*>::iterator i);
// Insert pointers to the externs added to this module at I in
// VEC. The pointed-to Externs are still owned by this module.
// (Since this is effectively a copy of the extern list, this is
// mostly useful for testing; other uses should probably get a more
// appropriate interface.)
- void GetExterns(vector<Extern *> *vec, vector<Extern *>::iterator i);
+ void GetExterns(vector<Extern*>* vec, vector<Extern*>::iterator i);
// Clear VEC and fill it with pointers to the Files added to this
// module, sorted by name. The pointed-to Files are still owned by
// this module. (Since this is effectively a copy of the file list,
// this is mostly useful for testing; other uses should probably get
// a more appropriate interface.)
- void GetFiles(vector<File *> *vec);
+ void GetFiles(vector<File*>* vec);
// Clear VEC and fill it with pointers to the StackFrameEntry
// objects that have been added to this module. (Since this is
// effectively a copy of the stack frame entry list, this is mostly
// useful for testing; other uses should probably get
// a more appropriate interface.)
- void GetStackFrameEntries(vector<StackFrameEntry *> *vec) const;
+ void GetStackFrameEntries(vector<StackFrameEntry*>* vec) const;
// Find those files in this module that are actually referred to by
// functions' line number data, and assign them source id numbers.
// Set the source id numbers for all other files --- unused by the
// source line data --- to -1. We do this before writing out the
// symbol file, at which point we omit any unused files.
- void AssignSourceIds();
+ void AssignSourceIds(set<InlineOrigin*, InlineOriginCompare>& inline_origins);
+
+ // This function should be called before AssignSourceIds() to get the set of
+ // valid InlineOrigins*.
+ void CreateInlineOrigins(
+ set<InlineOrigin*, InlineOriginCompare>& inline_origins);
// Call AssignSourceIds, and write this module to STREAM in the
// breakpad symbol format. Return true if all goes well, or false if
// an error occurs. This method writes out:
// - a header based on the values given to the constructor,
- // If symbol_data is not ONLY_CFI then:
+ // If symbol_data is not CFI then:
// - the source files added via FindFile,
// - the functions added via AddFunctions, each with its lines,
// - all public records,
- // If symbol_data is not NO_CFI then:
+ // If symbol_data is CFI then:
// - all CFI records.
// Addresses in the output are all relative to the load address
// established by SetLoadAddress.
- bool Write(std::ostream &stream, SymbolData symbol_data);
+ bool Write(std::ostream& stream, SymbolData symbol_data);
+
+ // Place the name in the global set of strings. Return a StringView points to
+ // a string inside the pool.
+ StringView AddStringToPool(const string& str) {
+ auto result = common_strings_.insert(str);
+ return *(result.first);
+ }
string name() const { return name_; }
string os() const { return os_; }
@@ -308,7 +444,7 @@ class Module {
// Write RULE_MAP to STREAM, in the form appropriate for 'STACK CFI'
// records, without a final newline. Return true if all goes well;
// if an error occurs, return false, and leave errno set.
- static bool WriteRuleMap(const RuleMap &rule_map, std::ostream &stream);
+ static bool WriteRuleMap(const RuleMap& rule_map, std::ostream& stream);
// Returns true of the specified address resides with an specified address
// range, or if no ranges have been specified.
@@ -329,32 +465,43 @@ class Module {
// Relation for maps whose keys are strings shared with some other
// structure.
struct CompareStringPtrs {
- bool operator()(const string *x, const string *y) const { return *x < *y; }
+ bool operator()(const string* x, const string* y) const { return *x < *y; }
};
// A map from filenames to File structures. The map's keys are
// pointers to the Files' names.
- typedef map<const string *, File *, CompareStringPtrs> FileByNameMap;
+ typedef map<const string*, File*, CompareStringPtrs> FileByNameMap;
// A set containing Function structures, sorted by address.
- typedef set<Function *, FunctionCompare> FunctionSet;
+ typedef set<Function*, FunctionCompare> FunctionSet;
// A set containing Extern structures, sorted by address.
- typedef set<Extern *, ExternCompare> ExternSet;
+ typedef set<std::unique_ptr<Extern>, ExternCompare> ExternSet;
// The module owns all the files and functions that have been added
// to it; destroying the module frees the Files and Functions these
// point to.
FileByNameMap files_; // This module's source files.
FunctionSet functions_; // This module's functions.
+ // Used to quickly look up whether a function exists at a particular address.
+ unordered_set<Address> function_addresses_;
// The module owns all the call frame info entries that have been
// added to it.
- vector<StackFrameEntry *> stack_frame_entries_;
+ vector<std::unique_ptr<StackFrameEntry>> stack_frame_entries_;
// The module owns all the externs that have been added to it;
// destroying the module frees the Externs these point to.
ExternSet externs_;
+
+ unordered_set<string> common_strings_;
+
+ // Whether symbols sharing an address should be collapsed into a single entry
+ // and marked with an `m` in the output. See
+ // https://bugs.chromium.org/p/google-breakpad/issues/detail?id=751 and docs
+ // at
+ // https://chromium.googlesource.com/breakpad/breakpad/+/master/docs/symbol_files.md#records-3
+ bool enable_multiple_field_;
};
} // namespace google_breakpad
diff --git a/src/common/module_unittest.cc b/src/common/module_unittest.cc
index 37fee5dd..39727554 100644
--- a/src/common/module_unittest.cc
+++ b/src/common/module_unittest.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2010 Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -37,19 +36,22 @@
#include <string.h>
#include <algorithm>
+#include <memory>
#include <sstream>
#include <string>
+#include <utility>
#include "breakpad_googletest_includes.h"
#include "common/module.h"
#include "common/using_std_string.h"
using google_breakpad::Module;
+using google_breakpad::StringView;
using std::stringstream;
using std::vector;
using testing::ContainerEq;
-static Module::Function* generate_duplicate_function(const string &name) {
+static Module::Function* generate_duplicate_function(StringView name) {
const Module::Address DUP_ADDRESS = 0xd35402aac7a7ad5cULL;
const Module::Address DUP_SIZE = 0x200b26e605f99071ULL;
const Module::Address DUP_PARAMETER_SIZE = 0xf14ac4fed48c4a99ULL;
@@ -67,7 +69,7 @@ static Module::Function* generate_duplicate_function(const string &name) {
#define MODULE_ID "id-string"
#define MODULE_CODE_ID "code-id-string"
-TEST(Write, Header) {
+TEST(Module, WriteHeader) {
stringstream s;
Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID);
m.Write(s, ALL_SYMBOL_DATA);
@@ -76,7 +78,7 @@ TEST(Write, Header) {
contents.c_str());
}
-TEST(Write, HeaderCodeId) {
+TEST(Module, WriteHeaderCodeId) {
stringstream s;
Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID, MODULE_CODE_ID);
m.Write(s, ALL_SYMBOL_DATA);
@@ -86,7 +88,7 @@ TEST(Write, HeaderCodeId) {
contents.c_str());
}
-TEST(Write, OneLineFunc) {
+TEST(Module, WriteOneLineFunc) {
stringstream s;
Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID);
@@ -111,7 +113,7 @@ TEST(Write, OneLineFunc) {
contents.c_str());
}
-TEST(Write, RelativeLoadAddress) {
+TEST(Module, WriteRelativeLoadAddress) {
stringstream s;
Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID);
@@ -137,7 +139,7 @@ TEST(Write, RelativeLoadAddress) {
m.AddFunction(function);
// Some stack information.
- Module::StackFrameEntry* entry = new Module::StackFrameEntry();
+ auto entry = std::make_unique<Module::StackFrameEntry>();
entry->address = 0x30f9e5c83323973dULL;
entry->size = 0x49fc9ca7c7c13dc2ULL;
entry->initial_rules[".cfa"] = "he was a handsome man";
@@ -145,7 +147,7 @@ TEST(Write, RelativeLoadAddress) {
entry->rule_changes[0x30f9e5c83323973eULL]["how"] =
"do you like your blueeyed boy";
entry->rule_changes[0x30f9e5c83323973eULL]["Mister"] = "Death";
- m.AddStackFrameEntry(entry);
+ m.AddStackFrameEntry(std::move(entry));
// Set the load address. Doing this after adding all the data to
// the module must work fine.
@@ -169,7 +171,7 @@ TEST(Write, RelativeLoadAddress) {
contents.c_str());
}
-TEST(Write, OmitUnusedFiles) {
+TEST(Module, WriteOmitUnusedFiles) {
Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID);
// Create some source files.
@@ -193,7 +195,8 @@ TEST(Write, OmitUnusedFiles) {
function->lines.push_back(line2);
m.AddFunction(function);
- m.AssignSourceIds();
+ std::set<Module::InlineOrigin*, Module::InlineOriginCompare> inline_origins;
+ m.AssignSourceIds(inline_origins);
vector<Module::File*> vec;
m.GetFiles(&vec);
@@ -219,7 +222,7 @@ TEST(Write, OmitUnusedFiles) {
contents.c_str());
}
-TEST(Write, NoCFI) {
+TEST(Module, WriteNoCFI) {
stringstream s;
Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID);
@@ -241,7 +244,7 @@ TEST(Write, NoCFI) {
m.AddFunction(function);
// Some stack information.
- Module::StackFrameEntry* entry = new Module::StackFrameEntry();
+ auto entry = std::make_unique<Module::StackFrameEntry>();
entry->address = 0x30f9e5c83323973dULL;
entry->size = 0x49fc9ca7c7c13dc2ULL;
entry->initial_rules[".cfa"] = "he was a handsome man";
@@ -249,13 +252,13 @@ TEST(Write, NoCFI) {
entry->rule_changes[0x30f9e5c83323973eULL]["how"] =
"do you like your blueeyed boy";
entry->rule_changes[0x30f9e5c83323973eULL]["Mister"] = "Death";
- m.AddStackFrameEntry(entry);
+ m.AddStackFrameEntry(std::move(entry));
// Set the load address. Doing this after adding all the data to
// the module must work fine.
m.SetLoadAddress(0x2ab698b0b6407073ULL);
- m.Write(s, NO_CFI);
+ m.Write(s, SYMBOLS_AND_FILES | INLINES);
string contents = s.str();
EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n"
"FILE 0 filename.cc\n"
@@ -265,7 +268,7 @@ TEST(Write, NoCFI) {
contents.c_str());
}
-TEST(Construct, AddFunctions) {
+TEST(Module, ConstructAddFunction) {
stringstream s;
Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID);
@@ -287,7 +290,8 @@ TEST(Construct, AddFunctions) {
vec.push_back(function1);
vec.push_back(function2);
- m.AddFunctions(vec.begin(), vec.end());
+ for (Module::Function* func: vec)
+ m.AddFunction(func);
m.Write(s, ALL_SYMBOL_DATA);
string contents = s.str();
@@ -306,27 +310,79 @@ TEST(Construct, AddFunctions) {
EXPECT_EQ((size_t) 2, vec.size());
}
-TEST(Construct, AddFrames) {
+TEST(Module, WriteOutOfRangeAddresses) {
+ stringstream s;
+ Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID);
+
+ // Specify an allowed address range, representing a PT_LOAD segment in a
+ // module.
+ vector<Module::Range> address_ranges = {
+ Module::Range(0x2000ULL, 0x1000ULL),
+ };
+ m.SetAddressRanges(address_ranges);
+
+ // Add three stack frames (one lower, one in, and one higher than the allowed
+ // address range). Only the middle frame should be captured.
+ auto entry1 = std::make_unique<Module::StackFrameEntry>();
+ entry1->address = 0x1000ULL;
+ entry1->size = 0x100ULL;
+ m.AddStackFrameEntry(std::move(entry1));
+ auto entry2 = std::make_unique<Module::StackFrameEntry>();
+ entry2->address = 0x2000ULL;
+ entry2->size = 0x100ULL;
+ m.AddStackFrameEntry(std::move(entry2));
+ auto entry3 = std::make_unique<Module::StackFrameEntry>();
+ entry3->address = 0x3000ULL;
+ entry3->size = 0x100ULL;
+ m.AddStackFrameEntry(std::move(entry3));
+
+ // Add a function outside the allowed range.
+ Module::File* file = m.FindFile("file_name.cc");
+ Module::Function* function = new Module::Function(
+ "function_name", 0x4000ULL);
+ Module::Range range(0x4000ULL, 0x1000ULL);
+ function->ranges.push_back(range);
+ function->parameter_size = 0x100ULL;
+ Module::Line line = { 0x4000ULL, 0x100ULL, file, 67519080 };
+ function->lines.push_back(line);
+ m.AddFunction(function);
+
+ // Add an extern outside the allowed range.
+ auto extern1 = std::make_unique<Module::Extern>(0x5000ULL);
+ extern1->name = "_xyz";
+ m.AddExtern(std::move(extern1));
+
+ m.Write(s, ALL_SYMBOL_DATA);
+
+ EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n"
+ "STACK CFI INIT 2000 100 \n",
+ s.str().c_str());
+
+ // Cleanup - Prevent Memory Leak errors.
+ delete (function);
+}
+
+TEST(Module, ConstructAddFrames) {
stringstream s;
Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID);
// First STACK CFI entry, with no initial rules or deltas.
- Module::StackFrameEntry* entry1 = new Module::StackFrameEntry();
+ auto entry1 = std::make_unique<Module::StackFrameEntry>();
entry1->address = 0xddb5f41285aa7757ULL;
entry1->size = 0x1486493370dc5073ULL;
- m.AddStackFrameEntry(entry1);
+ m.AddStackFrameEntry(std::move(entry1));
// Second STACK CFI entry, with initial rules but no deltas.
- Module::StackFrameEntry* entry2 = new Module::StackFrameEntry();
+ auto entry2 = std::make_unique<Module::StackFrameEntry>();
entry2->address = 0x8064f3af5e067e38ULL;
entry2->size = 0x0de2a5ee55509407ULL;
entry2->initial_rules[".cfa"] = "I think that I shall never see";
entry2->initial_rules["stromboli"] = "a poem lovely as a tree";
entry2->initial_rules["cannoli"] = "a tree whose hungry mouth is prest";
- m.AddStackFrameEntry(entry2);
+ m.AddStackFrameEntry(std::move(entry2));
// Third STACK CFI entry, with initial rules and deltas.
- Module::StackFrameEntry* entry3 = new Module::StackFrameEntry();
+ auto entry3 = std::make_unique<Module::StackFrameEntry>();
entry3->address = 0x5e8d0db0a7075c6cULL;
entry3->size = 0x1c7edb12a7aea229ULL;
entry3->initial_rules[".cfa"] = "Whose woods are these";
@@ -338,7 +394,7 @@ TEST(Construct, AddFrames) {
"his house is in";
entry3->rule_changes[0x36682fad3763ffffULL][".cfa"] =
"I think I know";
- m.AddStackFrameEntry(entry3);
+ m.AddStackFrameEntry(std::move(entry3));
// Check that Write writes STACK CFI records properly.
m.Write(s, ALL_SYMBOL_DATA);
@@ -393,7 +449,7 @@ TEST(Construct, AddFrames) {
EXPECT_THAT(entries[2]->rule_changes, ContainerEq(entry3_changes));
}
-TEST(Construct, UniqueFiles) {
+TEST(Module, ConstructUniqueFiles) {
Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID);
Module::File* file1 = m.FindFile("foo");
Module::File* file2 = m.FindFile(string("bar"));
@@ -406,7 +462,7 @@ TEST(Construct, UniqueFiles) {
EXPECT_TRUE(m.FindExistingFile("baz") == NULL);
}
-TEST(Construct, DuplicateFunctions) {
+TEST(Module, ConstructDuplicateFunctions) {
stringstream s;
Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID);
@@ -415,7 +471,10 @@ TEST(Construct, DuplicateFunctions) {
Module::Function* function2 = generate_duplicate_function("_without_form");
m.AddFunction(function1);
- m.AddFunction(function2);
+ // If this succeeds, we'll have a double-free with the `delete` below. Avoid
+ // that.
+ ASSERT_FALSE(m.AddFunction(function2));
+ delete function2;
m.Write(s, ALL_SYMBOL_DATA);
string contents = s.str();
@@ -425,7 +484,7 @@ TEST(Construct, DuplicateFunctions) {
contents.c_str());
}
-TEST(Construct, FunctionsWithSameAddress) {
+TEST(Module, ConstructFunctionsWithSameAddress) {
stringstream s;
Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID);
@@ -446,20 +505,48 @@ TEST(Construct, FunctionsWithSameAddress) {
contents.c_str());
}
+// If multiple fields are enabled, only one function is included per address.
+// The entry will be tagged with `m` to show that there are multiple symbols
+// at that address.
+// TODO(lgrey): Remove the non-multiple versions of these tests and remove the
+// suffixes from the suffxed ones when removing `enable_multiple_field_`.
+TEST(Module, ConstructFunctionsWithSameAddressMultiple) {
+ stringstream s;
+ Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID, "", true);
+
+ // Two functions.
+ Module::Function* function1 = generate_duplicate_function("_without_form");
+ Module::Function* function2 = generate_duplicate_function("_and_void");
+
+ m.AddFunction(function1);
+ // If this succeeds, we'll have a double-free with the `delete` below. Avoid
+ // that.
+ ASSERT_FALSE(m.AddFunction(function2));
+ delete function2;
+
+ m.Write(s, ALL_SYMBOL_DATA);
+ string contents = s.str();
+ EXPECT_STREQ(
+ "MODULE os-name architecture id-string name with spaces\n"
+ "FUNC m d35402aac7a7ad5c 200b26e605f99071 f14ac4fed48c4a99"
+ " _without_form\n",
+ contents.c_str());
+}
+
// Externs should be written out as PUBLIC records, sorted by
// address.
-TEST(Construct, Externs) {
+TEST(Module, ConstructExterns) {
stringstream s;
Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID);
// Two externs.
- Module::Extern* extern1 = new Module::Extern(0xffff);
+ auto extern1 = std::make_unique<Module::Extern>(0xffff);
extern1->name = "_abc";
- Module::Extern* extern2 = new Module::Extern(0xaaaa);
+ auto extern2 = std::make_unique<Module::Extern>(0xaaaa);
extern2->name = "_xyz";
- m.AddExtern(extern1);
- m.AddExtern(extern2);
+ m.AddExtern(std::move(extern1));
+ m.AddExtern(std::move(extern2));
m.Write(s, ALL_SYMBOL_DATA);
string contents = s.str();
@@ -473,18 +560,18 @@ TEST(Construct, Externs) {
// Externs with the same address should only keep the first entry
// added.
-TEST(Construct, DuplicateExterns) {
+TEST(Module, ConstructDuplicateExterns) {
stringstream s;
Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID);
// Two externs.
- Module::Extern* extern1 = new Module::Extern(0xffff);
+ auto extern1 = std::make_unique<Module::Extern>(0xffff);
extern1->name = "_xyz";
- Module::Extern* extern2 = new Module::Extern(0xffff);
+ auto extern2 = std::make_unique<Module::Extern>(0xffff);
extern2->name = "_abc";
- m.AddExtern(extern1);
- m.AddExtern(extern2);
+ m.AddExtern(std::move(extern1));
+ m.AddExtern(std::move(extern2));
m.Write(s, ALL_SYMBOL_DATA);
string contents = s.str();
@@ -494,21 +581,44 @@ TEST(Construct, DuplicateExterns) {
"PUBLIC ffff 0 _xyz\n",
contents.c_str());
}
+// Externs with the same address have the `m` tag if the multiple field are
+// enabled.
+TEST(Module, ConstructDuplicateExternsMultiple) {
+ stringstream s;
+ Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID, "", true);
+
+ // Two externs.
+ auto extern1 = std::make_unique<Module::Extern>(0xffff);
+ extern1->name = "_xyz";
+ auto extern2 = std::make_unique<Module::Extern>(0xffff);
+ extern2->name = "_abc";
+
+ m.AddExtern(std::move(extern1));
+ m.AddExtern(std::move(extern2));
+
+ m.Write(s, ALL_SYMBOL_DATA);
+ string contents = s.str();
+
+ EXPECT_STREQ("MODULE " MODULE_OS " " MODULE_ARCH " " MODULE_ID " " MODULE_NAME
+ "\n"
+ "PUBLIC m ffff 0 _xyz\n",
+ contents.c_str());
+}
// If there exists an extern and a function at the same address, only write
// out the FUNC entry.
-TEST(Construct, FunctionsAndExternsWithSameAddress) {
+TEST(Module, ConstructFunctionsAndExternsWithSameAddress) {
stringstream s;
Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID);
// Two externs.
- Module::Extern* extern1 = new Module::Extern(0xabc0);
+ auto extern1 = std::make_unique<Module::Extern>(0xabc0);
extern1->name = "abc";
- Module::Extern* extern2 = new Module::Extern(0xfff0);
+ auto extern2 = std::make_unique<Module::Extern>(0xfff0);
extern2->name = "xyz";
- m.AddExtern(extern1);
- m.AddExtern(extern2);
+ m.AddExtern(std::move(extern1));
+ m.AddExtern(std::move(extern2));
Module::Function* function = new Module::Function("_xyz", 0xfff0);
Module::Range range(0xfff0, 0x10);
@@ -527,24 +637,55 @@ TEST(Construct, FunctionsAndExternsWithSameAddress) {
}
// If there exists an extern and a function at the same address, only write
+// out the FUNC entry, and mark it with `m` if the multiple field is enabled.
+TEST(Module, ConstructFunctionsAndExternsWithSameAddressMultiple) {
+ stringstream s;
+ Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID, "", true);
+
+ // Two externs.
+ auto extern1 = std::make_unique<Module::Extern>(0xabc0);
+ extern1->name = "abc";
+ auto extern2 = std::make_unique<Module::Extern>(0xfff0);
+ extern2->name = "xyz";
+
+ m.AddExtern(std::move(extern1));
+ m.AddExtern(std::move(extern2));
+
+ Module::Function* function = new Module::Function("_xyz", 0xfff0);
+ Module::Range range(0xfff0, 0x10);
+ function->ranges.push_back(range);
+ function->parameter_size = 0;
+ m.AddFunction(function);
+
+ m.Write(s, ALL_SYMBOL_DATA);
+ string contents = s.str();
+
+ EXPECT_STREQ("MODULE " MODULE_OS " " MODULE_ARCH " " MODULE_ID " " MODULE_NAME
+ "\n"
+ "FUNC m fff0 10 0 _xyz\n"
+ "PUBLIC abc0 0 abc\n",
+ contents.c_str());
+}
+
+// If there exists an extern and a function at the same address, only write
// out the FUNC entry. For ARM THUMB, the extern that comes from the ELF
// symbol section has bit 0 set.
-TEST(Construct, FunctionsAndThumbExternsWithSameAddress) {
+TEST(Module, ConstructFunctionsAndThumbExternsWithSameAddress) {
stringstream s;
Module m(MODULE_NAME, MODULE_OS, "arm", MODULE_ID);
// Two THUMB externs.
- Module::Extern* thumb_extern1 = new Module::Extern(0xabc1);
+ auto thumb_extern1 = std::make_unique<Module::Extern>(0xabc1);
thumb_extern1->name = "thumb_abc";
- Module::Extern* thumb_extern2 = new Module::Extern(0xfff1);
+ auto thumb_extern2 = std::make_unique<Module::Extern>(0xfff1);
thumb_extern2->name = "thumb_xyz";
- Module::Extern* arm_extern1 = new Module::Extern(0xcc00);
+ auto arm_extern1 = std::make_unique<Module::Extern>(0xcc00);
arm_extern1->name = "arm_func";
- m.AddExtern(thumb_extern1);
- m.AddExtern(thumb_extern2);
- m.AddExtern(arm_extern1);
+ m.AddExtern(std::move(thumb_extern1));
+ m.AddExtern(std::move(thumb_extern2));
+ m.AddExtern(std::move(arm_extern1));
// The corresponding function from the DWARF debug data have the actual
// address.
@@ -564,53 +705,3 @@ TEST(Construct, FunctionsAndThumbExternsWithSameAddress) {
"PUBLIC cc00 0 arm_func\n",
contents.c_str());
}
-
-TEST(Write, OutOfRangeAddresses) {
- stringstream s;
- Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID);
-
- // Specify an allowed address range, representing a PT_LOAD segment in a
- // module.
- vector<Module::Range> address_ranges = {
- Module::Range(0x2000ULL, 0x1000ULL),
- };
- m.SetAddressRanges(address_ranges);
-
- // Add three stack frames (one lower, one in, and one higher than the allowed
- // address range). Only the middle frame should be captured.
- Module::StackFrameEntry* entry1 = new Module::StackFrameEntry();
- entry1->address = 0x1000ULL;
- entry1->size = 0x100ULL;
- m.AddStackFrameEntry(entry1);
- Module::StackFrameEntry* entry2 = new Module::StackFrameEntry();
- entry2->address = 0x2000ULL;
- entry2->size = 0x100ULL;
- m.AddStackFrameEntry(entry2);
- Module::StackFrameEntry* entry3 = new Module::StackFrameEntry();
- entry3->address = 0x3000ULL;
- entry3->size = 0x100ULL;
- m.AddStackFrameEntry(entry3);
-
- // Add a function outside the allowed range.
- Module::File* file = m.FindFile("file_name.cc");
- Module::Function* function = new Module::Function(
- "function_name", 0x4000ULL);
- Module::Range range(0x4000ULL, 0x1000ULL);
- function->ranges.push_back(range);
- function->parameter_size = 0x100ULL;
- Module::Line line = { 0x4000ULL, 0x100ULL, file, 67519080 };
- function->lines.push_back(line);
- m.AddFunction(function);
-
- // Add an extern outside the allowed range.
- Module::Extern* extern1 = new Module::Extern(0x5000ULL);
- extern1->name = "_xyz";
- m.AddExtern(extern1);
-
- m.Write(s, ALL_SYMBOL_DATA);
-
- EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n"
- "STACK CFI INIT 2000 100 \n",
- s.str().c_str());
-
-}
diff --git a/src/common/path_helper.cc b/src/common/path_helper.cc
index 61a6e318..e51a1b68 100644
--- a/src/common/path_helper.cc
+++ b/src/common/path_helper.cc
@@ -1,5 +1,4 @@
-// Copyright 2017, Google Inc.
-// All rights reserved.
+// Copyright 2017 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/common/path_helper.h b/src/common/path_helper.h
index 2166ba01..0c026c25 100644
--- a/src/common/path_helper.h
+++ b/src/common/path_helper.h
@@ -1,5 +1,4 @@
-// Copyright 2017, Google Inc.
-// All rights reserved.
+// Copyright 2017 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/common/safe_math.h b/src/common/safe_math.h
new file mode 100644
index 00000000..3eab0d21
--- /dev/null
+++ b/src/common/safe_math.h
@@ -0,0 +1,81 @@
+// Copyright 2022 Google LLC
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google LLC nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// safe_math.h: Helpful math functions.
+#ifndef SAFE_MATH_H__
+#define SAFE_MATH_H__
+
+#include <utility>
+
+namespace google_breakpad {
+
+// Adds `a` and `b`, returning a pair of:
+// - The result after any truncation.
+// - Whether an overflow/underflow occurred.
+template <typename T>
+std::pair<T, bool> AddWithOverflowCheck(T a, T b) {
+#ifdef _WIN32
+ // Since C++11, unsigned overflow is well-defined; do everything unsigned,
+ // assuming 2's complement.
+ if (std::is_unsigned<T>::value) {
+ T result = a + b;
+ // Since we're adding two values >= 0, having a smaller value implies
+ // overflow.
+ bool overflow = result < a;
+ return {result, overflow};
+ }
+
+ using TUnsigned = typename std::make_unsigned<T>::type;
+ T result = TUnsigned(a) + TUnsigned(b);
+ bool overflow;
+ if ((a >= 0) == (b >= 0)) {
+ if (a >= 0) {
+ overflow = result < a;
+ } else {
+ overflow = result > a;
+ }
+ } else {
+ // If signs are different, it's impossible for overflow to happen.
+ overflow = false;
+ }
+ return {result, overflow};
+#else
+ T result;
+ bool overflow = __builtin_add_overflow(a, b, &result);
+ return {result, overflow};
+#endif
+}
+
+template <typename T>
+T AddIgnoringOverflow(T a, T b) {
+ return AddWithOverflowCheck(a, b).first;
+}
+
+} // namespace google_breakpad
+
+#endif // SAFE_MATH_H__
diff --git a/src/common/safe_math_unittest.cc b/src/common/safe_math_unittest.cc
new file mode 100644
index 00000000..1908155d
--- /dev/null
+++ b/src/common/safe_math_unittest.cc
@@ -0,0 +1,72 @@
+// Copyright 2022 Google LLC
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google LLC nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// safe_math_unittest.cc: Unit tests for SafeMath
+
+#include "safe_math.h"
+#include "breakpad_googletest_includes.h"
+
+namespace {
+
+using google_breakpad::AddIgnoringOverflow;
+using google_breakpad::AddWithOverflowCheck;
+
+TEST(SafeMath, AddOverflowWorksAsIntended) {
+ EXPECT_EQ(AddWithOverflowCheck<uint8_t>(0, 0),
+ std::make_pair<uint8_t>(0, false));
+ EXPECT_EQ(AddWithOverflowCheck<uint8_t>(0, 255),
+ std::make_pair<uint8_t>(255, false));
+ EXPECT_EQ(AddWithOverflowCheck<uint8_t>(1, 255),
+ std::make_pair<uint8_t>(0, true));
+
+ EXPECT_EQ(AddWithOverflowCheck<int8_t>(-128, 127),
+ std::make_pair<int8_t>(-1, false));
+ EXPECT_EQ(AddWithOverflowCheck<int8_t>(127, -128),
+ std::make_pair<int8_t>(-1, false));
+ EXPECT_EQ(AddWithOverflowCheck<int8_t>(1, -128),
+ std::make_pair<int8_t>(-127, false));
+ EXPECT_EQ(AddWithOverflowCheck<int8_t>(127, -1),
+ std::make_pair<int8_t>(126, false));
+
+ EXPECT_EQ(AddWithOverflowCheck<int8_t>(-128, -1),
+ std::make_pair<int8_t>(127, true));
+ EXPECT_EQ(AddWithOverflowCheck<int8_t>(-128, -128),
+ std::make_pair<int8_t>(0, true));
+ EXPECT_EQ(AddWithOverflowCheck<int8_t>(127, 1),
+ std::make_pair<int8_t>(-128, true));
+ EXPECT_EQ(AddWithOverflowCheck<int8_t>(127, 127),
+ std::make_pair<int8_t>(-2, true));
+}
+
+TEST(SafeMath, AddIgnoringOverflowWorksAsIntended) {
+ EXPECT_EQ(AddIgnoringOverflow<uint8_t>(0, 0), 0);
+ EXPECT_EQ(AddIgnoringOverflow<uint8_t>(0, 255), 255);
+ EXPECT_EQ(AddIgnoringOverflow<uint8_t>(1, 255), 0);
+}
+
+} // namespace
diff --git a/src/common/scoped_ptr.h b/src/common/scoped_ptr.h
index d137c186..d1110178 100644
--- a/src/common/scoped_ptr.h
+++ b/src/common/scoped_ptr.h
@@ -1,4 +1,4 @@
-// Copyright 2013 Google Inc. All Rights Reserved.
+// Copyright 2013 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -10,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/common/simple_string_dictionary.cc b/src/common/simple_string_dictionary.cc
index e0a74cee..68288897 100644
--- a/src/common/simple_string_dictionary.cc
+++ b/src/common/simple_string_dictionary.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2007, Google Inc.
-// All rights reserved.
+// Copyright 2007 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/common/simple_string_dictionary.h b/src/common/simple_string_dictionary.h
index 94849205..f7253a34 100644
--- a/src/common/simple_string_dictionary.h
+++ b/src/common/simple_string_dictionary.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2007, Google Inc.
-// All rights reserved.
+// Copyright 2007 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/common/simple_string_dictionary_unittest.cc b/src/common/simple_string_dictionary_unittest.cc
index e7b8fd76..4f3f1f5c 100644
--- a/src/common/simple_string_dictionary_unittest.cc
+++ b/src/common/simple_string_dictionary_unittest.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2008, Google Inc.
-// All rights reserved.
+// Copyright 2008 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/common/solaris/dump_symbols.cc b/src/common/solaris/dump_symbols.cc
index 168d0b28..8277fd66 100644
--- a/src/common/solaris/dump_symbols.cc
+++ b/src/common/solaris/dump_symbols.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2010 Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -97,7 +96,7 @@ struct LineInfo {
// Information of a function.
struct FuncInfo {
// Name of the function.
- const char *name;
+ const char* name;
// Offset from the base of the loading address.
GElf_Off rva_to_base;
// Virtual address of the function.
@@ -115,7 +114,7 @@ struct FuncInfo {
// Information of a source file.
struct SourceFileInfo {
// Name of the source file.
- const char *name;
+ const char* name;
// Starting address of the source file.
GElf_Addr addr;
// Id of the source file.
@@ -125,12 +124,12 @@ struct SourceFileInfo {
};
struct CompareString {
- bool operator()(const char *s1, const char *s2) const {
+ bool operator()(const char* s1, const char* s2) const {
return strcmp(s1, s2) < 0;
}
};
-typedef std::map<const char *, struct SymbolEntry *, CompareString> SymbolMap;
+typedef std::map<const char*, struct SymbolEntry*, CompareString> SymbolMap;
// Information of a symbol table.
// This is the root of all types of symbol.
@@ -141,16 +140,16 @@ struct SymbolInfo {
};
// Stab section name.
-const char *kStabName = ".stab";
+const char* kStabName = ".stab";
// Stab str section name.
-const char *kStabStrName = ".stabstr";
+const char* kStabStrName = ".stabstr";
// Symtab section name.
-const char *kSymtabName = ".symtab";
+const char* kSymtabName = ".symtab";
// Strtab section name.
-const char *kStrtabName = ".strtab";
+const char* kStrtabName = ".strtab";
// Default buffer lenght for demangle.
const int demangleLen = 20000;
@@ -160,11 +159,11 @@ uint64_t stringOffset = 0;
// Update the offset to the start of the string index of the next
// object module for every N_ENDM stabs.
-inline void RecalculateOffset(struct slist* cur_list, char *stabstr) {
+inline void RecalculateOffset(struct slist* cur_list, char* stabstr) {
while ((--cur_list)->n_strx == 0) ;
stringOffset += cur_list->n_strx;
- char *temp = stabstr + stringOffset;
+ char* temp = stabstr + stringOffset;
while (*temp != '\0') {
++stringOffset;
++temp;
@@ -174,10 +173,10 @@ inline void RecalculateOffset(struct slist* cur_list, char *stabstr) {
}
// Demangle using demangle library on Solaris.
-std::string Demangle(const char *mangled) {
+std::string Demangle(const char* mangled) {
int status = 0;
std::string str(mangled);
- char *demangled = (char *)malloc(demangleLen);
+ char* demangled = (char*)malloc(demangleLen);
if (!demangled) {
fprintf(stderr, "no enough memory.\n");
@@ -197,7 +196,7 @@ out:
return str;
}
-bool WriteFormat(int fd, const char *fmt, ...) {
+bool WriteFormat(int fd, const char* fmt, ...) {
va_list list;
char buffer[4096];
ssize_t expected, written;
@@ -209,27 +208,27 @@ bool WriteFormat(int fd, const char *fmt, ...) {
return expected == written;
}
-bool IsValidElf(const GElf_Ehdr *elf_header) {
+bool IsValidElf(const GElf_Ehdr* elf_header) {
return memcmp(elf_header, ELFMAG, SELFMAG) == 0;
}
-static bool FindSectionByName(Elf *elf, const char *name,
+static bool FindSectionByName(Elf* elf, const char* name,
int shstrndx,
- GElf_Shdr *shdr) {
+ GElf_Shdr* shdr) {
assert(name != NULL);
if (strlen(name) == 0)
return false;
- Elf_Scn *scn = NULL;
+ Elf_Scn* scn = NULL;
while ((scn = elf_nextscn(elf, scn)) != NULL) {
- if (gelf_getshdr(scn, shdr) == (GElf_Shdr *)0) {
+ if (gelf_getshdr(scn, shdr) == (GElf_Shdr*)0) {
fprintf(stderr, "failed to read section header: %s\n", elf_errmsg(0));
return false;
}
- const char *section_name = elf_strptr(elf, shstrndx, shdr->sh_name);
+ const char* section_name = elf_strptr(elf, shstrndx, shdr->sh_name);
if (!section_name) {
fprintf(stderr, "Section name error: %s\n", elf_errmsg(-1));
continue;
@@ -245,10 +244,10 @@ static bool FindSectionByName(Elf *elf, const char *name,
// The parameter size is used for FPO-optimized code, and
// this is all tied up with the debugging data for Windows x86.
// Set it to 0 on Solaris.
-int LoadStackParamSize(struct slist *list,
- struct slist *list_end,
- struct FuncInfo *func_info) {
- struct slist *cur_list = list;
+int LoadStackParamSize(struct slist* list,
+ struct slist* list_end,
+ struct FuncInfo* func_info) {
+ struct slist* cur_list = list;
int step = 1;
while (cur_list < list_end && cur_list->n_type == N_PSYM) {
++cur_list;
@@ -259,10 +258,10 @@ int LoadStackParamSize(struct slist *list,
return step;
}
-int LoadLineInfo(struct slist *list,
- struct slist *list_end,
- struct FuncInfo *func_info) {
- struct slist *cur_list = list;
+int LoadLineInfo(struct slist* list,
+ struct slist* list_end,
+ struct FuncInfo* func_info) {
+ struct slist* cur_list = list;
do {
// Skip non line information.
while (cur_list < list_end && cur_list->n_type != N_SLINE) {
@@ -288,12 +287,12 @@ int LoadLineInfo(struct slist *list,
return cur_list - list;
}
-int LoadFuncSymbols(struct slist *list,
- struct slist *list_end,
- char *stabstr,
+int LoadFuncSymbols(struct slist* list,
+ struct slist* list_end,
+ char* stabstr,
GElf_Word base,
- struct SourceFileInfo *source_file_info) {
- struct slist *cur_list = list;
+ struct SourceFileInfo* source_file_info) {
+ struct slist* cur_list = list;
assert(cur_list->n_type == N_SO);
++cur_list;
@@ -342,17 +341,17 @@ int LoadFuncSymbols(struct slist *list,
}
// Compute size and rva information based on symbols loaded from stab section.
-bool ComputeSizeAndRVA(struct SymbolInfo *symbols) {
- std::vector<struct SourceFileInfo> *sorted_files =
+bool ComputeSizeAndRVA(struct SymbolInfo* symbols) {
+ std::vector<struct SourceFileInfo>* sorted_files =
&(symbols->source_file_info);
- SymbolMap *symbol_entries = &(symbols->symbol_entries);
+ SymbolMap* symbol_entries = &(symbols->symbol_entries);
for (size_t i = 0; i < sorted_files->size(); ++i) {
- struct SourceFileInfo &source_file = (*sorted_files)[i];
- std::vector<struct FuncInfo> *sorted_functions = &(source_file.func_info);
+ struct SourceFileInfo& source_file = (*sorted_files)[i];
+ std::vector<struct FuncInfo>* sorted_functions = &(source_file.func_info);
int func_size = sorted_functions->size();
for (size_t j = 0; j < func_size; ++j) {
- struct FuncInfo &func_info = (*sorted_functions)[j];
+ struct FuncInfo& func_info = (*sorted_functions)[j];
int line_count = func_info.line_info.size();
// Discard the ending part of the name.
@@ -373,13 +372,13 @@ bool ComputeSizeAndRVA(struct SymbolInfo *symbols) {
// Compute function and line size.
for (size_t k = 0; k < line_count; ++k) {
- struct LineInfo &line_info = func_info.line_info[k];
+ struct LineInfo& line_info = func_info.line_info[k];
line_info.rva_to_base = line_info.rva_to_func + func_info.rva_to_base;
if (k == line_count - 1) {
line_info.size = func_info.size - line_info.rva_to_func;
} else {
- struct LineInfo &next_line = func_info.line_info[k + 1];
+ struct LineInfo& next_line = func_info.line_info[k + 1];
line_info.size = next_line.rva_to_func - line_info.rva_to_func;
}
} // for each line.
@@ -392,24 +391,23 @@ bool ComputeSizeAndRVA(struct SymbolInfo *symbols) {
return true;
}
-bool LoadAllSymbols(const GElf_Shdr *stab_section,
- const GElf_Shdr *stabstr_section,
+bool LoadAllSymbols(const GElf_Shdr* stab_section,
+ const GElf_Shdr* stabstr_section,
GElf_Word base,
- struct SymbolInfo *symbols) {
+ struct SymbolInfo* symbols) {
if (stab_section == NULL || stabstr_section == NULL)
return false;
- char *stabstr =
- reinterpret_cast<char *>(stabstr_section->sh_offset + base);
- struct slist *lists =
- reinterpret_cast<struct slist *>(stab_section->sh_offset + base);
+ char* stabstr = reinterpret_cast<char*>(stabstr_section->sh_offset + base);
+ struct slist* lists =
+ reinterpret_cast<struct slist*>(stab_section->sh_offset + base);
int nstab = stab_section->sh_size / sizeof(struct slist);
int source_id = 0;
// First pass, load all symbols from the object file.
for (int i = 0; i < nstab; ) {
int step = 1;
- struct slist *cur_list = lists + i;
+ struct slist* cur_list = lists + i;
if (cur_list->n_type == N_SO) {
// FUNC <address> <size> <param_stack_size> <function>
struct SourceFileInfo source_file_info;
@@ -431,12 +429,12 @@ bool LoadAllSymbols(const GElf_Shdr *stab_section,
return ComputeSizeAndRVA(symbols);
}
-bool LoadSymbols(Elf *elf, GElf_Ehdr *elf_header, struct SymbolInfo *symbols,
- void *obj_base) {
+bool LoadSymbols(Elf* elf, GElf_Ehdr* elf_header, struct SymbolInfo* symbols,
+ void* obj_base) {
GElf_Word base = reinterpret_cast<GElf_Word>(obj_base);
- const GElf_Shdr *sections =
- reinterpret_cast<GElf_Shdr *>(elf_header->e_shoff + base);
+ const GElf_Shdr* sections =
+ reinterpret_cast<GElf_Shdr*>(elf_header->e_shoff + base);
GElf_Shdr stab_section;
if (!FindSectionByName(elf, kStabName, elf_header->e_shstrndx,
&stab_section)) {
@@ -462,11 +460,11 @@ bool LoadSymbols(Elf *elf, GElf_Ehdr *elf_header, struct SymbolInfo *symbols,
return false;
}
- Elf_Sym *symbol = (Elf_Sym *)((char *)base + symtab_section.sh_offset);
+ Elf_Sym* symbol = (Elf_Sym*)((char*)base + symtab_section.sh_offset);
for (int i = 0; i < symtab_section.sh_size/symtab_section.sh_entsize; ++i) {
- struct SymbolEntry *symbol_entry =
- (struct SymbolEntry *)malloc(sizeof(struct SymbolEntry));
- const char *name = reinterpret_cast<char *>(
+ struct SymbolEntry* symbol_entry =
+ (struct SymbolEntry*)malloc(sizeof(struct SymbolEntry));
+ const char* name = reinterpret_cast<char*>(
strtab_section.sh_offset + (GElf_Word)base + symbol->st_name);
symbol_entry->offset = symbol->st_value;
symbol_entry->size = symbol->st_size;
@@ -479,8 +477,8 @@ bool LoadSymbols(Elf *elf, GElf_Ehdr *elf_header, struct SymbolInfo *symbols,
return LoadAllSymbols(&stab_section, &stabstr_section, base, symbols);
}
-bool WriteModuleInfo(int fd, GElf_Half arch, const std::string &obj_file) {
- const char *arch_name = NULL;
+bool WriteModuleInfo(int fd, GElf_Half arch, const std::string& obj_file) {
+ const char* arch_name = NULL;
if (arch == EM_386)
arch_name = "x86";
else if (arch == EM_X86_64)
@@ -493,7 +491,7 @@ bool WriteModuleInfo(int fd, GElf_Half arch, const std::string &obj_file) {
}
unsigned char identifier[16];
- google_breakpad::FileID file_id(obj_file.c_str());
+ google_breakpad::elf::FileID file_id(obj_file.c_str());
if (file_id.ElfFileIdentifier(identifier)) {
char identifier_str[40];
file_id.ConvertIdentifierToString(identifier,
@@ -508,10 +506,10 @@ bool WriteModuleInfo(int fd, GElf_Half arch, const std::string &obj_file) {
return false;
}
-bool WriteSourceFileInfo(int fd, const struct SymbolInfo &symbols) {
+bool WriteSourceFileInfo(int fd, const struct SymbolInfo& symbols) {
for (size_t i = 0; i < symbols.source_file_info.size(); ++i) {
if (symbols.source_file_info[i].source_id != -1) {
- const char *name = symbols.source_file_info[i].name;
+ const char* name = symbols.source_file_info[i].name;
if (!WriteFormat(fd, "FILE %d %s\n",
symbols.source_file_info[i].source_id, name))
return false;
@@ -521,7 +519,7 @@ bool WriteSourceFileInfo(int fd, const struct SymbolInfo &symbols) {
}
bool WriteOneFunction(int fd, int source_id,
- const struct FuncInfo &func_info){
+ const struct FuncInfo& func_info){
// Discard the ending part of the name.
std::string func_name(func_info.name);
std::string::size_type last_colon = func_name.find_last_of(':');
@@ -539,7 +537,7 @@ bool WriteOneFunction(int fd, int source_id,
func_info.stack_param_size,
func_name.c_str())) {
for (size_t i = 0; i < func_info.line_info.size(); ++i) {
- const struct LineInfo &line_info = func_info.line_info[i];
+ const struct LineInfo& line_info = func_info.line_info[i];
if (line_info.line_num == 0)
return true;
if (!WriteFormat(fd, "%llx %x %d %d\n",
@@ -554,11 +552,11 @@ bool WriteOneFunction(int fd, int source_id,
return false;
}
-bool WriteFunctionInfo(int fd, const struct SymbolInfo &symbols) {
+bool WriteFunctionInfo(int fd, const struct SymbolInfo& symbols) {
for (size_t i = 0; i < symbols.source_file_info.size(); ++i) {
- const struct SourceFileInfo &file_info = symbols.source_file_info[i];
+ const struct SourceFileInfo& file_info = symbols.source_file_info[i];
for (size_t j = 0; j < file_info.func_info.size(); ++j) {
- const struct FuncInfo &func_info = file_info.func_info[j];
+ const struct FuncInfo& func_info = file_info.func_info[j];
if (!WriteOneFunction(fd, file_info.source_id, func_info))
return false;
}
@@ -566,7 +564,7 @@ bool WriteFunctionInfo(int fd, const struct SymbolInfo &symbols) {
return true;
}
-bool DumpStabSymbols(int fd, const struct SymbolInfo &symbols) {
+bool DumpStabSymbols(int fd, const struct SymbolInfo& symbols) {
return WriteSourceFileInfo(fd, symbols) &&
WriteFunctionInfo(fd, symbols);
}
@@ -604,13 +602,13 @@ class FDWrapper {
//
class MmapWrapper {
public:
- MmapWrapper(void *mapped_address, size_t mapped_size) :
+ MmapWrapper(void* mapped_address, size_t mapped_size) :
base_(mapped_address), size_(mapped_size) {
}
~MmapWrapper() {
if (base_ != NULL) {
assert(size_ > 0);
- munmap((char *)base_, size_);
+ munmap((char*)base_, size_);
}
}
void release() {
@@ -619,7 +617,7 @@ class MmapWrapper {
}
private:
- void *base_;
+ void* base_;
size_t size_;
};
@@ -629,14 +627,14 @@ namespace google_breakpad {
class AutoElfEnder {
public:
- AutoElfEnder(Elf *elf) : elf_(elf) {}
+ AutoElfEnder(Elf* elf) : elf_(elf) {}
~AutoElfEnder() { if (elf_) elf_end(elf_); }
private:
- Elf *elf_;
+ Elf* elf_;
};
-bool DumpSymbols::WriteSymbolFile(const std::string &obj_file, int sym_fd) {
+bool DumpSymbols::WriteSymbolFile(const std::string& obj_file, int sym_fd) {
if (elf_version(EV_CURRENT) == EV_NONE) {
fprintf(stderr, "elf_version() failed: %s\n", elf_errmsg(0));
return false;
@@ -649,16 +647,16 @@ bool DumpSymbols::WriteSymbolFile(const std::string &obj_file, int sym_fd) {
struct stat st;
if (fstat(obj_fd, &st) != 0 && st.st_size <= 0)
return false;
- void *obj_base = mmap(NULL, st.st_size,
+ void* obj_base = mmap(NULL, st.st_size,
PROT_READ, MAP_PRIVATE, obj_fd, 0);
if (obj_base == MAP_FAILED)
return false;
MmapWrapper map_wrapper(obj_base, st.st_size);
GElf_Ehdr elf_header;
- Elf *elf = elf_begin(obj_fd, ELF_C_READ, NULL);
+ Elf* elf = elf_begin(obj_fd, ELF_C_READ, NULL);
AutoElfEnder elfEnder(elf);
- if (gelf_getehdr(elf, &elf_header) == (GElf_Ehdr *)NULL) {
+ if (gelf_getehdr(elf, &elf_header) == (GElf_Ehdr*)NULL) {
fprintf(stderr, "failed to read elf header: %s\n", elf_errmsg(-1));
return false;
}
diff --git a/src/common/solaris/dump_symbols.h b/src/common/solaris/dump_symbols.h
index 7f4baadc..9c986e4c 100644
--- a/src/common/solaris/dump_symbols.h
+++ b/src/common/solaris/dump_symbols.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2007, Google Inc.
-// All rights reserved.
+// Copyright 2007 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -40,7 +39,7 @@ namespace google_breakpad {
class DumpSymbols {
public:
- bool WriteSymbolFile(const std::string &obj_file,
+ bool WriteSymbolFile(const std::string& obj_file,
int sym_fd);
};
diff --git a/src/common/solaris/file_id.cc b/src/common/solaris/file_id.cc
index 643a1462..53d205b6 100644
--- a/src/common/solaris/file_id.cc
+++ b/src/common/solaris/file_id.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2007, Google Inc.
-// All rights reserved.
+// Copyright 2007 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -54,17 +53,17 @@ namespace google_breakpad {
class AutoElfEnder {
public:
- AutoElfEnder(Elf *elf) : elf_(elf) {}
+ AutoElfEnder(Elf* elf) : elf_(elf) {}
~AutoElfEnder() { if (elf_) elf_end(elf_); }
private:
- Elf *elf_;
+ Elf* elf_;
};
// Find the text section in elf object file.
// Return the section start address and the size.
-static bool FindElfTextSection(int fd, const void *elf_base,
- const void **text_start,
- int *text_size) {
+static bool FindElfTextSection(int fd, const void* elf_base,
+ const void** text_start,
+ int* text_size) {
assert(text_start);
assert(text_size);
@@ -78,10 +77,10 @@ static bool FindElfTextSection(int fd, const void *elf_base,
GElf_Ehdr elf_header;
lseek(fd, 0L, 0);
- Elf *elf = elf_begin(fd, ELF_C_READ, NULL);
+ Elf* elf = elf_begin(fd, ELF_C_READ, NULL);
AutoElfEnder elfEnder(elf);
- if (gelf_getehdr(elf, &elf_header) == (GElf_Ehdr *)NULL) {
+ if (gelf_getehdr(elf, &elf_header) == (GElf_Ehdr*)NULL) {
print_message2(2, "failed to read elf header: %s\n", elf_errmsg(-1));
return false;
}
@@ -95,18 +94,18 @@ static bool FindElfTextSection(int fd, const void *elf_base,
}
static const char kTextSectionName[] = ".text";
- const GElf_Shdr *text_section = NULL;
- Elf_Scn *scn = NULL;
+ const GElf_Shdr* text_section = NULL;
+ Elf_Scn* scn = NULL;
GElf_Shdr shdr;
while ((scn = elf_nextscn(elf, scn)) != NULL) {
- if (gelf_getshdr(scn, &shdr) == (GElf_Shdr *)0) {
+ if (gelf_getshdr(scn, &shdr) == (GElf_Shdr*)0) {
print_message2(2, "failed to read section header: %s\n", elf_errmsg(0));
return false;
}
if (shdr.sh_type == SHT_PROGBITS) {
- const char *section_name = elf_strptr(elf, elf_header.e_shstrndx,
+ const char* section_name = elf_strptr(elf, elf_header.e_shstrndx,
shdr.sh_name);
if (!section_name) {
print_message2(2, "Section name error: %s\n", elf_errmsg(-1));
@@ -120,7 +119,7 @@ static bool FindElfTextSection(int fd, const void *elf_base,
}
}
if (text_section != NULL && text_section->sh_size > 0) {
- *text_start = (char *)elf_base + text_section->sh_offset;
+ *text_start = (char*)elf_base + text_section->sh_offset;
*text_size = text_section->sh_size;
return true;
}
@@ -128,10 +127,6 @@ static bool FindElfTextSection(int fd, const void *elf_base,
return false;
}
-FileID::FileID(const char *path) {
- strcpy(path_, path);
-}
-
class AutoCloser {
public:
AutoCloser(int fd) : fd_(fd) {}
@@ -140,6 +135,12 @@ class AutoCloser {
int fd_;
};
+namespace elf {
+
+FileID::FileID(const char* path) {
+ strcpy(path_, path);
+}
+
bool FileID::ElfFileIdentifier(unsigned char identifier[16]) {
int fd = 0;
if ((fd = open(path_, O_RDONLY)) < 0)
@@ -150,29 +151,29 @@ bool FileID::ElfFileIdentifier(unsigned char identifier[16]) {
if (fstat(fd, &st) != 0 || st.st_size <= 0)
return false;
- void *base = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
+ void* base = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
if (base == MAP_FAILED)
return false;
bool success = false;
- const void *text_section = NULL;
+ const void* text_section = NULL;
int text_size = 0;
if (FindElfTextSection(fd, base, &text_section, &text_size)) {
MD5Context md5;
MD5Init(&md5);
- MD5Update(&md5, (const unsigned char *)text_section, text_size);
+ MD5Update(&md5, (const unsigned char*)text_section, text_size);
MD5Final(identifier, &md5);
success = true;
}
- munmap((char *)base, st.st_size);
+ munmap((char*)base, st.st_size);
return success;
}
// static
bool FileID::ConvertIdentifierToString(const unsigned char identifier[16],
- char *buffer, int buffer_length) {
+ char* buffer, int buffer_length) {
if (buffer_length < 34)
return false;
@@ -194,4 +195,5 @@ bool FileID::ConvertIdentifierToString(const unsigned char identifier[16],
return true;
}
+} // elf
} // namespace google_breakpad
diff --git a/src/common/solaris/file_id.h b/src/common/solaris/file_id.h
index 375e8575..2e41f0ae 100644
--- a/src/common/solaris/file_id.h
+++ b/src/common/solaris/file_id.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2007, Google Inc.
-// All rights reserved.
+// Copyright 2007 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -37,6 +36,7 @@
#include <limits.h>
namespace google_breakpad {
+namespace elf {
class FileID {
public:
@@ -61,6 +61,7 @@ class FileID {
char path_[PATH_MAX];
};
+} // elf
} // namespace google_breakpad
#endif // COMMON_SOLARIS_FILE_ID_H__
diff --git a/src/common/solaris/guid_creator.cc b/src/common/solaris/guid_creator.cc
index e9e6c6f5..4802f5a7 100644
--- a/src/common/solaris/guid_creator.cc
+++ b/src/common/solaris/guid_creator.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2007, Google Inc.
-// All rights reserved.
+// Copyright 2007 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -74,8 +73,8 @@ bool GUIDToString(const GUID *guid, char *buf, int buf_len) {
assert(buf_len > kGUIDStringLength);
int num = snprintf(buf, buf_len, kGUIDFormatString,
guid->data1, guid->data2, guid->data3,
- *reinterpret_cast<const uint32_t *>(&(guid->data4[0])),
- *reinterpret_cast<const uint32_t *>(&(guid->data4[4])));
+ *reinterpret_cast<const uint32_t*>(&(guid->data4[0])),
+ *reinterpret_cast<const uint32_t*>(&(guid->data4[4])));
if (num != kGUIDStringLength)
return false;
diff --git a/src/common/solaris/guid_creator.h b/src/common/solaris/guid_creator.h
index 4aee3a1c..91ed0041 100644
--- a/src/common/solaris/guid_creator.h
+++ b/src/common/solaris/guid_creator.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2007, Google Inc.
-// All rights reserved.
+// Copyright 2007 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/common/solaris/message_output.h b/src/common/solaris/message_output.h
index 3e3b1d46..9810dc57 100644
--- a/src/common/solaris/message_output.h
+++ b/src/common/solaris/message_output.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2007, Google Inc.
-// All rights reserved.
+// Copyright 2007 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/common/stabs_reader.cc b/src/common/stabs_reader.cc
index 6019fc7e..30118830 100644
--- a/src/common/stabs_reader.cc
+++ b/src/common/stabs_reader.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2010 Google Inc. All Rights Reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -10,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -45,7 +45,7 @@ using std::vector;
namespace google_breakpad {
-StabsReader::EntryIterator::EntryIterator(const ByteBuffer *buffer,
+StabsReader::EntryIterator::EntryIterator(const ByteBuffer* buffer,
bool big_endian, size_t value_size)
: value_size_(value_size), cursor_(buffer, big_endian) {
// Actually, we could handle weird sizes just fine, but they're
@@ -65,10 +65,10 @@ void StabsReader::EntryIterator::Fetch() {
entry_.at_end = !cursor_;
}
-StabsReader::StabsReader(const uint8_t *stab, size_t stab_size,
- const uint8_t *stabstr, size_t stabstr_size,
+StabsReader::StabsReader(const uint8_t* stab, size_t stab_size,
+ const uint8_t* stabstr, size_t stabstr_size,
bool big_endian, size_t value_size, bool unitized,
- StabsHandler *handler)
+ StabsHandler* handler)
: entries_(stab, stab_size),
strings_(stabstr, stabstr_size),
iterator_(&entries_, big_endian, value_size),
@@ -78,7 +78,7 @@ StabsReader::StabsReader(const uint8_t *stab, size_t stab_size,
next_cu_string_offset_(0),
current_source_file_(NULL) { }
-const char *StabsReader::SymbolString() {
+const char* StabsReader::SymbolString() {
ptrdiff_t offset = string_offset_ + iterator_->name_offset;
if (offset < 0 || (size_t) offset >= strings_.Size()) {
handler_->Warning("symbol %d: name offset outside the string section\n",
@@ -87,7 +87,7 @@ const char *StabsReader::SymbolString() {
// taken from the string section.
offset = 0;
}
- return reinterpret_cast<const char *>(strings_.start + offset);
+ return reinterpret_cast<const char*>(strings_.start + offset);
}
bool StabsReader::Process() {
@@ -134,9 +134,9 @@ bool StabsReader::ProcessCompilationUnit() {
// There may be an N_SO entry whose name ends with a slash,
// indicating the directory in which the compilation occurred.
// The build directory defaults to NULL.
- const char *build_directory = NULL;
+ const char* build_directory = NULL;
{
- const char *name = SymbolString();
+ const char* name = SymbolString();
if (name[0] && name[strlen(name) - 1] == '/') {
build_directory = name;
++iterator_;
@@ -148,7 +148,7 @@ bool StabsReader::ProcessCompilationUnit() {
{
if (iterator_->at_end || iterator_->type != N_SO)
return true;
- const char *name = SymbolString();
+ const char* name = SymbolString();
if (name[0] == '\0') {
// This seems to be a stray end-of-compilation-unit marker;
// consume it, but don't report the end, since we didn't see a
@@ -203,7 +203,7 @@ bool StabsReader::ProcessCompilationUnit() {
uint64_t ending_address = 0;
if (!iterator_->at_end) {
assert(iterator_->type == N_SO);
- const char *name = SymbolString();
+ const char* name = SymbolString();
if (name[0] == '\0') {
ending_address = iterator_->value;
++iterator_;
@@ -225,8 +225,8 @@ bool StabsReader::ProcessFunction() {
// The STABS string for an N_FUN entry is the name of the function,
// followed by a colon, followed by type information for the
// function. We want to pass the name alone to StartFunction.
- const char *stab_string = SymbolString();
- const char *name_end = strchr(stab_string, ':');
+ const char* stab_string = SymbolString();
+ const char* name_end = strchr(stab_string, ':');
if (! name_end)
name_end = stab_string + strlen(stab_string);
string name(stab_string, name_end - stab_string);
@@ -270,7 +270,7 @@ bool StabsReader::ProcessFunction() {
if (!iterator_->at_end) {
assert(iterator_->type == N_SO || iterator_->type == N_FUN);
if (iterator_->type == N_FUN) {
- const char *symbol_name = SymbolString();
+ const char* symbol_name = SymbolString();
if (symbol_name[0] == '\0') {
// An N_FUN entry with no name is a terminator for this function;
// its value is the function's size.
diff --git a/src/common/stabs_reader.h b/src/common/stabs_reader.h
index 98ee2dd5..3f5f0a8f 100644
--- a/src/common/stabs_reader.h
+++ b/src/common/stabs_reader.h
@@ -1,6 +1,6 @@
// -*- mode: c++ -*-
-// Copyright (c) 2010 Google Inc. All Rights Reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -12,7 +12,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -92,10 +92,10 @@ class StabsReader {
//
// Note that, in ELF, the .stabstr section should be found using the
// 'sh_link' field of the .stab section header, not by name.
- StabsReader(const uint8_t *stab, size_t stab_size,
- const uint8_t *stabstr, size_t stabstr_size,
+ StabsReader(const uint8_t* stab, size_t stab_size,
+ const uint8_t* stabstr, size_t stabstr_size,
bool big_endian, size_t value_size, bool unitized,
- StabsHandler *handler);
+ StabsHandler* handler);
// Process the STABS data, calling the handler's member functions to
// report what we find. While the handler functions return true,
@@ -149,17 +149,17 @@ class StabsReader {
// Mac, they are 32 or 64 bits long. Oddly, the section header's entry
// size for a Linux ELF .stab section varies according to the ELF class
// from 12 to 20 even as the actual entries remain unchanged.
- EntryIterator(const ByteBuffer *buffer, bool big_endian, size_t value_size);
+ EntryIterator(const ByteBuffer* buffer, bool big_endian, size_t value_size);
// Move to the next entry. This function's behavior is undefined if
// at_end() is true when it is called.
- EntryIterator &operator++() { Fetch(); entry_.index++; return *this; }
+ EntryIterator& operator++() { Fetch(); entry_.index++; return *this; }
// Dereferencing this iterator produces a reference to an Entry structure
// that holds the current entry's values. The entry is owned by this
// EntryIterator, and will be invalidated at the next call to operator++.
- const Entry &operator*() const { return entry_; }
- const Entry *operator->() const { return &entry_; }
+ const Entry& operator*() const { return entry_; }
+ const Entry* operator->() const { return &entry_; }
private:
// Read the STABS entry at cursor_, and set entry_ appropriately.
@@ -178,12 +178,12 @@ class StabsReader {
// A source line, saved to be reported later.
struct Line {
uint64_t address;
- const char *filename;
+ const char* filename;
int number;
};
// Return the name of the current symbol.
- const char *SymbolString();
+ const char* SymbolString();
// Process a compilation unit starting at symbol_. Return true
// to continue processing, or false to abort.
@@ -210,7 +210,7 @@ class StabsReader {
// StabsReader::StabsReader.
bool unitized_;
- StabsHandler *handler_;
+ StabsHandler* handler_;
// The offset of the current compilation unit's strings within stabstr_.
size_t string_offset_;
@@ -220,7 +220,7 @@ class StabsReader {
size_t next_cu_string_offset_;
// The current source file name.
- const char *current_source_file_;
+ const char* current_source_file_;
// Mac OS X STABS place SLINE records before functions; we accumulate a
// vector of these until we see the FUN record, and then report them
@@ -261,7 +261,7 @@ class StabsHandler {
// FILENAME values are different addresses, they represent different
// file names.
//
- // Thus, it's safe to use (say) std::map<char *, ...>, which does
+ // Thus, it's safe to use (say) std::map<char*, ...>, which does
// string address comparisons, not string content comparisons.
// Since all the strings are in same array of characters --- the
// .stabstr section --- comparing their addresses produces
@@ -271,8 +271,8 @@ class StabsHandler {
// named FILENAME, and whose base address is ADDRESS. If
// BUILD_DIRECTORY is non-NULL, it is the name of the build
// directory in which the compilation occurred.
- virtual bool StartCompilationUnit(const char *filename, uint64_t address,
- const char *build_directory) {
+ virtual bool StartCompilationUnit(const char* filename, uint64_t address,
+ const char* build_directory) {
return true;
}
@@ -292,7 +292,7 @@ class StabsHandler {
// StartFunction is the function name alone.
//
// In languages that use name mangling, like C++, NAME is mangled.
- virtual bool StartFunction(const string &name, uint64_t address) {
+ virtual bool StartFunction(const string& name, uint64_t address) {
return true;
}
@@ -305,19 +305,19 @@ class StabsHandler {
// Report that the code at ADDRESS is attributable to line NUMBER of
// the source file named FILENAME. The caller must infer the ending
// address of the line.
- virtual bool Line(uint64_t address, const char *filename, int number) {
+ virtual bool Line(uint64_t address, const char* filename, int number) {
return true;
}
// Report that an exported function NAME is present at ADDRESS.
// The size of the function is unknown.
- virtual bool Extern(const string &name, uint64_t address) {
+ virtual bool Extern(const string& name, uint64_t address) {
return true;
}
// Report a warning. FORMAT is a printf-like format string,
// specifying how to format the subsequent arguments.
- virtual void Warning(const char *format, ...) = 0;
+ virtual void Warning(const char* format, ...) = 0;
};
} // namespace google_breakpad
diff --git a/src/common/stabs_reader_unittest.cc b/src/common/stabs_reader_unittest.cc
index a84da1c4..79888815 100644
--- a/src/common/stabs_reader_unittest.cc
+++ b/src/common/stabs_reader_unittest.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2010 Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -75,7 +74,7 @@ class StringAssembler: public Section {
// Add the string S to this StringAssembler, and return the string's
// offset within this compilation unit's strings. If S has been added
// already, this returns the offset of its first instance.
- size_t Add(const string &s) {
+ size_t Add(const string& s) {
map<string, size_t>::iterator it = added_.find(s);
if (it != added_.end())
return it->second;
@@ -127,7 +126,7 @@ class StringAssembler: public Section {
class StabsAssembler: public Section {
public:
// Create a StabsAssembler that uses StringAssembler for its strings.
- StabsAssembler(StringAssembler *string_assembler)
+ StabsAssembler(StringAssembler* string_assembler)
: Section(string_assembler->endianness()),
string_assembler_(string_assembler),
value_size_(0),
@@ -137,7 +136,7 @@ class StabsAssembler: public Section {
// Accessor and setter for value_size_.
size_t value_size() const { return value_size_; }
- StabsAssembler &set_value_size(size_t value_size) {
+ StabsAssembler& set_value_size(size_t value_size) {
value_size_ = value_size;
return *this;
}
@@ -147,7 +146,7 @@ class StabsAssembler: public Section {
// its compilation unit's portion of the .stabstr section; this can be a
// value generated by a StringAssembler. Return a reference to this
// StabsAssembler.
- StabsAssembler &Stab(uint8_t type, uint8_t other, Label descriptor,
+ StabsAssembler& Stab(uint8_t type, uint8_t other, Label descriptor,
Label value, Label name) {
D32(name);
D8(type);
@@ -159,15 +158,15 @@ class StabsAssembler: public Section {
}
// As above, but automatically add NAME to our StringAssembler.
- StabsAssembler &Stab(uint8_t type, uint8_t other, Label descriptor,
- Label value, const string &name) {
+ StabsAssembler& Stab(uint8_t type, uint8_t other, Label descriptor,
+ Label value, const string& name) {
return Stab(type, other, descriptor, value, string_assembler_->Add(name));
}
// Start a compilation unit named NAME, with an N_UNDF symbol to start
// it, and its own portion of the string section. Return a reference to
// this StabsAssembler.
- StabsAssembler &StartCU(const string &name) {
+ StabsAssembler& StartCU(const string& name) {
assert(!cu_header_);
cu_header_ = new CUHeader;
string_assembler_->StartCU();
@@ -180,7 +179,7 @@ class StabsAssembler: public Section {
// Close off the current compilation unit. Return a reference to this
// StabsAssembler.
- StabsAssembler &EndCU() {
+ StabsAssembler& EndCU() {
assert(cu_header_);
cu_header_->final_entry_count = entry_count_;
cu_header_->final_string_size = string_assembler_->EndCU();
@@ -201,7 +200,7 @@ class StabsAssembler: public Section {
};
// The strings for our STABS entries.
- StringAssembler *string_assembler_;
+ StringAssembler* string_assembler_;
// The size of the 'value' field of stabs entries in this section.
size_t value_size_;
@@ -211,20 +210,20 @@ class StabsAssembler: public Section {
// Header labels for this compilation unit, if we've started one but not
// finished it.
- CUHeader *cu_header_;
+ CUHeader* cu_header_;
};
class MockStabsReaderHandler: public StabsHandler {
public:
MOCK_METHOD3(StartCompilationUnit,
- bool(const char *, uint64_t, const char *));
+ bool(const char*, uint64_t, const char*));
MOCK_METHOD1(EndCompilationUnit, bool(uint64_t));
- MOCK_METHOD2(StartFunction, bool(const string &, uint64_t));
+ MOCK_METHOD2(StartFunction, bool(const string&, uint64_t));
MOCK_METHOD1(EndFunction, bool(uint64_t));
- MOCK_METHOD3(Line, bool(uint64_t, const char *, int));
- MOCK_METHOD2(Extern, bool(const string &, uint64_t));
- void Warning(const char *format, ...) { MockWarning(format); }
- MOCK_METHOD1(MockWarning, void(const char *));
+ MOCK_METHOD3(Line, bool(uint64_t, const char*, int));
+ MOCK_METHOD2(Extern, bool(const string&, uint64_t));
+ void Warning(const char* format, ...) { MockWarning(format); }
+ MOCK_METHOD1(MockWarning, void(const char*));
};
struct StabsFixture {
@@ -243,9 +242,9 @@ struct StabsFixture {
// Run the parser on the test input, passing whatever we find to HANDLER.
StabsReader reader(
- reinterpret_cast<const uint8_t *>(stabs_contents.data()),
+ reinterpret_cast<const uint8_t*>(stabs_contents.data()),
stabs_contents.size(),
- reinterpret_cast<const uint8_t *>(stabstr_contents.data()),
+ reinterpret_cast<const uint8_t*>(stabstr_contents.data()),
stabstr_contents.size(),
stabs.endianness() == kBigEndian, stabs.value_size(), unitized,
&mock_handler);
diff --git a/src/common/stabs_to_module.cc b/src/common/stabs_to_module.cc
index 049a6cc6..3d026c22 100644
--- a/src/common/stabs_to_module.cc
+++ b/src/common/stabs_to_module.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2010 Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -37,6 +36,8 @@
#include <stdio.h>
#include <algorithm>
+#include <memory>
+#include <utility>
#include "common/stabs_to_module.h"
#include "common/using_std_string.h"
@@ -45,7 +46,7 @@ namespace google_breakpad {
// Demangle using abi call.
// Older GCC may not support it.
-static string Demangle(const string &mangled) {
+static string Demangle(const string& mangled) {
int status = 0;
char *demangled = abi::__cxa_demangle(mangled.c_str(), NULL, NULL, &status);
if (status == 0 && demangled != NULL) {
@@ -58,7 +59,7 @@ static string Demangle(const string &mangled) {
StabsToModule::~StabsToModule() {
// Free any functions we've accumulated but not added to the module.
- for (vector<Module::Function *>::const_iterator func_it = functions_.begin();
+ for (vector<Module::Function*>::const_iterator func_it = functions_.begin();
func_it != functions_.end(); func_it++)
delete *func_it;
// Free any function that we're currently within.
@@ -87,10 +88,11 @@ bool StabsToModule::EndCompilationUnit(uint64_t address) {
return true;
}
-bool StabsToModule::StartFunction(const string &name,
+bool StabsToModule::StartFunction(const string& name,
uint64_t address) {
assert(!current_function_);
- Module::Function *f = new Module::Function(Demangle(name), address);
+ Module::Function* f =
+ new Module::Function(module_->AddStringToPool(Demangle(name)), address);
Module::Range r(address, 0); // We compute this in StabsToModule::Finalize().
f->ranges.push_back(r);
f->parameter_size = 0; // We don't provide this information.
@@ -131,8 +133,8 @@ bool StabsToModule::Line(uint64_t address, const char *name, int number) {
return true;
}
-bool StabsToModule::Extern(const string &name, uint64_t address) {
- Module::Extern *ext = new Module::Extern(address);
+bool StabsToModule::Extern(const string& name, uint64_t address) {
+ auto ext = std::make_unique<Module::Extern>(address);
// Older libstdc++ demangle implementations can crash on unexpected
// input, so be careful about what gets passed in.
if (name.compare(0, 3, "__Z") == 0) {
@@ -142,7 +144,7 @@ bool StabsToModule::Extern(const string &name, uint64_t address) {
} else {
ext->name = name;
}
- module_->AddExtern(ext);
+ module_->AddExtern(std::move(ext));
return true;
}
@@ -160,7 +162,7 @@ void StabsToModule::Finalize() {
sort(functions_.begin(), functions_.end(),
Module::Function::CompareByAddress);
- for (vector<Module::Function *>::const_iterator func_it = functions_.begin();
+ for (vector<Module::Function*>::const_iterator func_it = functions_.begin();
func_it != functions_.end();
func_it++) {
Module::Function *f = *func_it;
@@ -191,8 +193,11 @@ void StabsToModule::Finalize() {
}
}
// Now that everything has a size, add our functions to the module, and
- // dispose of our private list.
- module_->AddFunctions(functions_.begin(), functions_.end());
+ // dispose of our private list. Delete the functions that we fail to add, so
+ // they aren't leaked.
+ for (Module::Function* func: functions_)
+ if (!module_->AddFunction(func))
+ delete func;
functions_.clear();
}
diff --git a/src/common/stabs_to_module.h b/src/common/stabs_to_module.h
index 5e04fa79..99c61b0c 100644
--- a/src/common/stabs_to_module.h
+++ b/src/common/stabs_to_module.h
@@ -1,7 +1,6 @@
// -*- mode: C++ -*-
-// Copyright (c) 2010 Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -13,7 +12,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -76,10 +75,10 @@ class StabsToModule: public google_breakpad::StabsHandler {
bool StartCompilationUnit(const char *name, uint64_t address,
const char *build_directory);
bool EndCompilationUnit(uint64_t address);
- bool StartFunction(const string &name, uint64_t address);
+ bool StartFunction(const string& name, uint64_t address);
bool EndFunction(uint64_t address);
bool Line(uint64_t address, const char *name, int number);
- bool Extern(const string &name, uint64_t address);
+ bool Extern(const string& name, uint64_t address);
void Warning(const char *format, ...);
// Do any final processing necessary to make module_ contain all the
@@ -107,7 +106,7 @@ class StabsToModule: public google_breakpad::StabsHandler {
// We could just stick them in module_ from the outset, but if
// module_ already contains data gathered from other debugging
// formats, that would complicate the size computation.
- vector<Module::Function *> functions_;
+ vector<Module::Function*> functions_;
// Boundary addresses. STABS doesn't necessarily supply sizes for
// functions and lines, so we need to compute them ourselves by
diff --git a/src/common/stabs_to_module_unittest.cc b/src/common/stabs_to_module_unittest.cc
index aae00476..95bdb261 100644
--- a/src/common/stabs_to_module_unittest.cc
+++ b/src/common/stabs_to_module_unittest.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2010 Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -58,11 +57,11 @@ TEST(StabsToModule, SimpleCU) {
Module::File *file = m.FindExistingFile("source-file-name");
ASSERT_TRUE(file != NULL);
- vector<Module::Function *> functions;
+ vector<Module::Function*> functions;
m.GetFunctions(&functions, functions.end());
ASSERT_EQ((size_t) 1, functions.size());
Module::Function *function = functions[0];
- EXPECT_STREQ("function", function->name.c_str());
+ EXPECT_STREQ("function", function->name.str().c_str());
EXPECT_EQ(0xfde4abbed390c394LL, function->address);
EXPECT_EQ(0x10U, function->ranges[0].size);
EXPECT_EQ(0U, function->parameter_size);
@@ -88,7 +87,7 @@ TEST(StabsToModule, Externs) {
h.Finalize();
// Now check to see what has been added to the Module.
- vector<Module::Extern *> externs;
+ vector<Module::Extern*> externs;
m.GetExterns(&externs, externs.end());
ASSERT_EQ((size_t) 3, externs.size());
Module::Extern *extern1 = externs[0];
@@ -124,7 +123,7 @@ TEST(StabsToModule, DuplicateFunctionNames) {
Module::File *file = m.FindExistingFile("compilation-unit");
ASSERT_TRUE(file != NULL);
- vector<Module::Function *> functions;
+ vector<Module::Function*> functions;
m.GetFunctions(&functions, functions.end());
ASSERT_EQ(1U, functions.size());
@@ -159,12 +158,12 @@ TEST(InferSizes, LineSize) {
Module::File *file2 = m.FindExistingFile("source-file-name-2");
ASSERT_TRUE(file2 != NULL);
- vector<Module::Function *> functions;
+ vector<Module::Function*> functions;
m.GetFunctions(&functions, functions.end());
ASSERT_EQ((size_t) 1, functions.size());
Module::Function *function = functions[0];
- EXPECT_STREQ("function", function->name.c_str());
+ EXPECT_STREQ("function", function->name.str().c_str());
EXPECT_EQ(0xb4513962eff94e92LL, function->address);
EXPECT_EQ(0x1000100000000ULL, function->ranges[0].size); // inferred from CU end
EXPECT_EQ(0U, function->parameter_size);
@@ -204,17 +203,16 @@ TEST(FunctionNames, Mangled) {
Module::File *file = m.FindExistingFile("compilation-unit");
ASSERT_TRUE(file != NULL);
- vector<Module::Function *> functions;
+ vector<Module::Function*> functions;
m.GetFunctions(&functions, functions.end());
ASSERT_EQ(1U, functions.size());
Module::Function *function = functions[0];
// This is GCC-specific, but we shouldn't be seeing STABS data anywhere
// but Linux.
- EXPECT_STREQ("std::vector<unsigned long long, "
- "std::allocator<unsigned long long> >::"
- "push_back(unsigned long long const&)",
- function->name.c_str());
+ EXPECT_THAT(function->name.str(), ::testing::ContainsRegex(
+ "std::vector<unsigned long long, std::allocator<unsigned long long>\\s?>::"
+ "push_back\\(unsigned long long const&\\)"));
EXPECT_EQ(0xf2cfda63cef7f46dLL, function->address);
EXPECT_LT(0U, function->ranges[0].size); // should have used dummy size
EXPECT_EQ(0U, function->parameter_size);
diff --git a/src/common/stdio_wrapper.h b/src/common/stdio_wrapper.h
index a3dd50aa..32093bd4 100644
--- a/src/common/stdio_wrapper.h
+++ b/src/common/stdio_wrapper.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2016, Google Inc.
-// All rights reserved.
+// Copyright 2016 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/common/string_conversion.cc b/src/common/string_conversion.cc
index 11d60a36..213d6ed7 100644
--- a/src/common/string_conversion.cc
+++ b/src/common/string_conversion.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2006, Google Inc.
-// All rights reserved.
+// Copyright 2006 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -38,15 +37,15 @@ namespace google_breakpad {
using std::vector;
-void UTF8ToUTF16(const char *in, vector<uint16_t> *out) {
+void UTF8ToUTF16(const char* in, vector<uint16_t>* out) {
size_t source_length = strlen(in);
- const UTF8 *source_ptr = reinterpret_cast<const UTF8 *>(in);
- const UTF8 *source_end_ptr = source_ptr + source_length;
+ const UTF8* source_ptr = reinterpret_cast<const UTF8*>(in);
+ const UTF8* source_end_ptr = source_ptr + source_length;
// Erase the contents and zero fill to the expected size
out->clear();
out->insert(out->begin(), source_length, 0);
- uint16_t *target_ptr = &(*out)[0];
- uint16_t *target_end_ptr = target_ptr + out->capacity();
+ uint16_t* target_ptr = &(*out)[0];
+ uint16_t* target_end_ptr = target_ptr + out->capacity();
ConversionResult result = ConvertUTF8toUTF16(&source_ptr, source_end_ptr,
&target_ptr, target_end_ptr,
strictConversion);
@@ -55,11 +54,11 @@ void UTF8ToUTF16(const char *in, vector<uint16_t> *out) {
out->resize(result == conversionOK ? target_ptr - &(*out)[0] + 1: 0);
}
-int UTF8ToUTF16Char(const char *in, int in_length, uint16_t out[2]) {
- const UTF8 *source_ptr = reinterpret_cast<const UTF8 *>(in);
- const UTF8 *source_end_ptr = source_ptr + 1;
- uint16_t *target_ptr = out;
- uint16_t *target_end_ptr = target_ptr + 2;
+int UTF8ToUTF16Char(const char* in, int in_length, uint16_t out[2]) {
+ const UTF8* source_ptr = reinterpret_cast<const UTF8*>(in);
+ const UTF8* source_end_ptr = source_ptr + 1;
+ uint16_t* target_ptr = out;
+ uint16_t* target_end_ptr = target_ptr + 2;
out[0] = out[1] = 0;
// Process one character at a time
@@ -69,28 +68,28 @@ int UTF8ToUTF16Char(const char *in, int in_length, uint16_t out[2]) {
strictConversion);
if (result == conversionOK)
- return static_cast<int>(source_ptr - reinterpret_cast<const UTF8 *>(in));
+ return static_cast<int>(source_ptr - reinterpret_cast<const UTF8*>(in));
// Add another character to the input stream and try again
- source_ptr = reinterpret_cast<const UTF8 *>(in);
+ source_ptr = reinterpret_cast<const UTF8*>(in);
++source_end_ptr;
- if (source_end_ptr > reinterpret_cast<const UTF8 *>(in) + in_length)
+ if (source_end_ptr > reinterpret_cast<const UTF8*>(in) + in_length)
break;
}
return 0;
}
-void UTF32ToUTF16(const wchar_t *in, vector<uint16_t> *out) {
+void UTF32ToUTF16(const wchar_t* in, vector<uint16_t>* out) {
size_t source_length = wcslen(in);
- const UTF32 *source_ptr = reinterpret_cast<const UTF32 *>(in);
- const UTF32 *source_end_ptr = source_ptr + source_length;
+ const UTF32* source_ptr = reinterpret_cast<const UTF32*>(in);
+ const UTF32* source_end_ptr = source_ptr + source_length;
// Erase the contents and zero fill to the expected size
out->clear();
out->insert(out->begin(), source_length, 0);
- uint16_t *target_ptr = &(*out)[0];
- uint16_t *target_end_ptr = target_ptr + out->capacity();
+ uint16_t* target_ptr = &(*out)[0];
+ uint16_t* target_end_ptr = target_ptr + out->capacity();
ConversionResult result = ConvertUTF32toUTF16(&source_ptr, source_end_ptr,
&target_ptr, target_end_ptr,
strictConversion);
@@ -100,10 +99,10 @@ void UTF32ToUTF16(const wchar_t *in, vector<uint16_t> *out) {
}
void UTF32ToUTF16Char(wchar_t in, uint16_t out[2]) {
- const UTF32 *source_ptr = reinterpret_cast<const UTF32 *>(&in);
- const UTF32 *source_end_ptr = source_ptr + 1;
- uint16_t *target_ptr = out;
- uint16_t *target_end_ptr = target_ptr + 2;
+ const UTF32* source_ptr = reinterpret_cast<const UTF32*>(&in);
+ const UTF32* source_end_ptr = source_ptr + 1;
+ uint16_t* target_ptr = out;
+ uint16_t* target_end_ptr = target_ptr + 2;
out[0] = out[1] = 0;
ConversionResult result = ConvertUTF32toUTF16(&source_ptr, source_end_ptr,
&target_ptr, target_end_ptr,
@@ -118,15 +117,15 @@ static inline uint16_t Swap(uint16_t value) {
return (value >> 8) | static_cast<uint16_t>(value << 8);
}
-string UTF16ToUTF8(const vector<uint16_t> &in, bool swap) {
- const UTF16 *source_ptr = &in[0];
+string UTF16ToUTF8(const vector<uint16_t>& in, bool swap) {
+ const UTF16* source_ptr = &in[0];
scoped_array<uint16_t> source_buffer;
// If we're to swap, we need to make a local copy and swap each byte pair
if (swap) {
int idx = 0;
source_buffer.reset(new uint16_t[in.size()]);
- UTF16 *source_buffer_ptr = source_buffer.get();
+ UTF16* source_buffer_ptr = source_buffer.get();
for (vector<uint16_t>::const_iterator it = in.begin();
it != in.end(); ++it, ++idx)
source_buffer_ptr[idx] = Swap(*it);
@@ -135,17 +134,17 @@ string UTF16ToUTF8(const vector<uint16_t> &in, bool swap) {
}
// The maximum expansion would be 4x the size of the input string.
- const UTF16 *source_end_ptr = source_ptr + in.size();
+ const UTF16* source_end_ptr = source_ptr + in.size();
size_t target_capacity = in.size() * 4;
scoped_array<UTF8> target_buffer(new UTF8[target_capacity]);
- UTF8 *target_ptr = target_buffer.get();
- UTF8 *target_end_ptr = target_ptr + target_capacity;
+ UTF8* target_ptr = target_buffer.get();
+ UTF8* target_end_ptr = target_ptr + target_capacity;
ConversionResult result = ConvertUTF16toUTF8(&source_ptr, source_end_ptr,
&target_ptr, target_end_ptr,
strictConversion);
if (result == conversionOK) {
- const char *targetPtr = reinterpret_cast<const char *>(target_buffer.get());
+ const char* targetPtr = reinterpret_cast<const char*>(target_buffer.get());
return targetPtr;
}
diff --git a/src/common/string_conversion.h b/src/common/string_conversion.h
index b9ba96a2..c5f5a357 100644
--- a/src/common/string_conversion.h
+++ b/src/common/string_conversion.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2006, Google Inc.
-// All rights reserved.
+// Copyright 2006 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -44,24 +43,24 @@ using std::vector;
// Convert |in| to UTF-16 into |out|. Use platform byte ordering. If the
// conversion failed, |out| will be zero length.
-void UTF8ToUTF16(const char *in, vector<uint16_t> *out);
+void UTF8ToUTF16(const char* in, vector<uint16_t>* out);
// Convert at least one character (up to a maximum of |in_length|) from |in|
// to UTF-16 into |out|. Return the number of characters consumed from |in|.
// Any unused characters in |out| will be initialized to 0. No memory will
// be allocated by this routine.
-int UTF8ToUTF16Char(const char *in, int in_length, uint16_t out[2]);
+int UTF8ToUTF16Char(const char* in, int in_length, uint16_t out[2]);
// Convert |in| to UTF-16 into |out|. Use platform byte ordering. If the
// conversion failed, |out| will be zero length.
-void UTF32ToUTF16(const wchar_t *in, vector<uint16_t> *out);
+void UTF32ToUTF16(const wchar_t* in, vector<uint16_t>* out);
// Convert |in| to UTF-16 into |out|. Any unused characters in |out| will be
// initialized to 0. No memory will be allocated by this routine.
void UTF32ToUTF16Char(wchar_t in, uint16_t out[2]);
// Convert |in| to UTF-8. If |swap| is true, swap bytes before converting.
-string UTF16ToUTF8(const vector<uint16_t> &in, bool swap);
+string UTF16ToUTF8(const vector<uint16_t>& in, bool swap);
} // namespace google_breakpad
diff --git a/src/common/string_conversion_unittest.cc b/src/common/string_conversion_unittest.cc
index e9f9b55d..2e64a957 100644
--- a/src/common/string_conversion_unittest.cc
+++ b/src/common/string_conversion_unittest.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2019, Google Inc.
-// All rights reserved.
+// Copyright 2019 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/common/string_view.h b/src/common/string_view.h
new file mode 100644
index 00000000..a8e15922
--- /dev/null
+++ b/src/common/string_view.h
@@ -0,0 +1,113 @@
+// Copyright 2021 Google LLC
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google LLC nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef COMMON_STRING_VIEW_H__
+#define COMMON_STRING_VIEW_H__
+
+#include <cassert>
+#include <cstring>
+#include <ostream>
+#include "common/using_std_string.h"
+
+namespace google_breakpad {
+
+// A StringView is a string reference to a string object, but not own the
+// string object. It's a compatibile layer until we can use std::string_view in
+// C++17.
+class StringView {
+ private:
+ // The start of the string, in an external buffer. It doesn't have to be
+ // null-terminated.
+ const char* data_ = "";
+
+ size_t length_ = 0;
+
+ public:
+ // Construct an empty StringView.
+ StringView() = default;
+
+ // Disallow construct StringView from nullptr.
+ StringView(std::nullptr_t) = delete;
+
+ // Construct a StringView from a cstring.
+ StringView(const char* str) : data_(str) {
+ assert(str);
+ length_ = strlen(str);
+ }
+
+ // Construct a StringView from a cstring with fixed length.
+ StringView(const char* str, size_t length) : data_(str), length_(length) {
+ assert(str);
+ }
+
+ // Construct a StringView from an std::string.
+ StringView(const string& str) : data_(str.data()), length_(str.length()) {}
+
+ string str() const { return string(data_, length_); }
+
+ const char* data() const { return data_; }
+
+ bool empty() const { return length_ == 0; }
+
+ size_t size() const { return length_; }
+
+ int compare(StringView rhs) const {
+ size_t min_len = std::min(size(), rhs.size());
+ int res = memcmp(data_, rhs.data(), min_len);
+ if (res != 0)
+ return res;
+ if (size() == rhs.size())
+ return 0;
+ return size() < rhs.size() ? -1 : 1;
+ }
+};
+
+inline bool operator==(StringView lhs, StringView rhs) {
+ return lhs.compare(rhs) == 0;
+}
+
+inline bool operator!=(StringView lhs, StringView rhs) {
+ return lhs.compare(rhs) != 0;
+}
+
+inline bool operator<(StringView lhs, StringView rhs) {
+ return lhs.compare(rhs) < 0;
+}
+
+inline bool operator>(StringView lhs, StringView rhs) {
+ return lhs.compare(rhs) > 0;
+}
+
+inline std::ostream& operator<<(std::ostream& os, StringView s) {
+ os << s.str();
+ return os;
+}
+
+} // namespace google_breakpad
+
+#endif // COMMON_STRING_VIEW_H__
diff --git a/src/common/symbol_data.h b/src/common/symbol_data.h
index 2cf15a85..19d6f3dd 100644
--- a/src/common/symbol_data.h
+++ b/src/common/symbol_data.h
@@ -1,7 +1,6 @@
// -*- mode: c++ -*-
-// Copyright (c) 2013 Google Inc.
-// All rights reserved.
+// Copyright 2013 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -13,7 +12,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -32,11 +31,27 @@
#ifndef COMMON_SYMBOL_DATA_H_
#define COMMON_SYMBOL_DATA_H_
+#include<type_traits>
+
// Control what data is used from the symbol file.
enum SymbolData {
- ALL_SYMBOL_DATA,
- NO_CFI,
- ONLY_CFI
+ NO_DATA = 0,
+ SYMBOLS_AND_FILES = 1,
+ CFI = 1 << 1,
+ INLINES = 1 << 2,
+ ALL_SYMBOL_DATA = INLINES | CFI | SYMBOLS_AND_FILES
};
+inline SymbolData operator&(SymbolData data1, SymbolData data2) {
+ return static_cast<SymbolData>(
+ static_cast<std::underlying_type<SymbolData>::type>(data1) &
+ static_cast<std::underlying_type<SymbolData>::type>(data2));
+}
+
+inline SymbolData operator|(SymbolData data1, SymbolData data2) {
+ return static_cast<SymbolData>(
+ static_cast<std::underlying_type<SymbolData>::type>(data1) |
+ static_cast<std::underlying_type<SymbolData>::type>(data2));
+}
+
#endif // COMMON_SYMBOL_DATA_H_
diff --git a/src/common/test_assembler.cc b/src/common/test_assembler.cc
index 1e783b45..91899663 100644
--- a/src/common/test_assembler.cc
+++ b/src/common/test_assembler.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2010, Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -46,7 +45,7 @@ using std::back_insert_iterator;
Label::Label() : value_(new Binding()) { }
Label::Label(uint64_t value) : value_(new Binding(value)) { }
-Label::Label(const Label &label) {
+Label::Label(const Label& label) {
value_ = label.value_;
value_->Acquire();
}
@@ -54,12 +53,12 @@ Label::~Label() {
if (value_->Release()) delete value_;
}
-Label &Label::operator=(uint64_t value) {
+Label& Label::operator=(uint64_t value) {
value_->Set(NULL, value);
return *this;
}
-Label &Label::operator=(const Label &label) {
+Label& Label::operator=(const Label& label) {
value_->Set(label.value_, 0);
return *this;
}
@@ -89,7 +88,7 @@ Label Label::operator-(uint64_t subtrahend) const {
#define ALWAYS_EVALUATE_AND_ASSERT(x) assert(x)
#endif
-uint64_t Label::operator-(const Label &label) const {
+uint64_t Label::operator-(const Label& label) const {
uint64_t offset;
ALWAYS_EVALUATE_AND_ASSERT(IsKnownOffsetFrom(label, &offset));
return offset;
@@ -101,8 +100,8 @@ uint64_t Label::Value() const {
return v;
};
-bool Label::IsKnownConstant(uint64_t *value_p) const {
- Binding *base;
+bool Label::IsKnownConstant(uint64_t* value_p) const {
+ Binding* base;
uint64_t addend;
value_->Get(&base, &addend);
if (base != NULL) return false;
@@ -110,9 +109,9 @@ bool Label::IsKnownConstant(uint64_t *value_p) const {
return true;
}
-bool Label::IsKnownOffsetFrom(const Label &label, uint64_t *offset_p) const
+bool Label::IsKnownOffsetFrom(const Label& label, uint64_t* offset_p) const
{
- Binding *label_base, *this_base;
+ Binding* label_base, *this_base;
uint64_t label_addend, this_addend;
label.value_->Get(&label_base, &label_addend);
value_->Get(&this_base, &this_addend);
@@ -135,7 +134,7 @@ Label::Binding::~Binding() {
delete base_;
}
-void Label::Binding::Set(Binding *binding, uint64_t addend) {
+void Label::Binding::Set(Binding* binding, uint64_t addend) {
if (!base_ && !binding) {
// We're equating two constants. This could be okay.
assert(addend_ == addend);
@@ -183,13 +182,13 @@ void Label::Binding::Set(Binding *binding, uint64_t addend) {
}
}
-void Label::Binding::Get(Binding **base, uint64_t *addend) {
+void Label::Binding::Get(Binding** base, uint64_t* addend) {
if (base_ && base_ != this) {
// Recurse to find the end of our reference chain (the root of our
// tree), and then rewrite every binding along the chain to refer
// to it directly, adjusting addends appropriately. (This is why
// this member function isn't this-const.)
- Binding *final_base;
+ Binding* final_base;
uint64_t final_addend;
base_->Get(&final_base, &final_addend);
if (final_base) final_base->Acquire();
@@ -218,14 +217,14 @@ static inline void InsertEndian(test_assembler::Endianness endianness,
}
}
-Section &Section::Append(Endianness endianness, size_t size, uint64_t number) {
+Section& Section::Append(Endianness endianness, size_t size, uint64_t number) {
InsertEndian(endianness, size, number,
back_insert_iterator<string>(contents_));
return *this;
}
-Section &Section::Append(Endianness endianness, size_t size,
- const Label &label) {
+Section& Section::Append(Endianness endianness, size_t size,
+ const Label& label) {
// If this label's value is known, there's no reason to waste an
// entry in references_ on it.
uint64_t value;
@@ -246,14 +245,14 @@ Section &Section::Append(Endianness endianness, size_t size,
#define ENDIANNESS(e) ENDIANNESS_ ## e
#define DEFINE_SHORT_APPEND_NUMBER_ENDIAN(e, bits) \
- Section &Section::e ## bits(uint ## bits ## _t v) { \
+ Section& Section::e ## bits(uint ## bits ## _t v) { \
InsertEndian(ENDIANNESS(e), bits / 8, v, \
back_insert_iterator<string>(contents_)); \
return *this; \
}
#define DEFINE_SHORT_APPEND_LABEL_ENDIAN(e, bits) \
- Section &Section::e ## bits(const Label &v) { \
+ Section& Section::e ## bits(const Label& v) { \
return Append(ENDIANNESS(e), bits / 8, v); \
}
@@ -272,13 +271,13 @@ DEFINE_SHORT_APPEND_ENDIAN(B, 32);
DEFINE_SHORT_APPEND_ENDIAN(B, 64);
#define DEFINE_SHORT_APPEND_NUMBER_DEFAULT(bits) \
- Section &Section::D ## bits(uint ## bits ## _t v) { \
+ Section& Section::D ## bits(uint ## bits ## _t v) { \
InsertEndian(endianness_, bits / 8, v, \
back_insert_iterator<string>(contents_)); \
return *this; \
}
#define DEFINE_SHORT_APPEND_LABEL_DEFAULT(bits) \
- Section &Section::D ## bits(const Label &v) { \
+ Section& Section::D ## bits(const Label& v) { \
return Append(endianness_, bits / 8, v); \
}
#define DEFINE_SHORT_APPEND_DEFAULT(bits) \
@@ -290,7 +289,7 @@ DEFINE_SHORT_APPEND_DEFAULT(16);
DEFINE_SHORT_APPEND_DEFAULT(32);
DEFINE_SHORT_APPEND_DEFAULT(64);
-Section &Section::Append(const Section &section) {
+Section& Section::Append(const Section& section) {
size_t base = contents_.size();
contents_.append(section.contents_);
for (vector<Reference>::const_iterator it = section.references_.begin();
@@ -300,7 +299,7 @@ Section &Section::Append(const Section &section) {
return *this;
}
-Section &Section::LEB128(long long value) {
+Section& Section::LEB128(long long value) {
while (value < -0x40 || 0x3f < value) {
contents_ += (value & 0x7f) | 0x80;
if (value < 0)
@@ -312,7 +311,7 @@ Section &Section::LEB128(long long value) {
return *this;
}
-Section &Section::ULEB128(uint64_t value) {
+Section& Section::ULEB128(uint64_t value) {
while (value > 0x7f) {
contents_ += (value & 0x7f) | 0x80;
value = (value >> 7);
@@ -321,7 +320,7 @@ Section &Section::ULEB128(uint64_t value) {
return *this;
}
-Section &Section::Align(size_t alignment, uint8_t pad_byte) {
+Section& Section::Align(size_t alignment, uint8_t pad_byte) {
// ALIGNMENT must be a power of two.
assert(((alignment - 1) & alignment) == 0);
size_t new_size = (contents_.size() + alignment - 1) & ~(alignment - 1);
@@ -335,11 +334,11 @@ void Section::Clear() {
references_.clear();
}
-bool Section::GetContents(string *contents) {
+bool Section::GetContents(string* contents) {
// For each label reference, find the label's value, and patch it into
// the section's contents.
for (size_t i = 0; i < references_.size(); i++) {
- Reference &r = references_[i];
+ Reference& r = references_[i];
uint64_t value;
if (!r.label.IsKnownConstant(&value)) {
fprintf(stderr, "Undefined label #%zu at offset 0x%zx\n", i, r.offset);
diff --git a/src/common/test_assembler.h b/src/common/test_assembler.h
index 373dbeba..809c7b21 100644
--- a/src/common/test_assembler.h
+++ b/src/common/test_assembler.h
@@ -1,7 +1,6 @@
// -*- mode: C++ -*-
-// Copyright (c) 2010, Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -13,7 +12,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -111,7 +110,7 @@ class Label {
public:
Label(); // An undefined label.
Label(uint64_t value); // A label with a fixed value
- Label(const Label &value); // A label equal to another.
+ Label(const Label& value); // A label equal to another.
~Label();
// Return this label's value; it must be known.
@@ -124,18 +123,18 @@ class Label {
// former could fail if the label is not yet defined and the latter won't.
uint64_t Value() const;
- Label &operator=(uint64_t value);
- Label &operator=(const Label &value);
+ Label& operator=(uint64_t value);
+ Label& operator=(const Label& value);
Label operator+(uint64_t addend) const;
Label operator-(uint64_t subtrahend) const;
- uint64_t operator-(const Label &subtrahend) const;
+ uint64_t operator-(const Label& subtrahend) const;
// We could also provide == and != that work on undefined, but
// related, labels.
// Return true if this label's value is known. If VALUE_P is given,
// set *VALUE_P to the known value if returning true.
- bool IsKnownConstant(uint64_t *value_p = NULL) const;
+ bool IsKnownConstant(uint64_t* value_p = NULL) const;
// Return true if the offset from LABEL to this label is known. If
// OFFSET_P is given, set *OFFSET_P to the offset when returning true.
@@ -155,7 +154,7 @@ class Label {
// l-m // -10
// m-l // 10
// m.Value() // error: m's value is not known
- bool IsKnownOffsetFrom(const Label &label, uint64_t *offset_p = NULL) const;
+ bool IsKnownOffsetFrom(const Label& label, uint64_t* offset_p = NULL) const;
private:
// A label's value, or if that is not yet known, how the value is
@@ -186,7 +185,7 @@ class Label {
// Update every binding on this binding's chain to point directly
// to BINDING, or to be a constant, with addends adjusted
// appropriately.
- void Set(Binding *binding, uint64_t value);
+ void Set(Binding* binding, uint64_t value);
// Return what we know about the value of this binding.
// - If this binding's value is a known constant, set BASE to
@@ -198,7 +197,7 @@ class Label {
// value.
// - If this binding is unconstrained, set BASE to this, and leave
// ADDEND unchanged.
- void Get(Binding **base, uint64_t *addend);
+ void Get(Binding** base, uint64_t* addend);
private:
// There are three cases:
@@ -220,7 +219,7 @@ class Label {
// operations on bindings do path compression: they change every
// binding on the chain to point directly to the final value,
// adjusting addends as appropriate.
- Binding *base_;
+ Binding* base_;
uint64_t addend_;
// The number of Labels and Bindings pointing to this binding.
@@ -230,10 +229,10 @@ class Label {
};
// This label's value.
- Binding *value_;
+ Binding* value_;
};
-inline Label operator+(uint64_t a, const Label &l) { return l + a; }
+inline Label operator+(uint64_t a, const Label& l) { return l + a; }
// Note that int-Label isn't defined, as negating a Label is not an
// operation we support.
@@ -288,18 +287,18 @@ class Section {
// Append the SIZE bytes at DATA or the contents of STRING to the
// end of this section. Return a reference to this section.
- Section &Append(const uint8_t *data, size_t size) {
- contents_.append(reinterpret_cast<const char *>(data), size);
+ Section& Append(const uint8_t* data, size_t size) {
+ contents_.append(reinterpret_cast<const char*>(data), size);
return *this;
};
- Section &Append(const string &data) {
+ Section& Append(const string& data) {
contents_.append(data);
return *this;
};
// Append SIZE copies of BYTE to the end of this section. Return a
// reference to this section.
- Section &Append(size_t size, uint8_t byte) {
+ Section& Append(size_t size, uint8_t byte) {
contents_.append(size, (char) byte);
return *this;
}
@@ -307,8 +306,8 @@ class Section {
// Append NUMBER to this section. ENDIANNESS is the endianness to
// use to write the number. SIZE is the length of the number in
// bytes. Return a reference to this section.
- Section &Append(Endianness endianness, size_t size, uint64_t number);
- Section &Append(Endianness endianness, size_t size, const Label &label);
+ Section& Append(Endianness endianness, size_t size, uint64_t number);
+ Section& Append(Endianness endianness, size_t size, const Label& label);
// Append SECTION to the end of this section. The labels SECTION
// refers to need not be defined yet.
@@ -317,11 +316,11 @@ class Section {
// SECTION. If placing SECTION within 'this' provides new
// constraints on existing labels' values, then it's up to the
// caller to fiddle with those labels as needed.
- Section &Append(const Section &section);
+ Section& Append(const Section& section);
// Append the contents of DATA as a series of bytes terminated by
// a NULL character.
- Section &AppendCString(const string &data) {
+ Section& AppendCString(const string& data) {
Append(data);
contents_ += '\0';
return *this;
@@ -329,7 +328,7 @@ class Section {
// Append at most SIZE bytes from DATA; if DATA is less than SIZE bytes
// long, pad with '\0' characters.
- Section &AppendCString(const string &data, size_t size) {
+ Section& AppendCString(const string& data, size_t size) {
contents_.append(data, 0, size);
if (data.size() < size)
Append(size - data.size(), 0);
@@ -352,18 +351,18 @@ class Section {
// the compiler will properly sign-extend a signed value before
// passing it to the function, at which point the function's
// behavior is the same either way.
- Section &L8(uint8_t value) { contents_ += value; return *this; }
- Section &B8(uint8_t value) { contents_ += value; return *this; }
- Section &D8(uint8_t value) { contents_ += value; return *this; }
+ Section& L8(uint8_t value) { contents_ += value; return *this; }
+ Section& B8(uint8_t value) { contents_ += value; return *this; }
+ Section& D8(uint8_t value) { contents_ += value; return *this; }
Section &L16(uint16_t), &L32(uint32_t), &L64(uint64_t),
&B16(uint16_t), &B32(uint32_t), &B64(uint64_t),
&D16(uint16_t), &D32(uint32_t), &D64(uint64_t);
- Section &L8(const Label &label), &L16(const Label &label),
- &L32(const Label &label), &L64(const Label &label),
- &B8(const Label &label), &B16(const Label &label),
- &B32(const Label &label), &B64(const Label &label),
- &D8(const Label &label), &D16(const Label &label),
- &D32(const Label &label), &D64(const Label &label);
+ Section &L8(const Label& label), &L16(const Label& label),
+ &L32(const Label& label), &L64(const Label& label),
+ &B8(const Label& label), &B16(const Label& label),
+ &B32(const Label& label), &B64(const Label& label),
+ &D8(const Label& label), &D16(const Label& label),
+ &D32(const Label& label), &D64(const Label& label);
// Append VALUE in a signed LEB128 (Little-Endian Base 128) form.
//
@@ -383,7 +382,7 @@ class Section {
//
// Note that VALUE cannot be a Label (we would have to implement
// relaxation).
- Section &LEB128(long long value);
+ Section& LEB128(long long value);
// Append VALUE in unsigned LEB128 (Little-Endian Base 128) form.
//
@@ -399,13 +398,13 @@ class Section {
//
// Note that VALUE cannot be a Label (we would have to implement
// relaxation).
- Section &ULEB128(uint64_t value);
+ Section& ULEB128(uint64_t value);
// Jump to the next location aligned on an ALIGNMENT-byte boundary,
// relative to the start of the section. Fill the gap with PAD_BYTE.
// ALIGNMENT must be a power of two. Return a reference to this
// section.
- Section &Align(size_t alignment, uint8_t pad_byte = 0);
+ Section& Align(size_t alignment, uint8_t pad_byte = 0);
// Clear the contents of this section.
void Clear();
@@ -436,19 +435,19 @@ class Section {
Label Here() const { return start_ + Size(); }
// Set *LABEL to Here, and return a reference to this section.
- Section &Mark(Label *label) { *label = Here(); return *this; }
+ Section& Mark(Label* label) { *label = Here(); return *this; }
// If there are no undefined label references left in this
// section, set CONTENTS to the contents of this section, as a
// string, and clear this section. Return true on success, or false
// if there were still undefined labels.
- bool GetContents(string *contents);
+ bool GetContents(string* contents);
private:
// Used internally. A reference to a label's value.
struct Reference {
Reference(size_t set_offset, Endianness set_endianness, size_t set_size,
- const Label &set_label)
+ const Label& set_label)
: offset(set_offset), endianness(set_endianness), size(set_size),
label(set_label) { }
diff --git a/src/common/test_assembler_unittest.cc b/src/common/test_assembler_unittest.cc
index 94b5a5ce..f16594f1 100644
--- a/src/common/test_assembler_unittest.cc
+++ b/src/common/test_assembler_unittest.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2010, Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -755,7 +754,7 @@ const uint8_t SectionFixture::data[] = {
{ \
static const uint8_t expected_bytes[] = b; \
ASSERT_EQ(sizeof(expected_bytes), s.size()); \
- ASSERT_TRUE(memcmp(s.data(), (const char *) expected_bytes, \
+ ASSERT_TRUE(memcmp(s.data(), (const char*) expected_bytes, \
sizeof(expected_bytes)) == 0); \
} \
while(0)
@@ -766,7 +765,7 @@ TEST_F(Append, Bytes) {
section.Append(data, sizeof(data));
ASSERT_TRUE(section.GetContents(&contents));
ASSERT_EQ(sizeof(data), contents.size());
- EXPECT_TRUE(0 == memcmp(contents.data(), (const char *) data, sizeof(data)));
+ EXPECT_TRUE(0 == memcmp(contents.data(), (const char*) data, sizeof(data)));
}
TEST_F(Append, BytesTwice) {
@@ -774,9 +773,9 @@ TEST_F(Append, BytesTwice) {
section.Append(data, sizeof(data));
ASSERT_TRUE(section.GetContents(&contents));
ASSERT_EQ(2 * sizeof(data), contents.size());
- ASSERT_TRUE(0 == memcmp(contents.data(), (const char *) data, sizeof(data)));
+ ASSERT_TRUE(0 == memcmp(contents.data(), (const char*) data, sizeof(data)));
ASSERT_TRUE(0 == memcmp(contents.data() + sizeof(data),
- (const char *) data, sizeof(data)));
+ (const char*) data, sizeof(data)));
}
TEST_F(Append, String) {
diff --git a/src/common/tests/auto_tempdir.h b/src/common/tests/auto_tempdir.h
index 1df88db8..963c2dcf 100644
--- a/src/common/tests/auto_tempdir.h
+++ b/src/common/tests/auto_tempdir.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2011, Google Inc.
-// All rights reserved.
+// Copyright 2011 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/common/tests/file_utils.cc b/src/common/tests/file_utils.cc
index 1c041777..814b2094 100644
--- a/src/common/tests/file_utils.cc
+++ b/src/common/tests/file_utils.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2011, Google Inc.
-// All rights reserved.
+// Copyright 2011 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -96,6 +95,10 @@ bool CopyFile(const char* from_path, const char* to_path) {
return result;
}
+bool CopyFile(const std::string& from_path, const std::string& to_path) {
+ return CopyFile(from_path.c_str(), to_path.c_str());
+}
+
bool ReadFile(const char* path, void* buffer, ssize_t* buffer_size) {
int fd = HANDLE_EINTR(open(path, O_RDONLY));
if (fd == -1) {
diff --git a/src/common/tests/file_utils.h b/src/common/tests/file_utils.h
index c98a9bfa..b96029d0 100644
--- a/src/common/tests/file_utils.h
+++ b/src/common/tests/file_utils.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2011, Google Inc.
-// All rights reserved.
+// Copyright 2011 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -33,9 +32,12 @@
#ifndef COMMON_TESTS_FILE_UTILS_H_
#define COMMON_TESTS_FILE_UTILS_H_
+#include <string>
+
namespace google_breakpad {
// Copies a file from |from_path| to |to_path|. Returns true on success.
+bool CopyFile(const std::string& from_path, const std::string& to_path);
bool CopyFile(const char* from_path, const char* to_path);
// Reads the content of a file at |path| into |buffer|. |buffer_size| specifies
diff --git a/src/common/unordered.h b/src/common/unordered.h
index c9cbd585..7606f170 100644
--- a/src/common/unordered.h
+++ b/src/common/unordered.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2010 Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -46,17 +45,11 @@ struct unordered_map : public __gnu_cxx::hash_map<T, U, H> {};
template <class T, class H = __gnu_cxx::hash<T> >
struct unordered_set : public __gnu_cxx::hash_set<T, H> {};
-#elif defined(_LIBCPP_VERSION) // c++11
+#else
#include <unordered_map>
#include <unordered_set>
using std::unordered_map;
using std::unordered_set;
-
-#else // Fallback to tr1::unordered
-#include <tr1/unordered_map>
-#include <tr1/unordered_set>
-using std::tr1::unordered_map;
-using std::tr1::unordered_set;
#endif
#endif // COMMON_UNORDERED_H_
diff --git a/src/common/using_std_string.h b/src/common/using_std_string.h
index 13c1da59..0f11db7b 100644
--- a/src/common/using_std_string.h
+++ b/src/common/using_std_string.h
@@ -1,7 +1,6 @@
// -*- mode: C++ -*-
-// Copyright (c) 2012, Google Inc.
-// All rights reserved.
+// Copyright 2012 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -13,7 +12,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -55,6 +54,7 @@
#ifdef HAS_GLOBAL_STRING
typedef ::string google_breakpad_string;
#else
+#include <string>
using std::string;
typedef std::string google_breakpad_string;
#endif
diff --git a/src/common/windows/common_windows.gyp b/src/common/windows/common_windows.gyp
deleted file mode 100644
index 5f7594b1..00000000
--- a/src/common/windows/common_windows.gyp
+++ /dev/null
@@ -1,112 +0,0 @@
-# Copyright 2013 Google Inc. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-# * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-# * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-{
- 'includes': [
- '../../build/common.gypi',
- ],
- 'targets': [
- {
- 'target_name': 'dia_sdk',
- 'type': 'none',
- 'all_dependent_settings': {
- 'include_dirs': [
- '<(DEPTH)',
- '$(VSInstallDir)/DIA SDK/include',
- ],
- 'msvs_settings': {
- 'VCLinkerTool': {
- 'AdditionalDependencies': [
- 'diaguids.lib',
- 'imagehlp.lib',
- ],
- },
- },
- 'configurations': {
- 'x86_Base': {
- 'msvs_settings': {
- 'VCLinkerTool': {
- 'AdditionalLibraryDirectories':
- ['$(VSInstallDir)/DIA SDK/lib'],
- },
- },
- },
- 'x64_Base': {
- 'msvs_settings': {
- 'VCLinkerTool': {
- 'AdditionalLibraryDirectories':
- ['$(VSInstallDir)/DIA SDK/lib/amd64'],
- },
- },
- },
- },
- },
- },
- {
- 'target_name': 'common_windows_lib',
- 'type': 'static_library',
- 'sources': [
- 'dia_util.cc',
- 'dia_util.h',
- 'guid_string.cc',
- 'guid_string.h',
- 'http_upload.cc',
- 'http_upload.h',
- 'module_info.h',
- 'omap.cc',
- 'omap.h',
- 'omap_internal.h',
- 'pdb_source_line_writer.cc',
- 'pdb_source_line_writer.h',
- 'pe_source_line_writer.cc',
- 'pe_source_line_writer.h',
- 'pe_util.h',
- 'pe_util.cc',
- 'string_utils.cc',
- 'string_utils-inl.h',
- 'symbol_collector_client.cc',
- 'symbol_collector_client.h',
- ],
- 'dependencies': [
- 'dia_sdk',
- ],
- },
- {
- 'target_name': 'common_windows_unittests',
- 'type': 'executable',
- 'sources': [
- 'omap_unittest.cc',
- ],
- 'dependencies': [
- '<(DEPTH)/client/windows/unittests/testing.gyp:gmock',
- '<(DEPTH)/client/windows/unittests/testing.gyp:gtest',
- 'common_windows_lib',
- ],
- },
- ],
-}
diff --git a/src/common/windows/dia_util.cc b/src/common/windows/dia_util.cc
index ed8cb5b6..dcfe0ef9 100644
--- a/src/common/windows/dia_util.cc
+++ b/src/common/windows/dia_util.cc
@@ -1,92 +1,92 @@
-// Copyright 2013 Google Inc. All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-#include "common/windows/dia_util.h"
-
-#include <atlbase.h>
-
-namespace google_breakpad {
-
-bool FindDebugStream(const wchar_t* name,
- IDiaSession* session,
- IDiaEnumDebugStreamData** debug_stream) {
- CComPtr<IDiaEnumDebugStreams> enum_debug_streams;
- if (FAILED(session->getEnumDebugStreams(&enum_debug_streams))) {
- fprintf(stderr, "IDiaSession::getEnumDebugStreams failed\n");
- return false;
- }
-
- CComPtr<IDiaEnumDebugStreamData> temp_debug_stream;
- ULONG fetched = 0;
- while (SUCCEEDED(enum_debug_streams->Next(1, &temp_debug_stream, &fetched)) &&
- fetched == 1) {
- CComBSTR stream_name;
- if (FAILED(temp_debug_stream->get_name(&stream_name))) {
- fprintf(stderr, "IDiaEnumDebugStreamData::get_name failed\n");
- return false;
- }
-
- // Found the stream?
- if (wcsncmp((LPWSTR)stream_name, name, stream_name.Length()) == 0) {
- *debug_stream = temp_debug_stream.Detach();
- return true;
- }
-
- temp_debug_stream.Release();
- }
-
- // No table was found.
- return false;
-}
-
-bool FindTable(REFIID iid, IDiaSession* session, void** table) {
- // Get the table enumerator.
- CComPtr<IDiaEnumTables> enum_tables;
- if (FAILED(session->getEnumTables(&enum_tables))) {
- fprintf(stderr, "IDiaSession::getEnumTables failed\n");
- return false;
- }
-
- // Iterate through the tables.
- CComPtr<IDiaTable> temp_table;
- ULONG fetched = 0;
- while (SUCCEEDED(enum_tables->Next(1, &temp_table, &fetched)) &&
- fetched == 1) {
- void* temp = NULL;
- if (SUCCEEDED(temp_table->QueryInterface(iid, &temp))) {
- *table = temp;
- return true;
- }
- temp_table.Release();
- }
-
- // The table was not found.
- return false;
-}
-
+// Copyright 2013 Google LLC
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google LLC nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "common/windows/dia_util.h"
+
+#include <atlbase.h>
+
+namespace google_breakpad {
+
+bool FindDebugStream(const wchar_t* name,
+ IDiaSession* session,
+ IDiaEnumDebugStreamData** debug_stream) {
+ CComPtr<IDiaEnumDebugStreams> enum_debug_streams;
+ if (FAILED(session->getEnumDebugStreams(&enum_debug_streams))) {
+ fprintf(stderr, "IDiaSession::getEnumDebugStreams failed\n");
+ return false;
+ }
+
+ CComPtr<IDiaEnumDebugStreamData> temp_debug_stream;
+ ULONG fetched = 0;
+ while (SUCCEEDED(enum_debug_streams->Next(1, &temp_debug_stream, &fetched)) &&
+ fetched == 1) {
+ CComBSTR stream_name;
+ if (FAILED(temp_debug_stream->get_name(&stream_name))) {
+ fprintf(stderr, "IDiaEnumDebugStreamData::get_name failed\n");
+ return false;
+ }
+
+ // Found the stream?
+ if (wcsncmp((LPWSTR)stream_name, name, stream_name.Length()) == 0) {
+ *debug_stream = temp_debug_stream.Detach();
+ return true;
+ }
+
+ temp_debug_stream.Release();
+ }
+
+ // No table was found.
+ return false;
+}
+
+bool FindTable(REFIID iid, IDiaSession* session, void** table) {
+ // Get the table enumerator.
+ CComPtr<IDiaEnumTables> enum_tables;
+ if (FAILED(session->getEnumTables(&enum_tables))) {
+ fprintf(stderr, "IDiaSession::getEnumTables failed\n");
+ return false;
+ }
+
+ // Iterate through the tables.
+ CComPtr<IDiaTable> temp_table;
+ ULONG fetched = 0;
+ while (SUCCEEDED(enum_tables->Next(1, &temp_table, &fetched)) &&
+ fetched == 1) {
+ void* temp = NULL;
+ if (SUCCEEDED(temp_table->QueryInterface(iid, &temp))) {
+ *table = temp;
+ return true;
+ }
+ temp_table.Release();
+ }
+
+ // The table was not found.
+ return false;
+}
+
} // namespace google_breakpad \ No newline at end of file
diff --git a/src/common/windows/dia_util.h b/src/common/windows/dia_util.h
index b9e0df2d..16ed8380 100644
--- a/src/common/windows/dia_util.h
+++ b/src/common/windows/dia_util.h
@@ -1,4 +1,4 @@
-// Copyright 2013 Google Inc. All rights reserved.
+// Copyright 2013 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -10,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/common/windows/guid_string.cc b/src/common/windows/guid_string.cc
index b7f877e6..be9eb8a3 100644
--- a/src/common/windows/guid_string.cc
+++ b/src/common/windows/guid_string.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2006, Google Inc.
-// All rights reserved.
+// Copyright 2006 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/common/windows/guid_string.h b/src/common/windows/guid_string.h
index 48a5c1d3..ee3d1006 100644
--- a/src/common/windows/guid_string.h
+++ b/src/common/windows/guid_string.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2006, Google Inc.
-// All rights reserved.
+// Copyright 2006 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/common/windows/http_upload.cc b/src/common/windows/http_upload.cc
index b0cc9078..088a5e54 100644
--- a/src/common/windows/http_upload.cc
+++ b/src/common/windows/http_upload.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2006, Google Inc.
-// All rights reserved.
+// Copyright 2006 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -65,7 +64,7 @@ namespace {
HINTERNET handle_;
};
- wstring UTF8ToWide(const string &utf8) {
+ wstring UTF8ToWide(const string& utf8) {
if (utf8.length() == 0) {
return wstring();
}
@@ -85,7 +84,7 @@ namespace {
return result;
}
- string WideToMBCP(const wstring &wide, unsigned int cp) {
+ string WideToMBCP(const wstring& wide, unsigned int cp) {
if (wide.length() == 0) {
return string();
}
@@ -107,7 +106,7 @@ namespace {
return result;
}
- bool GetFileContents(const wstring &filename, vector<char> *contents) {
+ bool GetFileContents(const wstring& filename, vector<char>* contents) {
bool rv = false;
// The "open" method on pre-MSVC8 ifstream implementations doesn't accept a
// wchar_t* filename, so use _wfopen directly in that case. For VC8 and
@@ -141,10 +140,10 @@ namespace {
return rv;
}
- bool CheckParameters(const map<wstring, wstring> &parameters) {
+ bool CheckParameters(const map<wstring, wstring>& parameters) {
for (map<wstring, wstring>::const_iterator pos = parameters.begin();
pos != parameters.end(); ++pos) {
- const wstring &str = pos->first;
+ const wstring& str = pos->first;
if (str.size() == 0) {
return false; // disallow empty parameter names
}
@@ -159,7 +158,7 @@ namespace {
}
// Converts a UTF16 string to UTF8.
- string WideToUTF8(const wstring &wide) {
+ string WideToUTF8(const wstring& wide) {
return WideToMBCP(wide, CP_UTF8);
}
@@ -262,7 +261,7 @@ namespace {
NULL, // password
INTERNET_SERVICE_HTTP,
0, // flags
- NULL)); // context
+ 0)); // context
if (!connection.get()) {
return false;
}
@@ -276,7 +275,7 @@ namespace {
NULL, // referer
NULL, // agent type
http_open_flags,
- NULL)); // context
+ 0)); // context
if (!request.get()) {
return false;
}
@@ -305,7 +304,7 @@ namespace {
}
if (!HttpSendRequest(request.get(), NULL, 0,
- const_cast<char *>(request_body.data()),
+ const_cast<char*>(request_body.data()),
static_cast<DWORD>(request_body.size()))) {
return false;
}
@@ -351,16 +350,16 @@ namespace {
return wstring(temp);
}
- wstring GenerateMultipartPostRequestHeader(const wstring &boundary) {
+ wstring GenerateMultipartPostRequestHeader(const wstring& boundary) {
wstring header = L"Content-Type: multipart/form-data; boundary=";
header += boundary;
return header;
}
- bool AppendFileToRequestBody(
- const wstring& file_part_name,
- const wstring& filename,
- string* request_body) {
+ bool AppendFileToRequestBody(const wstring& file_part_name,
+ const wstring& filename,
+ string* request_body,
+ bool set_content_type = true) {
string file_part_name_utf8 = WideToUTF8(file_part_name);
if (file_part_name_utf8.empty()) {
return false;
@@ -371,11 +370,17 @@ namespace {
return false;
}
- request_body->append("Content-Disposition: form-data; "
- "name=\"" + file_part_name_utf8 + "\"; "
- "filename=\"" + filename_utf8 + "\"\r\n");
- request_body->append("Content-Type: application/octet-stream\r\n");
- request_body->append("\r\n");
+ if (set_content_type) {
+ request_body->append(
+ "Content-Disposition: form-data; "
+ "name=\"" +
+ file_part_name_utf8 +
+ "\"; "
+ "filename=\"" +
+ filename_utf8 + "\"\r\n");
+ request_body->append("Content-Type: application/octet-stream\r\n");
+ request_body->append("\r\n");
+ }
vector<char> contents;
if (!GetFileContents(filename, &contents)) {
@@ -385,14 +390,13 @@ namespace {
if (!contents.empty()) {
request_body->append(&(contents[0]), contents.size());
}
- request_body->append("\r\n");
return true;
}
- bool GenerateRequestBody(const map<wstring, wstring> &parameters,
- const map<wstring, wstring> &files,
- const wstring &boundary,
+ bool GenerateRequestBody(const map<wstring, wstring>& parameters,
+ const map<wstring, wstring>& files,
+ const wstring& boundary,
string *request_body) {
string boundary_str = WideToUTF8(boundary);
if (boundary_str.empty()) {
@@ -432,7 +436,11 @@ namespace google_breakpad {
wstring* response_body,
int* response_code) {
string request_body;
- if (!AppendFileToRequestBody(L"symbol_file", path, &request_body)) {
+ // Turn off content-type in the body. If content-type is set then binary
+ // files uploaded to GCS end up with the it prepended to the file
+ // contents.
+ if (!AppendFileToRequestBody(L"symbol_file", path, &request_body,
+ /*set_content_type=*/false)) {
return false;
}
diff --git a/src/common/windows/http_upload.h b/src/common/windows/http_upload.h
index 57e526e3..e117840e 100644
--- a/src/common/windows/http_upload.h
+++ b/src/common/windows/http_upload.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2006, Google Inc.
-// All rights reserved.
+// Copyright 2006 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -114,8 +113,8 @@ class HTTPUpload {
// No instances of this class should be created.
// Disallow all constructors, destructors, and operator=.
HTTPUpload();
- explicit HTTPUpload(const HTTPUpload &);
- void operator=(const HTTPUpload &);
+ explicit HTTPUpload(const HTTPUpload&);
+ void operator=(const HTTPUpload&);
~HTTPUpload();
};
diff --git a/src/common/windows/module_info.h b/src/common/windows/module_info.h
index 3dccc808..ade32c11 100644
--- a/src/common/windows/module_info.h
+++ b/src/common/windows/module_info.h
@@ -1,75 +1,74 @@
-// Copyright (c) 2019, Google Inc.
-// All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-#ifndef COMMON_WINDOWS_MODULE_INFO_H_
-#define COMMON_WINDOWS_MODULE_INFO_H_
-
-#include <string>
-
-namespace google_breakpad {
-
-using std::wstring;
-// A structure that carries information that identifies a module.
-struct PDBModuleInfo {
-public:
- // The basename of the pe/pdb file from which information was loaded.
- wstring debug_file;
-
- // The module's identifier. For recent pe/pdb files, the identifier consists
- // of the pe/pdb's guid, in uppercase hexadecimal form without any dashes
- // or separators, followed immediately by the pe/pdb's age, also in
- // uppercase hexadecimal form. For older pe/pdb files which have no guid,
- // the identifier is the pe/pdb's 32-bit signature value, in zero-padded
- // hexadecimal form, followed immediately by the pe/pdb's age, in lowercase
- // hexadecimal form.
- wstring debug_identifier;
-
- // A string identifying the cpu that the pe/pdb is associated with.
- // Currently, this may be "x86" or "unknown".
- wstring cpu;
-};
-
-// A structure that carries information that identifies a PE file,
-// either an EXE or a DLL.
-struct PEModuleInfo {
- // The basename of the PE file.
- wstring code_file;
-
- // The PE file's code identifier, which consists of its timestamp
- // and file size concatenated together into a single hex string.
- // (The fields IMAGE_OPTIONAL_HEADER::SizeOfImage and
- // IMAGE_FILE_HEADER::TimeDateStamp, as defined in the ImageHlp
- // documentation.) This is not well documented, if it's documented
- // at all, but it's what symstore does and what DbgHelp supports.
- wstring code_identifier;
-};
-
-} // namespace google_breakpad
-
-#endif // COMMON_WINDOWS_MODULE_INFO_H_
+// Copyright 2019 Google LLC
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google LLC nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef COMMON_WINDOWS_MODULE_INFO_H_
+#define COMMON_WINDOWS_MODULE_INFO_H_
+
+#include <string>
+
+namespace google_breakpad {
+
+using std::wstring;
+// A structure that carries information that identifies a module.
+struct PDBModuleInfo {
+public:
+ // The basename of the pe/pdb file from which information was loaded.
+ wstring debug_file;
+
+ // The module's identifier. For recent pe/pdb files, the identifier consists
+ // of the pe/pdb's guid, in uppercase hexadecimal form without any dashes
+ // or separators, followed immediately by the pe/pdb's age, also in
+ // uppercase hexadecimal form. For older pe/pdb files which have no guid,
+ // the identifier is the pe/pdb's 32-bit signature value, in zero-padded
+ // hexadecimal form, followed immediately by the pe/pdb's age, in lowercase
+ // hexadecimal form.
+ wstring debug_identifier;
+
+ // A string identifying the cpu that the pe/pdb is associated with.
+ // Currently, this may be "x86" or "unknown".
+ wstring cpu;
+};
+
+// A structure that carries information that identifies a PE file,
+// either an EXE or a DLL.
+struct PEModuleInfo {
+ // The basename of the PE file.
+ wstring code_file;
+
+ // The PE file's code identifier, which consists of its timestamp
+ // and file size concatenated together into a single hex string.
+ // (The fields IMAGE_OPTIONAL_HEADER::SizeOfImage and
+ // IMAGE_FILE_HEADER::TimeDateStamp, as defined in the ImageHlp
+ // documentation.) This is not well documented, if it's documented
+ // at all, but it's what symstore does and what DbgHelp supports.
+ wstring code_identifier;
+};
+
+} // namespace google_breakpad
+
+#endif // COMMON_WINDOWS_MODULE_INFO_H_
diff --git a/src/common/windows/omap.cc b/src/common/windows/omap.cc
index ba3ce86b..ad916997 100644
--- a/src/common/windows/omap.cc
+++ b/src/common/windows/omap.cc
@@ -1,4 +1,4 @@
-// Copyright 2013 Google Inc. All rights reserved.
+// Copyright 2013 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -10,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -449,11 +449,11 @@ void BuildEndpointIndexMap(ImageMap* image_map) {
}
}
-void BuildSubsequentRVAMap(const OmapData &omap_data,
- std::map<DWORD, DWORD> *subsequent) {
+void BuildSubsequentRVAMap(const OmapData& omap_data,
+ std::map<DWORD, DWORD>* subsequent) {
assert(subsequent->empty());
- const OmapFromTable &orig2tran =
- reinterpret_cast<const OmapFromTable &>(omap_data.omap_from);
+ const OmapFromTable& orig2tran =
+ reinterpret_cast<const OmapFromTable&>(omap_data.omap_from);
if (orig2tran.empty())
return;
diff --git a/src/common/windows/omap.h b/src/common/windows/omap.h
index bc293afb..51601fa9 100644
--- a/src/common/windows/omap.h
+++ b/src/common/windows/omap.h
@@ -1,4 +1,4 @@
-// Copyright 2013 Google Inc. All rights reserved.
+// Copyright 2013 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -10,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/common/windows/omap_internal.h b/src/common/windows/omap_internal.h
index 2a4713d9..cd20d9fb 100644
--- a/src/common/windows/omap_internal.h
+++ b/src/common/windows/omap_internal.h
@@ -1,4 +1,4 @@
-// Copyright 2013 Google Inc. All rights reserved.
+// Copyright 2013 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -10,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/common/windows/omap_unittest.cc b/src/common/windows/omap_unittest.cc
index 7fe66bd4..841e5391 100644
--- a/src/common/windows/omap_unittest.cc
+++ b/src/common/windows/omap_unittest.cc
@@ -1,329 +1,329 @@
-// Copyright 2013 Google Inc. All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-// Unittests for OMAP related functions.
-
-#include "common/windows/omap.h"
-
-#include "breakpad_googletest_includes.h"
-
-namespace google_breakpad {
-
-// Equality operators for ContainerEq. These must be outside of the anonymous
-// namespace in order for them to be found.
-bool operator==(const MappedRange& mr1, const MappedRange& mr2) {
- return mr1.rva_original == mr2.rva_original &&
- mr1.rva_transformed == mr2.rva_transformed &&
- mr1.length == mr2.length &&
- mr1.injected == mr2.injected &&
- mr1.removed == mr2.removed;
-}
-bool operator==(const EndpointIndex& ei1, const EndpointIndex& ei2) {
- return ei1.endpoint == ei2.endpoint && ei1.index == ei2.index;
-}
-
-// Pretty printers for more meaningful error messages. Also need to be outside
-// the anonymous namespace.
-std::ostream& operator<<(std::ostream& os, const MappedRange& mr) {
- os << "MappedRange(rva_original=" << mr.rva_original
- << ", rva_transformed=" << mr.rva_transformed
- << ", length=" << mr.length
- << ", injected=" << mr.injected
- << ", removed=" << mr.removed << ")";
- return os;
-}
-std::ostream& operator<<(std::ostream& os, const EndpointIndex& ei) {
- os << "EndpointIndex(endpoint=" << ei.endpoint
- << ", index=" << ei.index << ")";
- return os;
-}
-std::ostream& operator<<(std::ostream& os, const AddressRange& ar) {
- os << "AddressRange(rva=" << ar.rva << ", length=" << ar.length << ")";
- return os;
-}
-
-namespace {
-
-OMAP CreateOmap(DWORD rva, DWORD rvaTo) {
- OMAP o = { rva, rvaTo };
- return o;
-}
-
-MappedRange CreateMappedRange(DWORD rva_original,
- DWORD rva_transformed,
- DWORD length,
- DWORD injected,
- DWORD removed) {
- MappedRange mr = { rva_original, rva_transformed, length, injected, removed };
- return mr;
-}
-
-EndpointIndex CreateEndpointIndex(DWORD endpoint, size_t index) {
- EndpointIndex ei = { endpoint, index };
- return ei;
-}
-
-// (C is removed)
-// Original : A B C D E F G H
-// Transformed: A B D F E * H1 G1 G2 H2
-// (* is injected, G is copied, H is split)
-// A is implied.
-
-// Layout of the original image.
-const AddressRange B(100, 15);
-const AddressRange C(B.end(), 10);
-const AddressRange D(C.end(), 25);
-const AddressRange E(D.end(), 10);
-const AddressRange F(E.end(), 40);
-const AddressRange G(F.end(), 3);
-const AddressRange H(G.end(), 7);
-
-// Layout of the transformed image.
-const AddressRange Bt(100, 15);
-const AddressRange Dt(Bt.end(), 20); // D is shortened.
-const AddressRange Ft(Dt.end(), F.length);
-const AddressRange Et(Ft.end(), E.length);
-const AddressRange injected(Et.end(), 5);
-const AddressRange H1t(injected.end(), 4); // H is split.
-const AddressRange G1t(H1t.end(), G.length); // G is copied.
-const AddressRange G2t(G1t.end(), G.length); // G is copied.
-const AddressRange H2t(G2t.end(), 3); // H is split.
-
-class BuildImageMapTest : public testing::Test {
- public:
- static const DWORD kInvalidAddress = 0xFFFFFFFF;
-
- void InitOmapData() {
- omap_data.length_original = H.end();
-
- // Build the OMAPTO vector (from transformed to original).
- omap_data.omap_to.push_back(CreateOmap(Bt.rva, B.rva));
- omap_data.omap_to.push_back(CreateOmap(Dt.rva, D.rva));
- omap_data.omap_to.push_back(CreateOmap(Ft.rva, F.rva));
- omap_data.omap_to.push_back(CreateOmap(Et.rva, E.rva));
- omap_data.omap_to.push_back(CreateOmap(injected.rva, kInvalidAddress));
- omap_data.omap_to.push_back(CreateOmap(H1t.rva, H.rva));
- omap_data.omap_to.push_back(CreateOmap(G1t.rva, G.rva));
- omap_data.omap_to.push_back(CreateOmap(G2t.rva, G.rva));
- omap_data.omap_to.push_back(CreateOmap(H2t.rva, H.rva + H1t.length));
- omap_data.omap_to.push_back(CreateOmap(H2t.end(), kInvalidAddress));
-
- // Build the OMAPFROM vector (from original to transformed).
- omap_data.omap_from.push_back(CreateOmap(B.rva, Bt.rva));
- omap_data.omap_from.push_back(CreateOmap(C.rva, kInvalidAddress));
- omap_data.omap_from.push_back(CreateOmap(D.rva, Dt.rva));
- omap_data.omap_from.push_back(CreateOmap(E.rva, Et.rva));
- omap_data.omap_from.push_back(CreateOmap(F.rva, Ft.rva));
- omap_data.omap_from.push_back(CreateOmap(G.rva, G1t.rva));
- omap_data.omap_from.push_back(CreateOmap(H.rva, H1t.rva));
- omap_data.omap_from.push_back(CreateOmap(H.rva + H1t.length, H2t.rva));
- omap_data.omap_from.push_back(CreateOmap(H.end(), kInvalidAddress));
- }
-
- OmapData omap_data;
-};
-
-} // namespace
-
-TEST_F(BuildImageMapTest, EmptyImageMapOnEmptyOmapData) {
- ASSERT_EQ(0u, omap_data.omap_from.size());
- ASSERT_EQ(0u, omap_data.omap_to.size());
- ASSERT_EQ(0u, omap_data.length_original);
-
- ImageMap image_map;
- BuildImageMap(omap_data, &image_map);
- EXPECT_EQ(0u, image_map.mapping.size());
- EXPECT_EQ(0u, image_map.endpoint_index_map.size());
-}
-
-TEST_F(BuildImageMapTest, ImageMapIsCorrect) {
- InitOmapData();
- ASSERT_LE(0u, omap_data.omap_from.size());
- ASSERT_LE(0u, omap_data.omap_to.size());
- ASSERT_LE(0u, omap_data.length_original);
-
- ImageMap image_map;
- BuildImageMap(omap_data, &image_map);
- EXPECT_LE(9u, image_map.mapping.size());
- EXPECT_LE(9u, image_map.endpoint_index_map.size());
-
- Mapping mapping;
- mapping.push_back(CreateMappedRange(0, 0, B.rva, 0, 0));
- // C is removed, and it originally comes immediately after B.
- mapping.push_back(CreateMappedRange(B.rva, Bt.rva, B.length, 0, C.length));
- // D is shortened by a length of 5.
- mapping.push_back(CreateMappedRange(D.rva, Dt.rva, Dt.length, 0, 5));
- // The injected content comes immediately after E in the transformed image.
- mapping.push_back(CreateMappedRange(E.rva, Et.rva, E.length, injected.length,
- 0));
- mapping.push_back(CreateMappedRange(F.rva, Ft.rva, F.length, 0, 0));
- // G is copied so creates two entries.
- mapping.push_back(CreateMappedRange(G.rva, G1t.rva, G.length, 0, 0));
- mapping.push_back(CreateMappedRange(G.rva, G2t.rva, G.length, 0, 0));
- // H is split, so create two entries.
- mapping.push_back(CreateMappedRange(H.rva, H1t.rva, H1t.length, 0, 0));
- mapping.push_back(CreateMappedRange(H.rva + H1t.length, H2t.rva, H2t.length,
- 0, 0));
- EXPECT_THAT(mapping,
- testing::ContainerEq(image_map.mapping));
-
- EndpointIndexMap endpoint_index_map;
- endpoint_index_map.push_back(CreateEndpointIndex(0, 0));
- endpoint_index_map.push_back(CreateEndpointIndex(B.rva, 1));
- endpoint_index_map.push_back(CreateEndpointIndex(D.rva, 2));
- endpoint_index_map.push_back(CreateEndpointIndex(E.rva, 3));
- endpoint_index_map.push_back(CreateEndpointIndex(F.rva, 4));
- // G is duplicated so 2 ranges map back to it, hence the skip from 5 to 7.
- endpoint_index_map.push_back(CreateEndpointIndex(G.rva, 5));
- // H is split so we expect 2 endpoints to show up attributed to it.
- endpoint_index_map.push_back(CreateEndpointIndex(H.rva, 7));
- endpoint_index_map.push_back(CreateEndpointIndex(H.rva + H1t.length, 8));
- endpoint_index_map.push_back(CreateEndpointIndex(H.end(), 9));
- EXPECT_THAT(endpoint_index_map,
- testing::ContainerEq(image_map.endpoint_index_map));
-}
-
-namespace {
-
-class MapAddressRangeTest : public BuildImageMapTest {
- public:
- typedef BuildImageMapTest Super;
- virtual void SetUp() {
- Super::SetUp();
- InitOmapData();
- BuildImageMap(omap_data, &image_map);
- }
-
- ImageMap image_map;
-
- private:
- using BuildImageMapTest::InitOmapData;
- using BuildImageMapTest::omap_data;
-};
-
-} // namespace
-
-TEST_F(MapAddressRangeTest, EmptyImageMapReturnsIdentity) {
- ImageMap im;
- AddressRangeVector mapped_ranges;
- AddressRange ar(0, 1024);
- MapAddressRange(im, ar, &mapped_ranges);
- EXPECT_EQ(1u, mapped_ranges.size());
- EXPECT_EQ(ar, mapped_ranges[0]);
-}
-
-TEST_F(MapAddressRangeTest, MapOutOfImage) {
- AddressRangeVector mapped_ranges;
- MapAddressRange(image_map, AddressRange(H.end() + 10, 10), &mapped_ranges);
- EXPECT_EQ(0u, mapped_ranges.size());
-}
-
-TEST_F(MapAddressRangeTest, MapIdentity) {
- AddressRangeVector mapped_ranges;
- MapAddressRange(image_map, B, &mapped_ranges);
- EXPECT_EQ(1u, mapped_ranges.size());
- EXPECT_THAT(mapped_ranges, testing::ElementsAre(B));
-}
-
-TEST_F(MapAddressRangeTest, MapReorderedContiguous) {
- AddressRangeVector mapped_ranges;
-
- AddressRange DEF(D.rva, F.end() - D.rva);
- MapAddressRange(image_map, DEF, &mapped_ranges);
- EXPECT_EQ(1u, mapped_ranges.size());
-
- AddressRange DFEt(Dt.rva, Et.end() - Dt.rva);
- EXPECT_THAT(mapped_ranges, testing::ElementsAre(DFEt));
-}
-
-TEST_F(MapAddressRangeTest, MapEmptySingle) {
- AddressRangeVector mapped_ranges;
- MapAddressRange(image_map, AddressRange(D.rva, 0), &mapped_ranges);
- EXPECT_EQ(1u, mapped_ranges.size());
- EXPECT_THAT(mapped_ranges, testing::ElementsAre(AddressRange(Dt.rva, 0)));
-}
-
-TEST_F(MapAddressRangeTest, MapEmptyCopied) {
- AddressRangeVector mapped_ranges;
- MapAddressRange(image_map, AddressRange(G.rva, 0), &mapped_ranges);
- EXPECT_EQ(2u, mapped_ranges.size());
- EXPECT_THAT(mapped_ranges, testing::ElementsAre(AddressRange(G1t.rva, 0),
- AddressRange(G2t.rva, 0)));
-}
-
-TEST_F(MapAddressRangeTest, MapCopiedContiguous) {
- AddressRangeVector mapped_ranges;
- MapAddressRange(image_map, G, &mapped_ranges);
- EXPECT_EQ(1u, mapped_ranges.size());
- EXPECT_THAT(mapped_ranges, testing::ElementsAre(
- AddressRange(G1t.rva, G2t.end() - G1t.rva)));
-}
-
-TEST_F(MapAddressRangeTest, MapSplitDiscontiguous) {
- AddressRangeVector mapped_ranges;
- MapAddressRange(image_map, H, &mapped_ranges);
- EXPECT_EQ(2u, mapped_ranges.size());
- EXPECT_THAT(mapped_ranges, testing::ElementsAre(H1t, H2t));
-}
-
-TEST_F(MapAddressRangeTest, MapInjected) {
- AddressRangeVector mapped_ranges;
-
- AddressRange EFGH(E.rva, H.end() - E.rva);
- MapAddressRange(image_map, EFGH, &mapped_ranges);
- EXPECT_EQ(1u, mapped_ranges.size());
-
- AddressRange FEHGGHt(Ft.rva, H2t.end() - Ft.rva);
- EXPECT_THAT(mapped_ranges, testing::ElementsAre(FEHGGHt));
-}
-
-TEST_F(MapAddressRangeTest, MapRemovedEntirely) {
- AddressRangeVector mapped_ranges;
- MapAddressRange(image_map, C, &mapped_ranges);
- EXPECT_EQ(0u, mapped_ranges.size());
-}
-
-TEST_F(MapAddressRangeTest, MapRemovedPartly) {
- AddressRangeVector mapped_ranges;
- MapAddressRange(image_map, D, &mapped_ranges);
- EXPECT_EQ(1u, mapped_ranges.size());
- EXPECT_THAT(mapped_ranges, testing::ElementsAre(Dt));
-}
-
-TEST_F(MapAddressRangeTest, MapFull) {
- AddressRangeVector mapped_ranges;
-
- AddressRange AH(0, H.end());
- MapAddressRange(image_map, AH, &mapped_ranges);
- EXPECT_EQ(1u, mapped_ranges.size());
-
- AddressRange AHt(0, H2t.end());
- EXPECT_THAT(mapped_ranges, testing::ElementsAre(AHt));
-}
-
-} // namespace google_breakpad
+// Copyright 2013 Google LLC
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google LLC nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Unittests for OMAP related functions.
+
+#include "common/windows/omap.h"
+
+#include "breakpad_googletest_includes.h"
+
+namespace google_breakpad {
+
+// Equality operators for ContainerEq. These must be outside of the anonymous
+// namespace in order for them to be found.
+bool operator==(const MappedRange& mr1, const MappedRange& mr2) {
+ return mr1.rva_original == mr2.rva_original &&
+ mr1.rva_transformed == mr2.rva_transformed &&
+ mr1.length == mr2.length &&
+ mr1.injected == mr2.injected &&
+ mr1.removed == mr2.removed;
+}
+bool operator==(const EndpointIndex& ei1, const EndpointIndex& ei2) {
+ return ei1.endpoint == ei2.endpoint && ei1.index == ei2.index;
+}
+
+// Pretty printers for more meaningful error messages. Also need to be outside
+// the anonymous namespace.
+std::ostream& operator<<(std::ostream& os, const MappedRange& mr) {
+ os << "MappedRange(rva_original=" << mr.rva_original
+ << ", rva_transformed=" << mr.rva_transformed
+ << ", length=" << mr.length
+ << ", injected=" << mr.injected
+ << ", removed=" << mr.removed << ")";
+ return os;
+}
+std::ostream& operator<<(std::ostream& os, const EndpointIndex& ei) {
+ os << "EndpointIndex(endpoint=" << ei.endpoint
+ << ", index=" << ei.index << ")";
+ return os;
+}
+std::ostream& operator<<(std::ostream& os, const AddressRange& ar) {
+ os << "AddressRange(rva=" << ar.rva << ", length=" << ar.length << ")";
+ return os;
+}
+
+namespace {
+
+OMAP CreateOmap(DWORD rva, DWORD rvaTo) {
+ OMAP o = { rva, rvaTo };
+ return o;
+}
+
+MappedRange CreateMappedRange(DWORD rva_original,
+ DWORD rva_transformed,
+ DWORD length,
+ DWORD injected,
+ DWORD removed) {
+ MappedRange mr = { rva_original, rva_transformed, length, injected, removed };
+ return mr;
+}
+
+EndpointIndex CreateEndpointIndex(DWORD endpoint, size_t index) {
+ EndpointIndex ei = { endpoint, index };
+ return ei;
+}
+
+// (C is removed)
+// Original : A B C D E F G H
+// Transformed: A B D F E * H1 G1 G2 H2
+// (* is injected, G is copied, H is split)
+// A is implied.
+
+// Layout of the original image.
+const AddressRange B(100, 15);
+const AddressRange C(B.end(), 10);
+const AddressRange D(C.end(), 25);
+const AddressRange E(D.end(), 10);
+const AddressRange F(E.end(), 40);
+const AddressRange G(F.end(), 3);
+const AddressRange H(G.end(), 7);
+
+// Layout of the transformed image.
+const AddressRange Bt(100, 15);
+const AddressRange Dt(Bt.end(), 20); // D is shortened.
+const AddressRange Ft(Dt.end(), F.length);
+const AddressRange Et(Ft.end(), E.length);
+const AddressRange injected(Et.end(), 5);
+const AddressRange H1t(injected.end(), 4); // H is split.
+const AddressRange G1t(H1t.end(), G.length); // G is copied.
+const AddressRange G2t(G1t.end(), G.length); // G is copied.
+const AddressRange H2t(G2t.end(), 3); // H is split.
+
+class BuildImageMapTest : public testing::Test {
+ public:
+ static const DWORD kInvalidAddress = 0xFFFFFFFF;
+
+ void InitOmapData() {
+ omap_data.length_original = H.end();
+
+ // Build the OMAPTO vector (from transformed to original).
+ omap_data.omap_to.push_back(CreateOmap(Bt.rva, B.rva));
+ omap_data.omap_to.push_back(CreateOmap(Dt.rva, D.rva));
+ omap_data.omap_to.push_back(CreateOmap(Ft.rva, F.rva));
+ omap_data.omap_to.push_back(CreateOmap(Et.rva, E.rva));
+ omap_data.omap_to.push_back(CreateOmap(injected.rva, kInvalidAddress));
+ omap_data.omap_to.push_back(CreateOmap(H1t.rva, H.rva));
+ omap_data.omap_to.push_back(CreateOmap(G1t.rva, G.rva));
+ omap_data.omap_to.push_back(CreateOmap(G2t.rva, G.rva));
+ omap_data.omap_to.push_back(CreateOmap(H2t.rva, H.rva + H1t.length));
+ omap_data.omap_to.push_back(CreateOmap(H2t.end(), kInvalidAddress));
+
+ // Build the OMAPFROM vector (from original to transformed).
+ omap_data.omap_from.push_back(CreateOmap(B.rva, Bt.rva));
+ omap_data.omap_from.push_back(CreateOmap(C.rva, kInvalidAddress));
+ omap_data.omap_from.push_back(CreateOmap(D.rva, Dt.rva));
+ omap_data.omap_from.push_back(CreateOmap(E.rva, Et.rva));
+ omap_data.omap_from.push_back(CreateOmap(F.rva, Ft.rva));
+ omap_data.omap_from.push_back(CreateOmap(G.rva, G1t.rva));
+ omap_data.omap_from.push_back(CreateOmap(H.rva, H1t.rva));
+ omap_data.omap_from.push_back(CreateOmap(H.rva + H1t.length, H2t.rva));
+ omap_data.omap_from.push_back(CreateOmap(H.end(), kInvalidAddress));
+ }
+
+ OmapData omap_data;
+};
+
+} // namespace
+
+TEST_F(BuildImageMapTest, EmptyImageMapOnEmptyOmapData) {
+ ASSERT_EQ(0u, omap_data.omap_from.size());
+ ASSERT_EQ(0u, omap_data.omap_to.size());
+ ASSERT_EQ(0u, omap_data.length_original);
+
+ ImageMap image_map;
+ BuildImageMap(omap_data, &image_map);
+ EXPECT_EQ(0u, image_map.mapping.size());
+ EXPECT_EQ(0u, image_map.endpoint_index_map.size());
+}
+
+TEST_F(BuildImageMapTest, ImageMapIsCorrect) {
+ InitOmapData();
+ ASSERT_LE(0u, omap_data.omap_from.size());
+ ASSERT_LE(0u, omap_data.omap_to.size());
+ ASSERT_LE(0u, omap_data.length_original);
+
+ ImageMap image_map;
+ BuildImageMap(omap_data, &image_map);
+ EXPECT_LE(9u, image_map.mapping.size());
+ EXPECT_LE(9u, image_map.endpoint_index_map.size());
+
+ Mapping mapping;
+ mapping.push_back(CreateMappedRange(0, 0, B.rva, 0, 0));
+ // C is removed, and it originally comes immediately after B.
+ mapping.push_back(CreateMappedRange(B.rva, Bt.rva, B.length, 0, C.length));
+ // D is shortened by a length of 5.
+ mapping.push_back(CreateMappedRange(D.rva, Dt.rva, Dt.length, 0, 5));
+ // The injected content comes immediately after E in the transformed image.
+ mapping.push_back(CreateMappedRange(E.rva, Et.rva, E.length, injected.length,
+ 0));
+ mapping.push_back(CreateMappedRange(F.rva, Ft.rva, F.length, 0, 0));
+ // G is copied so creates two entries.
+ mapping.push_back(CreateMappedRange(G.rva, G1t.rva, G.length, 0, 0));
+ mapping.push_back(CreateMappedRange(G.rva, G2t.rva, G.length, 0, 0));
+ // H is split, so create two entries.
+ mapping.push_back(CreateMappedRange(H.rva, H1t.rva, H1t.length, 0, 0));
+ mapping.push_back(CreateMappedRange(H.rva + H1t.length, H2t.rva, H2t.length,
+ 0, 0));
+ EXPECT_THAT(mapping,
+ testing::ContainerEq(image_map.mapping));
+
+ EndpointIndexMap endpoint_index_map;
+ endpoint_index_map.push_back(CreateEndpointIndex(0, 0));
+ endpoint_index_map.push_back(CreateEndpointIndex(B.rva, 1));
+ endpoint_index_map.push_back(CreateEndpointIndex(D.rva, 2));
+ endpoint_index_map.push_back(CreateEndpointIndex(E.rva, 3));
+ endpoint_index_map.push_back(CreateEndpointIndex(F.rva, 4));
+ // G is duplicated so 2 ranges map back to it, hence the skip from 5 to 7.
+ endpoint_index_map.push_back(CreateEndpointIndex(G.rva, 5));
+ // H is split so we expect 2 endpoints to show up attributed to it.
+ endpoint_index_map.push_back(CreateEndpointIndex(H.rva, 7));
+ endpoint_index_map.push_back(CreateEndpointIndex(H.rva + H1t.length, 8));
+ endpoint_index_map.push_back(CreateEndpointIndex(H.end(), 9));
+ EXPECT_THAT(endpoint_index_map,
+ testing::ContainerEq(image_map.endpoint_index_map));
+}
+
+namespace {
+
+class MapAddressRangeTest : public BuildImageMapTest {
+ public:
+ typedef BuildImageMapTest Super;
+ virtual void SetUp() {
+ Super::SetUp();
+ InitOmapData();
+ BuildImageMap(omap_data, &image_map);
+ }
+
+ ImageMap image_map;
+
+ private:
+ using BuildImageMapTest::InitOmapData;
+ using BuildImageMapTest::omap_data;
+};
+
+} // namespace
+
+TEST_F(MapAddressRangeTest, EmptyImageMapReturnsIdentity) {
+ ImageMap im;
+ AddressRangeVector mapped_ranges;
+ AddressRange ar(0, 1024);
+ MapAddressRange(im, ar, &mapped_ranges);
+ EXPECT_EQ(1u, mapped_ranges.size());
+ EXPECT_EQ(ar, mapped_ranges[0]);
+}
+
+TEST_F(MapAddressRangeTest, MapOutOfImage) {
+ AddressRangeVector mapped_ranges;
+ MapAddressRange(image_map, AddressRange(H.end() + 10, 10), &mapped_ranges);
+ EXPECT_EQ(0u, mapped_ranges.size());
+}
+
+TEST_F(MapAddressRangeTest, MapIdentity) {
+ AddressRangeVector mapped_ranges;
+ MapAddressRange(image_map, B, &mapped_ranges);
+ EXPECT_EQ(1u, mapped_ranges.size());
+ EXPECT_THAT(mapped_ranges, testing::ElementsAre(B));
+}
+
+TEST_F(MapAddressRangeTest, MapReorderedContiguous) {
+ AddressRangeVector mapped_ranges;
+
+ AddressRange DEF(D.rva, F.end() - D.rva);
+ MapAddressRange(image_map, DEF, &mapped_ranges);
+ EXPECT_EQ(1u, mapped_ranges.size());
+
+ AddressRange DFEt(Dt.rva, Et.end() - Dt.rva);
+ EXPECT_THAT(mapped_ranges, testing::ElementsAre(DFEt));
+}
+
+TEST_F(MapAddressRangeTest, MapEmptySingle) {
+ AddressRangeVector mapped_ranges;
+ MapAddressRange(image_map, AddressRange(D.rva, 0), &mapped_ranges);
+ EXPECT_EQ(1u, mapped_ranges.size());
+ EXPECT_THAT(mapped_ranges, testing::ElementsAre(AddressRange(Dt.rva, 0)));
+}
+
+TEST_F(MapAddressRangeTest, MapEmptyCopied) {
+ AddressRangeVector mapped_ranges;
+ MapAddressRange(image_map, AddressRange(G.rva, 0), &mapped_ranges);
+ EXPECT_EQ(2u, mapped_ranges.size());
+ EXPECT_THAT(mapped_ranges, testing::ElementsAre(AddressRange(G1t.rva, 0),
+ AddressRange(G2t.rva, 0)));
+}
+
+TEST_F(MapAddressRangeTest, MapCopiedContiguous) {
+ AddressRangeVector mapped_ranges;
+ MapAddressRange(image_map, G, &mapped_ranges);
+ EXPECT_EQ(1u, mapped_ranges.size());
+ EXPECT_THAT(mapped_ranges, testing::ElementsAre(
+ AddressRange(G1t.rva, G2t.end() - G1t.rva)));
+}
+
+TEST_F(MapAddressRangeTest, MapSplitDiscontiguous) {
+ AddressRangeVector mapped_ranges;
+ MapAddressRange(image_map, H, &mapped_ranges);
+ EXPECT_EQ(2u, mapped_ranges.size());
+ EXPECT_THAT(mapped_ranges, testing::ElementsAre(H1t, H2t));
+}
+
+TEST_F(MapAddressRangeTest, MapInjected) {
+ AddressRangeVector mapped_ranges;
+
+ AddressRange EFGH(E.rva, H.end() - E.rva);
+ MapAddressRange(image_map, EFGH, &mapped_ranges);
+ EXPECT_EQ(1u, mapped_ranges.size());
+
+ AddressRange FEHGGHt(Ft.rva, H2t.end() - Ft.rva);
+ EXPECT_THAT(mapped_ranges, testing::ElementsAre(FEHGGHt));
+}
+
+TEST_F(MapAddressRangeTest, MapRemovedEntirely) {
+ AddressRangeVector mapped_ranges;
+ MapAddressRange(image_map, C, &mapped_ranges);
+ EXPECT_EQ(0u, mapped_ranges.size());
+}
+
+TEST_F(MapAddressRangeTest, MapRemovedPartly) {
+ AddressRangeVector mapped_ranges;
+ MapAddressRange(image_map, D, &mapped_ranges);
+ EXPECT_EQ(1u, mapped_ranges.size());
+ EXPECT_THAT(mapped_ranges, testing::ElementsAre(Dt));
+}
+
+TEST_F(MapAddressRangeTest, MapFull) {
+ AddressRangeVector mapped_ranges;
+
+ AddressRange AH(0, H.end());
+ MapAddressRange(image_map, AH, &mapped_ranges);
+ EXPECT_EQ(1u, mapped_ranges.size());
+
+ AddressRange AHt(0, H2t.end());
+ EXPECT_THAT(mapped_ranges, testing::ElementsAre(AHt));
+}
+
+} // namespace google_breakpad
diff --git a/src/common/windows/pdb_source_line_writer.cc b/src/common/windows/pdb_source_line_writer.cc
index 4030a2e9..800c316f 100644
--- a/src/common/windows/pdb_source_line_writer.cc
+++ b/src/common/windows/pdb_source_line_writer.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2006, Google Inc.
-// All rights reserved.
+// Copyright 2006 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -40,6 +39,7 @@
#include <algorithm>
#include <limits>
#include <map>
+#include <memory>
#include <set>
#include <utility>
@@ -58,6 +58,8 @@ namespace google_breakpad {
namespace {
+using std::set;
+using std::unique_ptr;
using std::vector;
// The symbol (among possibly many) selected to represent an rva.
@@ -120,7 +122,7 @@ bool SymbolsMatch(IDiaSymbol* a, IDiaSymbol* b) {
return a_section == b_section && a_offset == b_offset;
}
-bool CreateDiaDataSourceInstance(CComPtr<IDiaDataSource> &data_source) {
+bool CreateDiaDataSourceInstance(CComPtr<IDiaDataSource>& data_source) {
if (SUCCEEDED(data_source.CoCreateInstance(CLSID_DiaSource))) {
return true;
}
@@ -134,7 +136,7 @@ bool CreateDiaDataSourceInstance(CComPtr<IDiaDataSource> &data_source) {
// We can try loading the DLL corresponding to the #included DIA SDK, but
// the DIA headers don't provide a version. Lets try to figure out which DIA
// version we're compiling against by comparing CLSIDs.
- const wchar_t *msdia_dll = nullptr;
+ const wchar_t* msdia_dll = nullptr;
if (CLSID_DiaSource == _uuidof(DiaSource100)) {
msdia_dll = L"msdia100.dll";
} else if (CLSID_DiaSource == _uuidof(DiaSource110)) {
@@ -147,23 +149,261 @@ bool CreateDiaDataSourceInstance(CComPtr<IDiaDataSource> &data_source) {
if (msdia_dll &&
SUCCEEDED(NoRegCoCreate(msdia_dll, CLSID_DiaSource, IID_IDiaDataSource,
- reinterpret_cast<void **>(&data_source)))) {
+ reinterpret_cast<void**>(&data_source)))) {
return true;
}
return false;
}
+const DWORD kUndecorateOptions = UNDNAME_NO_MS_KEYWORDS |
+ UNDNAME_NO_FUNCTION_RETURNS |
+ UNDNAME_NO_ALLOCATION_MODEL |
+ UNDNAME_NO_ALLOCATION_LANGUAGE |
+ UNDNAME_NO_THISTYPE |
+ UNDNAME_NO_ACCESS_SPECIFIERS |
+ UNDNAME_NO_THROW_SIGNATURES |
+ UNDNAME_NO_MEMBER_TYPE |
+ UNDNAME_NO_RETURN_UDT_MODEL |
+ UNDNAME_NO_ECSU;
+
+#define arraysize(f) (sizeof(f) / sizeof(*f))
+
+void StripLlvmSuffixAndUndecorate(BSTR* name) {
+ // LLVM sometimes puts a suffix on symbols to give them a globally unique
+ // name. The suffix is either some string preceded by a period (like in the
+ // Itanium ABI; also on Windows this is safe since periods are otherwise
+ // never part of mangled names), or a dollar sign followed by a 32-char hex
+ // string (this should go away in future LLVM versions). Strip such suffixes
+ // and try demangling again.
+ //
+ //
+ // Example symbol names with such suffixes:
+ //
+ // ?foo@@YAXXZ$5520c83448162c04f2b239db4b5a2c61
+ // ?foo@@YAXXZ.llvm.13040715209719948753
+
+ if (**name != L'?')
+ return; // The name is already demangled.
+
+ for (size_t i = 0, len = wcslen(*name); i < len; i++) {
+ wchar_t c = (*name)[i];
+
+ if (c == L'.' || (c == L'$' && len - i == 32 + 1)) {
+ (*name)[i] = L'\0';
+ wchar_t undecorated[1024];
+ DWORD res = UnDecorateSymbolNameW(*name, undecorated,
+ arraysize(undecorated),
+ kUndecorateOptions);
+ if (res == 0 || undecorated[0] == L'?') {
+ // Demangling failed; restore the symbol name and return.
+ (*name)[i] = c;
+ return;
+ }
+
+ SysFreeString(*name);
+ *name = SysAllocString(undecorated);
+ return;
+ }
+ }
+}
+
+// Prints the error message related to the error code as seen in
+// Microsoft's MSVS documentation for loadDataFromPdb and loadDataForExe.
+void PrintOpenError(HRESULT hr, const char* fn_name, const wchar_t* file) {
+ switch (hr) {
+ case E_PDB_NOT_FOUND:
+ fprintf(stderr, "%s: Failed to open %ws, or the file has an "
+ "invalid format.\n", fn_name, file);
+ break;
+ case E_PDB_FORMAT:
+ fprintf(stderr, "%s: Attempted to access %ws with an obsolete "
+ "format.\n", fn_name, file);
+ break;
+ case E_PDB_INVALID_SIG:
+ fprintf(stderr, "%s: Signature does not match for %ws.\n", fn_name,
+ file);
+ break;
+ case E_PDB_INVALID_AGE:
+ fprintf(stderr, "%s: Age does not match for %ws.\n", fn_name, file);
+ break;
+ case E_INVALIDARG:
+ fprintf(stderr, "%s: Invalid parameter for %ws.\n", fn_name, file);
+ break;
+ case E_UNEXPECTED:
+ fprintf(stderr, "%s: Data source has already been prepared for %ws.\n",
+ fn_name, file);
+ break;
+ default:
+ fprintf(stderr, "%s: Unexpected error 0x%lx, file: %ws.\n",
+ fn_name, hr, file);
+ break;
+ }
+}
+
} // namespace
-PDBSourceLineWriter::PDBSourceLineWriter() : output_(NULL) {
+PDBSourceLineWriter::Inline::Inline(int inline_nest_level)
+ : inline_nest_level_(inline_nest_level) {}
+
+void PDBSourceLineWriter::Inline::SetOriginId(int origin_id) {
+ origin_id_ = origin_id;
+}
+
+void PDBSourceLineWriter::Inline::ExtendRanges(const Line& line) {
+ if (ranges_.empty()) {
+ ranges_[line.rva] = line.length;
+ return;
+ }
+ auto iter = ranges_.lower_bound(line.rva);
+ // There is no overlap if this function is called with inlinee lines from
+ // the same callsite.
+ if (iter == ranges_.begin()) {
+ return;
+ }
+ if (line.rva + line.length == iter->first) {
+ // If they are connected, merge their ranges into one.
+ DWORD length = line.length + iter->second;
+ ranges_.erase(iter);
+ ranges_[line.rva] = length;
+ } else {
+ --iter;
+ if (iter->first + iter->second == line.rva) {
+ ranges_[iter->first] = iter->second + line.length;
+ } else {
+ ranges_[line.rva] = line.length;
+ }
+ }
+}
+
+void PDBSourceLineWriter::Inline::SetCallSiteLine(DWORD call_site_line) {
+ call_site_line_ = call_site_line;
}
+void PDBSourceLineWriter::Inline::SetCallSiteFileId(DWORD call_site_file_id) {
+ call_site_file_id_ = call_site_file_id;
+}
+
+void PDBSourceLineWriter::Inline::SetChildInlines(
+ vector<unique_ptr<Inline>> child_inlines) {
+ child_inlines_ = std::move(child_inlines);
+}
+
+void PDBSourceLineWriter::Inline::Print(FILE* output) const {
+ // Ignore INLINE record that doesn't have any range.
+ if (ranges_.empty())
+ return;
+ fprintf(output, "INLINE %d %lu %lu %d", inline_nest_level_, call_site_line_,
+ call_site_file_id_, origin_id_);
+ for (const auto& r : ranges_) {
+ fprintf(output, " %lx %lx", r.first, r.second);
+ }
+ fprintf(output, "\n");
+ for (const unique_ptr<Inline>& in : child_inlines_) {
+ in->Print(output);
+ }
+}
+
+const PDBSourceLineWriter::Line* PDBSourceLineWriter::Lines::GetLine(
+ DWORD rva) const {
+ auto iter = line_map_.find(rva);
+ if (iter == line_map_.end()) {
+ // If not found exact rva, check if it's within any range.
+ iter = line_map_.lower_bound(rva);
+ if (iter == line_map_.begin())
+ return nullptr;
+ --iter;
+ auto l = iter->second;
+ // This happens when there is no top level lines cover this rva (e.g. empty
+ // lines found for the function). Then we don't know the call site line
+ // number for this inlined function.
+ if (rva >= l.rva + l.length)
+ return nullptr;
+ }
+ return &iter->second;
+}
+
+DWORD PDBSourceLineWriter::Lines::GetLineNum(DWORD rva) const {
+ const Line* line = GetLine(rva);
+ return line ? line->line_num : 0;
+}
+
+DWORD PDBSourceLineWriter::Lines::GetFileId(DWORD rva) const {
+ const Line* line = GetLine(rva);
+ return line ? line->file_id : 0;
+}
+
+void PDBSourceLineWriter::Lines::AddLine(const Line& line) {
+ if (line_map_.empty()) {
+ line_map_[line.rva] = line;
+ return;
+ }
+
+ // Given an existing line in line_map_, remove it from line_map_ if it
+ // overlaps with the line and add a new line for the non-overlap range. Return
+ // true if there is an overlap.
+ auto intercept = [&](Line old_line) {
+ DWORD end = old_line.rva + old_line.length;
+ // No overlap.
+ if (old_line.rva >= line.rva + line.length || line.rva >= end)
+ return false;
+ // old_line is within the line.
+ if (old_line.rva >= line.rva && end <= line.rva + line.length) {
+ line_map_.erase(old_line.rva);
+ return true;
+ }
+ // Then there is a overlap.
+ if (old_line.rva < line.rva) {
+ old_line.length -= end - line.rva;
+ if (end > line.rva + line.length) {
+ Line new_line = old_line;
+ new_line.rva = line.rva + line.length;
+ new_line.length = end - new_line.rva;
+ line_map_[new_line.rva] = new_line;
+ }
+ } else {
+ line_map_.erase(old_line.rva);
+ old_line.length -= line.rva + line.length - old_line.rva;
+ old_line.rva = line.rva + line.length;
+ }
+ line_map_[old_line.rva] = old_line;
+ return true;
+ };
+
+ bool is_intercept;
+ // Use a loop in cases that there are multiple lines within the given line.
+ do {
+ auto iter = line_map_.lower_bound(line.rva);
+ if (iter == line_map_.end()) {
+ if (!line_map_.empty()) {
+ --iter;
+ intercept(iter->second);
+ }
+ break;
+ }
+ is_intercept = false;
+ if (iter != line_map_.begin()) {
+ // Check if the given line overlaps a line with smaller in the map.
+ auto prev = line_map_.lower_bound(line.rva);
+ --prev;
+ is_intercept = intercept(prev->second);
+ }
+ // Check if the given line overlaps a line with greater or equal rva in the
+ // map. Using operator |= here since it's possible that there are multiple
+ // lines with greater rva in the map overlap with the given line.
+ is_intercept |= intercept(iter->second);
+ } while (is_intercept);
+ line_map_[line.rva] = line;
+}
+
+PDBSourceLineWriter::PDBSourceLineWriter(bool handle_inline)
+ : output_(NULL), handle_inline_(handle_inline) {}
+
PDBSourceLineWriter::~PDBSourceLineWriter() {
Close();
}
-bool PDBSourceLineWriter::SetCodeFile(const wstring &exe_file) {
+bool PDBSourceLineWriter::SetCodeFile(const wstring& exe_file) {
if (code_file_.empty()) {
code_file_ = exe_file;
return true;
@@ -173,7 +413,7 @@ bool PDBSourceLineWriter::SetCodeFile(const wstring &exe_file) {
return exe_file == code_file_;
}
-bool PDBSourceLineWriter::Open(const wstring &file, FileFormat format) {
+bool PDBSourceLineWriter::Open(const wstring& file, FileFormat format) {
Close();
code_file_.clear();
@@ -192,25 +432,32 @@ bool PDBSourceLineWriter::Open(const wstring &file, FileFormat format) {
return false;
}
+ HRESULT from_pdb_result;
+ HRESULT for_exe_result;
+ const wchar_t* file_name = file.c_str();
switch (format) {
case PDB_FILE:
- if (FAILED(data_source->loadDataFromPdb(file.c_str()))) {
- fprintf(stderr, "loadDataFromPdb failed for %ws\n", file.c_str());
+ from_pdb_result = data_source->loadDataFromPdb(file_name);
+ if (FAILED(from_pdb_result)) {
+ PrintOpenError(from_pdb_result, "loadDataFromPdb", file_name);
return false;
}
break;
case EXE_FILE:
- if (FAILED(data_source->loadDataForExe(file.c_str(), NULL, NULL))) {
- fprintf(stderr, "loadDataForExe failed for %ws\n", file.c_str());
+ for_exe_result = data_source->loadDataForExe(file_name, NULL, NULL);
+ if (FAILED(for_exe_result)) {
+ PrintOpenError(for_exe_result, "loadDataForExe", file_name);
return false;
}
code_file_ = file;
break;
case ANY_FILE:
- if (FAILED(data_source->loadDataFromPdb(file.c_str()))) {
- if (FAILED(data_source->loadDataForExe(file.c_str(), NULL, NULL))) {
- fprintf(stderr, "loadDataForPdb and loadDataFromExe failed for %ws\n",
- file.c_str());
+ from_pdb_result = data_source->loadDataFromPdb(file_name);
+ if (FAILED(from_pdb_result)) {
+ for_exe_result = data_source->loadDataForExe(file_name, NULL, NULL);
+ if (FAILED(for_exe_result)) {
+ PrintOpenError(from_pdb_result, "loadDataFromPdb", file_name);
+ PrintOpenError(for_exe_result, "loadDataForExe", file_name);
return false;
}
code_file_ = file;
@@ -228,52 +475,65 @@ bool PDBSourceLineWriter::Open(const wstring &file, FileFormat format) {
return true;
}
-bool PDBSourceLineWriter::PrintLines(IDiaEnumLineNumbers *lines) {
- // The line number format is:
- // <rva> <line number> <source file id>
- CComPtr<IDiaLineNumber> line;
- ULONG count;
+bool PDBSourceLineWriter::GetLine(IDiaLineNumber* dia_line, Line* line) const {
+ if (FAILED(dia_line->get_relativeVirtualAddress(&line->rva))) {
+ fprintf(stderr, "failed to get line rva\n");
+ return false;
+ }
- while (SUCCEEDED(lines->Next(1, &line, &count)) && count == 1) {
- DWORD rva;
- if (FAILED(line->get_relativeVirtualAddress(&rva))) {
- fprintf(stderr, "failed to get line rva\n");
- return false;
- }
+ if (FAILED(dia_line->get_length(&line->length))) {
+ fprintf(stderr, "failed to get line code length\n");
+ return false;
+ }
- DWORD length;
- if (FAILED(line->get_length(&length))) {
- fprintf(stderr, "failed to get line code length\n");
- return false;
- }
+ DWORD dia_source_id;
+ if (FAILED(dia_line->get_sourceFileId(&dia_source_id))) {
+ fprintf(stderr, "failed to get line source file id\n");
+ return false;
+ }
+ // duplicate file names are coalesced to share one ID
+ line->file_id = GetRealFileID(dia_source_id);
- DWORD dia_source_id;
- if (FAILED(line->get_sourceFileId(&dia_source_id))) {
- fprintf(stderr, "failed to get line source file id\n");
- return false;
- }
- // duplicate file names are coalesced to share one ID
- DWORD source_id = GetRealFileID(dia_source_id);
+ if (FAILED(dia_line->get_lineNumber(&line->line_num))) {
+ fprintf(stderr, "failed to get line number\n");
+ return false;
+ }
+ return true;
+}
- DWORD line_num;
- if (FAILED(line->get_lineNumber(&line_num))) {
- fprintf(stderr, "failed to get line number\n");
+bool PDBSourceLineWriter::GetLines(IDiaEnumLineNumbers* lines,
+ Lines* line_list) const {
+ CComPtr<IDiaLineNumber> line;
+ ULONG count;
+
+ while (SUCCEEDED(lines->Next(1, &line, &count)) && count == 1) {
+ Line l;
+ if (!GetLine(line, &l))
return false;
- }
+ // Silently ignore zero-length lines.
+ if (l.length != 0)
+ line_list->AddLine(l);
+ line.Release();
+ }
+ return true;
+}
+void PDBSourceLineWriter::PrintLines(const Lines& lines) const {
+ // The line number format is:
+ // <rva> <line number> <source file id>
+ for (const auto& kv : lines.GetLineMap()) {
+ const Line& l = kv.second;
AddressRangeVector ranges;
- MapAddressRange(image_map_, AddressRange(rva, length), &ranges);
- for (size_t i = 0; i < ranges.size(); ++i) {
- fprintf(output_, "%lx %lx %lu %lu\n", ranges[i].rva, ranges[i].length,
- line_num, source_id);
+ MapAddressRange(image_map_, AddressRange(l.rva, l.length), &ranges);
+ for (auto& range : ranges) {
+ fprintf(output_, "%lx %lx %lu %lu\n", range.rva, range.length, l.line_num,
+ l.file_id);
}
- line.Release();
}
- return true;
}
-bool PDBSourceLineWriter::PrintFunction(IDiaSymbol *function,
- IDiaSymbol *block,
+bool PDBSourceLineWriter::PrintFunction(IDiaSymbol* function,
+ IDiaSymbol* block,
bool has_multiple_symbols) {
// The function format is:
// FUNC <address> <length> <param_stack_size> <function>
@@ -320,9 +580,20 @@ bool PDBSourceLineWriter::PrintFunction(IDiaSymbol *function,
return false;
}
- if (!PrintLines(lines)) {
+ // Get top level lines first, which later may be split into multiple smaller
+ // lines if any inline exists in their ranges if we want to handle inline.
+ Lines line_list;
+ if (!GetLines(lines, &line_list)) {
return false;
}
+ if (handle_inline_) {
+ vector<unique_ptr<Inline>> inlines;
+ if (!GetInlines(block, &line_list, 0, &inlines)) {
+ return false;
+ }
+ PrintInlines(inlines);
+ }
+ PrintLines(line_list);
return true;
}
@@ -340,6 +611,10 @@ bool PDBSourceLineWriter::PrintSourceFiles() {
return false;
}
+ // Print a dummy file with id equals 0 to represent unknown file, because
+ // inline records might have unknown call site.
+ fwprintf(output_, L"FILE %d unknown file\n", 0);
+
CComPtr<IDiaSymbol> compiland;
ULONG count;
while (SUCCEEDED(compilands->Next(1, &compiland, &count)) && count == 1) {
@@ -503,6 +778,97 @@ bool PDBSourceLineWriter::PrintFunctions() {
return true;
}
+void PDBSourceLineWriter::PrintInlineOrigins() const {
+ struct OriginCompare {
+ bool operator()(const InlineOrigin lhs, const InlineOrigin rhs) const {
+ return lhs.id < rhs.id;
+ }
+ };
+ set<InlineOrigin, OriginCompare> origins;
+ // Sort by origin id.
+ for (auto const& origin : inline_origins_)
+ origins.insert(origin.second);
+ for (auto o : origins) {
+ fprintf(output_, "INLINE_ORIGIN %d %ls\n", o.id, o.name.c_str());
+ }
+}
+
+bool PDBSourceLineWriter::GetInlines(IDiaSymbol* block,
+ Lines* line_list,
+ int inline_nest_level,
+ vector<unique_ptr<Inline>>* inlines) {
+ CComPtr<IDiaEnumSymbols> inline_callsites;
+ if (FAILED(block->findChildrenEx(SymTagInlineSite, nullptr, nsNone,
+ &inline_callsites))) {
+ return false;
+ }
+ ULONG count;
+ CComPtr<IDiaSymbol> callsite;
+ while (SUCCEEDED(inline_callsites->Next(1, &callsite, &count)) &&
+ count == 1) {
+ unique_ptr<Inline> new_inline(new Inline(inline_nest_level));
+ CComPtr<IDiaEnumLineNumbers> lines;
+ // All inlinee lines have the same file id.
+ DWORD file_id = 0;
+ DWORD call_site_line = 0;
+ if (FAILED(session_->findInlineeLines(callsite, &lines))) {
+ return false;
+ }
+ CComPtr<IDiaLineNumber> dia_line;
+ while (SUCCEEDED(lines->Next(1, &dia_line, &count)) && count == 1) {
+ Line line;
+ if (!GetLine(dia_line, &line)) {
+ return false;
+ }
+ // Silently ignore zero-length lines.
+ if (line.length != 0) {
+ // Use the first line num and file id at rva as this inline's call site
+ // line number, because after adding lines it may be changed to inner
+ // line number and inner file id.
+ if (call_site_line == 0)
+ call_site_line = line_list->GetLineNum(line.rva);
+ if (file_id == 0)
+ file_id = line_list->GetFileId(line.rva);
+ line_list->AddLine(line);
+ new_inline->ExtendRanges(line);
+ }
+ dia_line.Release();
+ }
+ BSTR name;
+ callsite->get_name(&name);
+ if (SysStringLen(name) == 0) {
+ name = SysAllocString(L"<name omitted>");
+ }
+ auto iter = inline_origins_.find(name);
+ if (iter == inline_origins_.end()) {
+ InlineOrigin origin;
+ origin.id = inline_origins_.size();
+ origin.name = name;
+ inline_origins_[name] = origin;
+ }
+ new_inline->SetOriginId(inline_origins_[name].id);
+ new_inline->SetCallSiteLine(call_site_line);
+ new_inline->SetCallSiteFileId(file_id);
+ // Go to next level.
+ vector<unique_ptr<Inline>> child_inlines;
+ if (!GetInlines(callsite, line_list, inline_nest_level + 1,
+ &child_inlines)) {
+ return false;
+ }
+ new_inline->SetChildInlines(std::move(child_inlines));
+ inlines->push_back(std::move(new_inline));
+ callsite.Release();
+ }
+ return true;
+}
+
+void PDBSourceLineWriter::PrintInlines(
+ const vector<unique_ptr<Inline>>& inlines) const {
+ for (const unique_ptr<Inline>& in : inlines) {
+ in->Print(output_);
+ }
+}
+
#undef max
bool PDBSourceLineWriter::PrintFrameDataUsingPDB() {
@@ -673,13 +1039,11 @@ bool PDBSourceLineWriter::PrintFrameData() {
PDBModuleInfo info;
if (GetModuleInfo(&info) && info.cpu == L"x86_64") {
return PrintFrameDataUsingEXE();
- } else {
- return PrintFrameDataUsingPDB();
}
- return false;
+ return PrintFrameDataUsingPDB();
}
-bool PDBSourceLineWriter::PrintCodePublicSymbol(IDiaSymbol *symbol,
+bool PDBSourceLineWriter::PrintCodePublicSymbol(IDiaSymbol* symbol,
bool has_multiple_symbols) {
BOOL is_code;
if (FAILED(symbol->get_code(&is_code))) {
@@ -781,9 +1145,9 @@ bool PDBSourceLineWriter::PrintPEInfo() {
// and scanf families, which are not as strict about input and in some cases
// don't provide a good way for the caller to determine if a conversion was
// successful.
-static bool wcstol_positive_strict(wchar_t *string, int *result) {
+static bool wcstol_positive_strict(wchar_t* string, int* result) {
int value = 0;
- for (wchar_t *c = string; *c != '\0'; ++c) {
+ for (wchar_t* c = string; *c != '\0'; ++c) {
int last_value = value;
value *= 10;
// Detect overflow.
@@ -821,7 +1185,7 @@ bool PDBSourceLineWriter::FindPEFile() {
wstring file(symbols_file);
// Look for an EXE or DLL file.
- const wchar_t *extensions[] = { L"exe", L"dll" };
+ const wchar_t* extensions[] = { L"exe", L"dll" };
for (size_t i = 0; i < sizeof(extensions) / sizeof(extensions[0]); i++) {
size_t dot_pos = file.find_last_of(L".");
if (dot_pos != wstring::npos) {
@@ -839,23 +1203,13 @@ bool PDBSourceLineWriter::FindPEFile() {
}
// static
-bool PDBSourceLineWriter::GetSymbolFunctionName(IDiaSymbol *function,
- BSTR *name,
- int *stack_param_size) {
+bool PDBSourceLineWriter::GetSymbolFunctionName(IDiaSymbol* function,
+ BSTR* name,
+ int* stack_param_size) {
*stack_param_size = -1;
- const DWORD undecorate_options = UNDNAME_NO_MS_KEYWORDS |
- UNDNAME_NO_FUNCTION_RETURNS |
- UNDNAME_NO_ALLOCATION_MODEL |
- UNDNAME_NO_ALLOCATION_LANGUAGE |
- UNDNAME_NO_THISTYPE |
- UNDNAME_NO_ACCESS_SPECIFIERS |
- UNDNAME_NO_THROW_SIGNATURES |
- UNDNAME_NO_MEMBER_TYPE |
- UNDNAME_NO_RETURN_UDT_MODEL |
- UNDNAME_NO_ECSU;
// Use get_undecoratedNameEx to get readable C++ names with arguments.
- if (function->get_undecoratedNameEx(undecorate_options, name) != S_OK) {
+ if (function->get_undecoratedNameEx(kUndecorateOptions, name) != S_OK) {
if (function->get_name(name) != S_OK) {
fprintf(stderr, "failed to get function name\n");
return false;
@@ -879,15 +1233,17 @@ bool PDBSourceLineWriter::GetSymbolFunctionName(IDiaSymbol *function,
// all of the parameter and return type information may not be included in
// the name string.
} else {
+ StripLlvmSuffixAndUndecorate(name);
+
// C++ uses a bogus "void" argument for functions and methods that don't
// take any parameters. Take it out of the undecorated name because it's
// ugly and unnecessary.
- const wchar_t *replace_string = L"(void)";
+ const wchar_t* replace_string = L"(void)";
const size_t replace_length = wcslen(replace_string);
- const wchar_t *replacement_string = L"()";
+ const wchar_t* replacement_string = L"()";
size_t length = wcslen(*name);
if (length >= replace_length) {
- wchar_t *name_end = *name + length - replace_length;
+ wchar_t* name_end = *name + length - replace_length;
if (wcscmp(name_end, replace_string) == 0) {
WindowsStringUtils::safe_wcscpy(name_end, replace_length,
replacement_string);
@@ -903,7 +1259,7 @@ bool PDBSourceLineWriter::GetSymbolFunctionName(IDiaSymbol *function,
// whether the undecorated name contains any ':' or '(' characters.
if (!wcschr(*name, ':') && !wcschr(*name, '(') &&
(*name[0] == '_' || *name[0] == '@')) {
- wchar_t *last_at = wcsrchr(*name + 1, '@');
+ wchar_t* last_at = wcsrchr(*name + 1, '@');
if (last_at && wcstol_positive_strict(last_at + 1, stack_param_size)) {
// If this function adheres to the fastcall convention, it accepts up
// to the first 8 bytes of parameters in registers (%ecx and %edx).
@@ -935,7 +1291,7 @@ bool PDBSourceLineWriter::GetSymbolFunctionName(IDiaSymbol *function,
}
// static
-int PDBSourceLineWriter::GetFunctionStackParamSize(IDiaSymbol *function) {
+int PDBSourceLineWriter::GetFunctionStackParamSize(IDiaSymbol* function) {
// This implementation is highly x86-specific.
// Gather the symbols corresponding to data.
@@ -1050,7 +1406,7 @@ next_child:
return param_size;
}
-bool PDBSourceLineWriter::WriteSymbols(FILE *symbol_file) {
+bool PDBSourceLineWriter::WriteSymbols(FILE* symbol_file) {
output_ = symbol_file;
// Load the OMAP information, and disable auto-translation of addresses in
@@ -1063,10 +1419,8 @@ bool PDBSourceLineWriter::WriteSymbols(FILE *symbol_file) {
bool ret = PrintPDBInfo();
// This is not a critical piece of the symbol file.
PrintPEInfo();
- ret = ret &&
- PrintSourceFiles() &&
- PrintFunctions() &&
- PrintFrameData();
+ ret = ret && PrintSourceFiles() && PrintFunctions() && PrintFrameData();
+ PrintInlineOrigins();
output_ = NULL;
return ret;
@@ -1078,7 +1432,7 @@ void PDBSourceLineWriter::Close() {
}
}
-bool PDBSourceLineWriter::GetModuleInfo(PDBModuleInfo *info) {
+bool PDBSourceLineWriter::GetModuleInfo(PDBModuleInfo* info) {
if (!info) {
return false;
}
@@ -1143,7 +1497,7 @@ bool PDBSourceLineWriter::GetModuleInfo(PDBModuleInfo *info) {
return true;
}
-bool PDBSourceLineWriter::GetPEInfo(PEModuleInfo *info) {
+bool PDBSourceLineWriter::GetPEInfo(PEModuleInfo* info) {
if (!info) {
return false;
}
@@ -1156,7 +1510,7 @@ bool PDBSourceLineWriter::GetPEInfo(PEModuleInfo *info) {
return ReadPEInfo(code_file_, info);
}
-bool PDBSourceLineWriter::UsesGUID(bool *uses_guid) {
+bool PDBSourceLineWriter::UsesGUID(bool* uses_guid) {
if (!uses_guid)
return false;
diff --git a/src/common/windows/pdb_source_line_writer.h b/src/common/windows/pdb_source_line_writer.h
index c0adf29f..8c74e2ca 100644
--- a/src/common/windows/pdb_source_line_writer.h
+++ b/src/common/windows/pdb_source_line_writer.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2006, Google Inc.
-// All rights reserved.
+// Copyright 2006 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -35,8 +34,11 @@
#include <atlcomcli.h>
+#include <map>
+#include <memory>
#include <string>
#include <unordered_map>
+#include <vector>
#include "common/windows/module_info.h"
#include "common/windows/omap.h"
@@ -47,6 +49,8 @@ struct IDiaSymbol;
namespace google_breakpad {
+using std::map;
+using std::vector;
using std::wstring;
using std::unordered_map;
@@ -58,14 +62,14 @@ class PDBSourceLineWriter {
ANY_FILE // try PDB_FILE and then EXE_FILE
};
- explicit PDBSourceLineWriter();
+ explicit PDBSourceLineWriter(bool handle_inline = false);
~PDBSourceLineWriter();
// Opens the given file. For executable files, the corresponding pdb
// file must be available; Open will be if it is not.
// If there is already a pdb file open, it is automatically closed.
// Returns true on success.
- bool Open(const wstring &file, FileFormat format);
+ bool Open(const wstring& file, FileFormat format);
// Closes the current pdb file and its associated resources.
void Close();
@@ -77,7 +81,7 @@ class PDBSourceLineWriter {
// file and it must be called after Open() and before WriteMap().
// If Open() was called for an executable file, then it is an error to call
// SetCodeFile() with a different file path and it will return false.
- bool SetCodeFile(const wstring &exe_file);
+ bool SetCodeFile(const wstring& exe_file);
// Writes a Breakpad symbol file from the current pdb file to |symbol_file|.
// Returns true on success.
@@ -99,9 +103,110 @@ class PDBSourceLineWriter {
bool UsesGUID(bool *uses_guid);
private:
- // Outputs the line/address pairs for each line in the enumerator.
+ // InlineOrigin represents INLINE_ORIGIN record in a symbol file. It's an
+ // inlined function.
+ struct InlineOrigin {
+ // The unique id for an InlineOrigin.
+ int id;
+ // The name of the inlined function.
+ wstring name;
+ };
+
+ // Line represents LINE record in a symbol file. It represents a source code
+ // line.
+ struct Line {
+ // The relative address of a line.
+ DWORD rva;
+ // The number bytes this line has.
+ DWORD length;
+ // The source line number.
+ DWORD line_num;
+ // The source file id where the source line is located at.
+ DWORD file_id;
+ };
+
+ // Inline represents INLINE record in a symbol file.
+ class Inline {
+ public:
+ explicit Inline(int inline_nest_level);
+
+ void SetOriginId(int origin_id);
+
+ // Adding inlinee line's range into ranges. If line is adjacent with any
+ // existing lines, extend the range. Otherwise, add line as a new range.
+ void ExtendRanges(const Line& line);
+
+ void SetCallSiteLine(DWORD call_site_line);
+
+ void SetCallSiteFileId(DWORD call_site_file_id);
+
+ void SetChildInlines(std::vector<std::unique_ptr<Inline>> child_inlines);
+
+ void Print(FILE* output) const;
+
+ private:
+ // The nest level of this inline record.
+ int inline_nest_level_;
+ // The source line number at where this inlined function is called.
+ DWORD call_site_line_ = 0;
+ // The call site file id at where this inlined function is called.
+ DWORD call_site_file_id_ = 0;
+ // The id used for referring to an InlineOrigin.
+ int origin_id_ = 0;
+ // A map from rva to length. This is the address ranges covered by this
+ // Inline.
+ map<DWORD, DWORD> ranges_;
+ // The list of direct Inlines inlined inside this Inline.
+ vector<std::unique_ptr<Inline>> child_inlines_;
+ };
+
+ // Lines represents a map of lines inside a function with rva as the key.
+ // AddLine function adds a line into the map and ensures that there is no
+ // overlap between any two lines in the map.
+ class Lines {
+ public:
+ const map<DWORD, Line>& GetLineMap() const { return line_map_; }
+
+ // Finds the line from line_map_ that contains the given rva returns its
+ // line_num. If not found, return 0.
+ DWORD GetLineNum(DWORD rva) const;
+
+ // Finds the line from line_map_ that contains the given rva returns its
+ // file_id. If not found, return 0.
+ DWORD GetFileId(DWORD rva) const;
+
+ // Add the `line` into line_map_. If the `line` overlaps with existing
+ // lines, truncate the existing lines and add the given line. It ensures
+ // that all lines in line_map_ do not overlap with each other. For example,
+ // suppose there is a line A in the map and we call AddLine with Line B.
+ // Line A: rva: 100, length: 20, line_num: 10, file_id: 1
+ // Line B: rva: 105, length: 10, line_num: 4, file_id: 2
+ // After calling AddLine with Line B, we will have the following lines:
+ // Line 1: rva: 100, length: 5, line_num: 10, file_id: 1
+ // Line 2: rva: 105, length: 10, line_num: 4, file_id: 2
+ // Line 3: rva: 115, length: 5, line_num: 10, file_id: 1
+ void AddLine(const Line& line);
+
+ private:
+ // Finds the line from line_map_ that contains the given rva. If not found,
+ // return nullptr.
+ const Line* GetLine(DWORD rva) const;
+ // The key is rva. AddLine function ensures that any two lines in the map do
+ // not overlap.
+ map<DWORD, Line> line_map_;
+ };
+
+ // Construct Line from IDiaLineNumber. The output Line is stored at line.
+ // Return true on success.
+ bool GetLine(IDiaLineNumber* dia_line, Line* line) const;
+
+ // Construct Lines from IDiaEnumLineNumbers. The list of Lines are stored at
+ // line_list.
// Returns true on success.
- bool PrintLines(IDiaEnumLineNumbers *lines);
+ bool GetLines(IDiaEnumLineNumbers* lines, Lines* line_list) const;
+
+ // Outputs the line/address pairs for each line in the enumerator.
+ void PrintLines(const Lines& lines) const;
// Outputs a function address and name, followed by its source line list.
// block can be the same object as function, or it can be a reference to a
@@ -118,6 +223,25 @@ class PDBSourceLineWriter {
// Returns true on success.
bool PrintSourceFiles();
+ // Output all inline origins.
+ void PrintInlineOrigins() const;
+
+ // Retrieve inlines inside the given block. It also adds inlinee lines to
+ // `line_list` since inner lines are more precise source location. If the
+ // block has children wih SymTagInlineSite Tag, it will recursively (DFS) call
+ // itself with each child as first argument. Returns true on success.
+ // `block`: the IDiaSymbol that may have inline sites.
+ // `line_list`: the list of lines inside current function.
+ // `inline_nest_level`: the nest level of block's Inlines.
+ // `inlines`: the vector to store the list of inlines for the block.
+ bool GetInlines(IDiaSymbol* block,
+ Lines* line_list,
+ int inline_nest_level,
+ vector<std::unique_ptr<Inline>>* inlines);
+
+ // Outputs all inlines.
+ void PrintInlines(const vector<std::unique_ptr<Inline>>& inlines) const;
+
// Outputs all of the frame information necessary to construct stack
// backtraces in the absence of frame pointers. For x86 data stored in
// .pdb files. Returns true on success.
@@ -150,17 +274,17 @@ class PDBSourceLineWriter {
// Returns true if this filename has already been seen,
// and an ID is stored for it, or false if it has not.
- bool FileIDIsCached(const wstring &file) {
+ bool FileIDIsCached(const wstring& file) {
return unique_files_.find(file) != unique_files_.end();
}
// Cache this filename and ID for later reuse.
- void CacheFileID(const wstring &file, DWORD id) {
+ void CacheFileID(const wstring& file, DWORD id) {
unique_files_[file] = id;
}
// Store this ID in the cache as a duplicate for this filename.
- void StoreDuplicateFileID(const wstring &file, DWORD id) {
+ void StoreDuplicateFileID(const wstring& file, DWORD id) {
unordered_map<wstring, DWORD>::iterator iter = unique_files_.find(file);
if (iter != unique_files_.end()) {
// map this id to the previously seen one
@@ -172,8 +296,8 @@ class PDBSourceLineWriter {
// reference it. There may be multiple files with identical filenames
// but different unique IDs. The cache attempts to coalesce these into
// one ID per unique filename.
- DWORD GetRealFileID(DWORD id) {
- unordered_map<DWORD, DWORD>::iterator iter = file_ids_.find(id);
+ DWORD GetRealFileID(DWORD id) const {
+ unordered_map<DWORD, DWORD>::const_iterator iter = file_ids_.find(id);
if (iter == file_ids_.end())
return id;
return iter->second;
@@ -213,9 +337,15 @@ class PDBSourceLineWriter {
// This maps unique filenames to file IDs.
unordered_map<wstring, DWORD> unique_files_;
+ // The INLINE_ORIGINS records. The key is the function name.
+ std::map<wstring, InlineOrigin> inline_origins_;
+
// This is used for calculating post-transform symbol addresses and lengths.
ImageMap image_map_;
+ // If we should output INLINE/INLINE_ORIGIN records
+ bool handle_inline_;
+
// Disallow copy ctor and operator=
PDBSourceLineWriter(const PDBSourceLineWriter&);
void operator=(const PDBSourceLineWriter&);
diff --git a/src/common/windows/pe_source_line_writer.cc b/src/common/windows/pe_source_line_writer.cc
index cb6cc713..a568e0c7 100644
--- a/src/common/windows/pe_source_line_writer.cc
+++ b/src/common/windows/pe_source_line_writer.cc
@@ -1,77 +1,76 @@
-// Copyright (c) 2019, Google Inc.
-// All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-#include "common/windows/pe_source_line_writer.h"
-
-#include "common/windows/pe_util.h"
-
-namespace google_breakpad {
-PESourceLineWriter::PESourceLineWriter(const wstring& pe_file) :
- pe_file_(pe_file) {
-}
-
-PESourceLineWriter::~PESourceLineWriter() {
-}
-
-bool PESourceLineWriter::WriteSymbols(FILE* symbol_file) {
- PDBModuleInfo module_info;
- if (!GetModuleInfo(&module_info)) {
- return false;
- }
- // Hard-code "windows" for the OS because that's the only thing that makes
- // sense for PDB files. (This might not be strictly correct for Windows CE
- // support, but we don't care about that at the moment.)
- fprintf(symbol_file, "MODULE windows %ws %ws %ws\n",
- module_info.cpu.c_str(), module_info.debug_identifier.c_str(),
- module_info.debug_file.c_str());
-
- PEModuleInfo pe_info;
- if (!GetPEInfo(&pe_info)) {
- return false;
- }
- fprintf(symbol_file, "INFO CODE_ID %ws %ws\n",
- pe_info.code_identifier.c_str(),
- pe_info.code_file.c_str());
-
- if (!PrintPEFrameData(pe_file_, symbol_file)) {
- return false;
- }
-
- return true;
-}
-
-bool PESourceLineWriter::GetModuleInfo(PDBModuleInfo* info) {
- return ReadModuleInfo(pe_file_, info);
-}
-
-bool PESourceLineWriter::GetPEInfo(PEModuleInfo* info) {
- return ReadPEInfo(pe_file_, info);
-}
-
-} // namespace google_breakpad
+// Copyright 2019 Google LLC
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google LLC nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "common/windows/pe_source_line_writer.h"
+
+#include "common/windows/pe_util.h"
+
+namespace google_breakpad {
+PESourceLineWriter::PESourceLineWriter(const wstring& pe_file) :
+ pe_file_(pe_file) {
+}
+
+PESourceLineWriter::~PESourceLineWriter() {
+}
+
+bool PESourceLineWriter::WriteSymbols(FILE* symbol_file) {
+ PDBModuleInfo module_info;
+ if (!GetModuleInfo(&module_info)) {
+ return false;
+ }
+ // Hard-code "windows" for the OS because that's the only thing that makes
+ // sense for PDB files. (This might not be strictly correct for Windows CE
+ // support, but we don't care about that at the moment.)
+ fprintf(symbol_file, "MODULE windows %ws %ws %ws\n",
+ module_info.cpu.c_str(), module_info.debug_identifier.c_str(),
+ module_info.debug_file.c_str());
+
+ PEModuleInfo pe_info;
+ if (!GetPEInfo(&pe_info)) {
+ return false;
+ }
+ fprintf(symbol_file, "INFO CODE_ID %ws %ws\n",
+ pe_info.code_identifier.c_str(),
+ pe_info.code_file.c_str());
+
+ if (!PrintPEFrameData(pe_file_, symbol_file)) {
+ return false;
+ }
+
+ return true;
+}
+
+bool PESourceLineWriter::GetModuleInfo(PDBModuleInfo* info) {
+ return ReadModuleInfo(pe_file_, info);
+}
+
+bool PESourceLineWriter::GetPEInfo(PEModuleInfo* info) {
+ return ReadPEInfo(pe_file_, info);
+}
+
+} // namespace google_breakpad
diff --git a/src/common/windows/pe_source_line_writer.h b/src/common/windows/pe_source_line_writer.h
index 2bf1d4fd..a3748145 100644
--- a/src/common/windows/pe_source_line_writer.h
+++ b/src/common/windows/pe_source_line_writer.h
@@ -1,69 +1,68 @@
-// Copyright (c) 2019, Google Inc.
-// All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-#ifndef COMMON_WINDOWS_PE_SOURCE_LINE_WRITER_H_
-#define COMMON_WINDOWS_PE_SOURCE_LINE_WRITER_H_
-
-#include <string>
-
-#include "common/basictypes.h"
-#include "common/windows/module_info.h"
-
-namespace google_breakpad {
-
-using std::wstring;
-
-// PESourceLineWriter uses a pe file produced by Visual C++ to output
-// a line/address map for use with BasicSourceLineResolver.
-// NOTE: Only supports PE32+ format, ie. a 64bit PE file.
-class PESourceLineWriter {
-public:
- explicit PESourceLineWriter(const wstring& pe_file);
- ~PESourceLineWriter();
-
- // Writes Breakpad symbols from the pe file to |symbol_file|.
- // Returns true on success.
- bool WriteSymbols(FILE* symbol_file);
-
- // Retrieves information about the module. Returns true on success.
- bool GetModuleInfo(PDBModuleInfo* info);
-
+// Copyright 2019 Google LLC
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google LLC nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef COMMON_WINDOWS_PE_SOURCE_LINE_WRITER_H_
+#define COMMON_WINDOWS_PE_SOURCE_LINE_WRITER_H_
+
+#include <string>
+
+#include "common/basictypes.h"
+#include "common/windows/module_info.h"
+
+namespace google_breakpad {
+
+using std::wstring;
+
+// PESourceLineWriter uses a pe file produced by Visual C++ to output
+// a line/address map for use with BasicSourceLineResolver.
+// NOTE: Only supports PE32+ format, ie. a 64bit PE file.
+class PESourceLineWriter {
+public:
+ explicit PESourceLineWriter(const wstring& pe_file);
+ ~PESourceLineWriter();
+
+ // Writes Breakpad symbols from the pe file to |symbol_file|.
+ // Returns true on success.
+ bool WriteSymbols(FILE* symbol_file);
+
+ // Retrieves information about the module. Returns true on success.
+ bool GetModuleInfo(PDBModuleInfo* info);
+
// Retrieves information about the module's PE file. Returns
- // true on success.
- bool GetPEInfo(PEModuleInfo* info);
-
-private:
- const wstring pe_file_;
-
- DISALLOW_COPY_AND_ASSIGN(PESourceLineWriter);
-};
-
-} // namespace google_breakpad
-
-#endif // COMMON_WINDOWS_PE_SOURCE_LINE_WRITER_H_
+ // true on success.
+ bool GetPEInfo(PEModuleInfo* info);
+
+private:
+ const wstring pe_file_;
+
+ DISALLOW_COPY_AND_ASSIGN(PESourceLineWriter);
+};
+
+} // namespace google_breakpad
+
+#endif // COMMON_WINDOWS_PE_SOURCE_LINE_WRITER_H_
diff --git a/src/common/windows/pe_util.cc b/src/common/windows/pe_util.cc
index 6fa63fa3..1df93105 100644
--- a/src/common/windows/pe_util.cc
+++ b/src/common/windows/pe_util.cc
@@ -1,407 +1,411 @@
-// Copyright (c) 2019, Google Inc.
-// All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-#include "pe_util.h"
-
-#include <windows.h>
-#include <winnt.h>
-#include <atlbase.h>
-#include <ImageHlp.h>
-
-#include <functional>
-
-#include "common/windows/string_utils-inl.h"
-#include "common/windows/guid_string.h"
-
-namespace {
-
-/*
- * Not defined in WinNT.h for some reason. Definitions taken from:
- * http://uninformed.org/index.cgi?v=4&a=1&p=13
- *
- */
-typedef unsigned char UBYTE;
-
-#if !defined(_WIN64)
-#define UNW_FLAG_EHANDLER 0x01
-#define UNW_FLAG_UHANDLER 0x02
-#define UNW_FLAG_CHAININFO 0x04
-#endif
-
-union UnwindCode {
- struct {
- UBYTE offset_in_prolog;
- UBYTE unwind_operation_code : 4;
- UBYTE operation_info : 4;
- };
- USHORT frame_offset;
-};
-
-enum UnwindOperationCodes {
- UWOP_PUSH_NONVOL = 0, /* info == register number */
- UWOP_ALLOC_LARGE, /* no info, alloc size in next 2 slots */
- UWOP_ALLOC_SMALL, /* info == size of allocation / 8 - 1 */
- UWOP_SET_FPREG, /* no info, FP = RSP + UNWIND_INFO.FPRegOffset*16 */
- UWOP_SAVE_NONVOL, /* info == register number, offset in next slot */
- UWOP_SAVE_NONVOL_FAR, /* info == register number, offset in next 2 slots */
- // XXX: these are missing from MSDN!
- // See: http://www.osronline.com/ddkx/kmarch/64bitamd_4rs7.htm
- UWOP_SAVE_XMM,
- UWOP_SAVE_XMM_FAR,
- UWOP_SAVE_XMM128, /* info == XMM reg number, offset in next slot */
- UWOP_SAVE_XMM128_FAR, /* info == XMM reg number, offset in next 2 slots */
- UWOP_PUSH_MACHFRAME /* info == 0: no error-code, 1: error-code */
-};
-
-// See: http://msdn.microsoft.com/en-us/library/ddssxxy8.aspx
-// Note: some fields removed as we don't use them.
-struct UnwindInfo {
- UBYTE version : 3;
- UBYTE flags : 5;
- UBYTE size_of_prolog;
- UBYTE count_of_codes;
- UBYTE frame_register : 4;
- UBYTE frame_offset : 4;
- UnwindCode unwind_code[1];
-};
-
-struct CV_INFO_PDB70 {
- ULONG cv_signature;
- GUID signature;
- ULONG age;
- CHAR pdb_filename[ANYSIZE_ARRAY];
-};
-
-#define CV_SIGNATURE_RSDS 'SDSR'
-
-// A helper class to scope a PLOADED_IMAGE.
-class AutoImage {
-public:
- explicit AutoImage(PLOADED_IMAGE img) : img_(img) {}
- ~AutoImage() {
- if (img_)
- ImageUnload(img_);
- }
-
- operator PLOADED_IMAGE() { return img_; }
- PLOADED_IMAGE operator->() { return img_; }
-
-private:
- PLOADED_IMAGE img_;
-};
-} // namespace
-
-namespace google_breakpad {
-
-using std::unique_ptr;
-using google_breakpad::GUIDString;
-
-bool ReadModuleInfo(const wstring & pe_file, PDBModuleInfo * info) {
- // Convert wchar to native charset because ImageLoad only takes
- // a PSTR as input.
- string img_file;
- if (!WindowsStringUtils::safe_wcstombs(pe_file, &img_file)) {
- fprintf(stderr, "Image path '%S' contains unrecognized characters.\n",
- pe_file.c_str());
- return false;
- }
-
- AutoImage img(ImageLoad((PSTR)img_file.c_str(), NULL));
- if (!img) {
- fprintf(stderr, "Failed to load %s\n", img_file.c_str());
- return false;
- }
-
- info->cpu = FileHeaderMachineToCpuString(
- img->FileHeader->FileHeader.Machine);
-
- PIMAGE_OPTIONAL_HEADER64 optional_header =
- &(reinterpret_cast<PIMAGE_NT_HEADERS64>(img->FileHeader))->OptionalHeader;
-
- // Search debug directories for a guid signature & age
- DWORD debug_rva = optional_header->
- DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress;
- DWORD debug_size = optional_header->
- DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].Size;
- PIMAGE_DEBUG_DIRECTORY debug_directories =
- static_cast<PIMAGE_DEBUG_DIRECTORY>(
- ImageRvaToVa(img->FileHeader,
- img->MappedAddress,
- debug_rva,
- &img->LastRvaSection));
-
- for (DWORD i = 0; i < debug_size / sizeof(*debug_directories); i++) {
- if (debug_directories[i].Type != IMAGE_DEBUG_TYPE_CODEVIEW ||
- debug_directories[i].SizeOfData < sizeof(CV_INFO_PDB70)) {
- continue;
- }
-
- struct CV_INFO_PDB70* cv_info = static_cast<CV_INFO_PDB70*>(ImageRvaToVa(
- img->FileHeader,
- img->MappedAddress,
- debug_directories[i].AddressOfRawData,
- &img->LastRvaSection));
- if (cv_info->cv_signature != CV_SIGNATURE_RSDS) {
- continue;
- }
-
- info->debug_identifier = GenerateDebugIdentifier(cv_info->age,
- cv_info->signature);
-
- // This code assumes that the pdb_filename is stored as ASCII without
- // multibyte characters, but it's not clear if that's true.
- size_t debug_file_length = strnlen_s(cv_info->pdb_filename, MAX_PATH);
- if (debug_file_length < 0 || debug_file_length >= MAX_PATH) {
- fprintf(stderr, "PE debug directory is corrupt.\n");
- return false;
- }
- std::string debug_file(cv_info->pdb_filename, debug_file_length);
- if (!WindowsStringUtils::safe_mbstowcs(debug_file, &info->debug_file)) {
- fprintf(stderr, "PDB filename '%s' contains unrecognized characters.\n",
- debug_file.c_str());
- return false;
- }
- info->debug_file = WindowsStringUtils::GetBaseName(info->debug_file);
-
- return true;
- }
-
- fprintf(stderr, "Image is missing debug information.\n");
- return false;
-}
-
-bool ReadPEInfo(const wstring & pe_file, PEModuleInfo * info) {
- // Convert wchar to native charset because ImageLoad only takes
- // a PSTR as input.
- string img_file;
- if (!WindowsStringUtils::safe_wcstombs(pe_file, &img_file)) {
- fprintf(stderr, "Image path '%S' contains unrecognized characters.\n",
- pe_file.c_str());
- return false;
- }
-
- AutoImage img(ImageLoad((PSTR)img_file.c_str(), NULL));
- if (!img) {
- fprintf(stderr, "Failed to open PE file: %S\n", pe_file.c_str());
- return false;
- }
-
- info->code_file = WindowsStringUtils::GetBaseName(pe_file);
-
- // The date and time that the file was created by the linker.
- DWORD TimeDateStamp = img->FileHeader->FileHeader.TimeDateStamp;
- // The size of the file in bytes, including all headers.
- DWORD SizeOfImage = 0;
- PIMAGE_OPTIONAL_HEADER64 opt =
- &((PIMAGE_NT_HEADERS64)img->FileHeader)->OptionalHeader;
- if (opt->Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
- // 64-bit PE file.
- SizeOfImage = opt->SizeOfImage;
- }
- else {
- // 32-bit PE file.
- SizeOfImage = img->FileHeader->OptionalHeader.SizeOfImage;
- }
- wchar_t code_identifier[32];
- swprintf(code_identifier,
- sizeof(code_identifier) / sizeof(code_identifier[0]),
- L"%08X%X", TimeDateStamp, SizeOfImage);
- info->code_identifier = code_identifier;
-
- return true;
-}
-
-bool PrintPEFrameData(const wstring & pe_file, FILE * out_file)
-{
- // Convert wchar to native charset because ImageLoad only takes
- // a PSTR as input.
- string img_file;
- if (!WindowsStringUtils::safe_wcstombs(pe_file, &img_file)) {
- fprintf(stderr, "Image path '%S' contains unrecognized characters.\n",
- pe_file.c_str());
- return false;
- }
-
- AutoImage img(ImageLoad((PSTR)img_file.c_str(), NULL));
- if (!img) {
- fprintf(stderr, "Failed to load %s\n", img_file.c_str());
- return false;
- }
- PIMAGE_OPTIONAL_HEADER64 optional_header =
- &(reinterpret_cast<PIMAGE_NT_HEADERS64>(img->FileHeader))->OptionalHeader;
- if (optional_header->Magic != IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
- fprintf(stderr, "Not a PE32+ image\n");
- return false;
- }
-
- // Read Exception Directory
- DWORD exception_rva = optional_header->
- DataDirectory[IMAGE_DIRECTORY_ENTRY_EXCEPTION].VirtualAddress;
- DWORD exception_size = optional_header->
- DataDirectory[IMAGE_DIRECTORY_ENTRY_EXCEPTION].Size;
- PIMAGE_RUNTIME_FUNCTION_ENTRY funcs =
- static_cast<PIMAGE_RUNTIME_FUNCTION_ENTRY>(
- ImageRvaToVa(img->FileHeader,
- img->MappedAddress,
- exception_rva,
- &img->LastRvaSection));
- for (DWORD i = 0; i < exception_size / sizeof(*funcs); i++) {
- DWORD unwind_rva = funcs[i].UnwindInfoAddress;
- // handle chaining
- while (unwind_rva & 0x1) {
- unwind_rva ^= 0x1;
- PIMAGE_RUNTIME_FUNCTION_ENTRY chained_func =
- static_cast<PIMAGE_RUNTIME_FUNCTION_ENTRY>(
- ImageRvaToVa(img->FileHeader,
- img->MappedAddress,
- unwind_rva,
- &img->LastRvaSection));
- unwind_rva = chained_func->UnwindInfoAddress;
- }
-
- UnwindInfo *unwind_info = static_cast<UnwindInfo *>(
- ImageRvaToVa(img->FileHeader,
- img->MappedAddress,
- unwind_rva,
- &img->LastRvaSection));
-
- DWORD stack_size = 8; // minimal stack size is 8 for RIP
- DWORD rip_offset = 8;
- do {
- for (UBYTE c = 0; c < unwind_info->count_of_codes; c++) {
- UnwindCode *unwind_code = &unwind_info->unwind_code[c];
- switch (unwind_code->unwind_operation_code) {
- case UWOP_PUSH_NONVOL: {
- stack_size += 8;
- break;
- }
- case UWOP_ALLOC_LARGE: {
- if (unwind_code->operation_info == 0) {
- c++;
- if (c < unwind_info->count_of_codes)
- stack_size += (unwind_code + 1)->frame_offset * 8;
- }
- else {
- c += 2;
- if (c < unwind_info->count_of_codes)
- stack_size += (unwind_code + 1)->frame_offset |
- ((unwind_code + 2)->frame_offset << 16);
- }
- break;
- }
- case UWOP_ALLOC_SMALL: {
- stack_size += unwind_code->operation_info * 8 + 8;
- break;
- }
- case UWOP_SET_FPREG:
- case UWOP_SAVE_XMM:
- case UWOP_SAVE_XMM_FAR:
- break;
- case UWOP_SAVE_NONVOL:
- case UWOP_SAVE_XMM128: {
- c++; // skip slot with offset
- break;
- }
- case UWOP_SAVE_NONVOL_FAR:
- case UWOP_SAVE_XMM128_FAR: {
- c += 2; // skip 2 slots with offset
- break;
- }
- case UWOP_PUSH_MACHFRAME: {
- if (unwind_code->operation_info) {
- stack_size += 88;
- }
- else {
- stack_size += 80;
- }
- rip_offset += 80;
- break;
- }
- }
- }
- if (unwind_info->flags & UNW_FLAG_CHAININFO) {
- PIMAGE_RUNTIME_FUNCTION_ENTRY chained_func =
- reinterpret_cast<PIMAGE_RUNTIME_FUNCTION_ENTRY>(
- (unwind_info->unwind_code +
- ((unwind_info->count_of_codes + 1) & ~1)));
-
- unwind_info = static_cast<UnwindInfo *>(
- ImageRvaToVa(img->FileHeader,
- img->MappedAddress,
- chained_func->UnwindInfoAddress,
- &img->LastRvaSection));
- }
- else {
- unwind_info = NULL;
- }
- } while (unwind_info);
- fprintf(out_file, "STACK CFI INIT %lx %lx .cfa: $rsp .ra: .cfa %lu - ^\n",
- funcs[i].BeginAddress,
- funcs[i].EndAddress - funcs[i].BeginAddress, rip_offset);
- fprintf(out_file, "STACK CFI %lx .cfa: $rsp %lu +\n",
- funcs[i].BeginAddress, stack_size);
- }
-
- return true;
-}
-
-wstring GenerateDebugIdentifier(DWORD age, GUID signature)
-{
- // Use the same format that the MS symbol server uses in filesystem
- // hierarchies.
- wchar_t age_string[9];
- swprintf(age_string, sizeof(age_string) / sizeof(age_string[0]),
- L"%x", age);
-
- // remove when VC++7.1 is no longer supported
- age_string[sizeof(age_string) / sizeof(age_string[0]) - 1] = L'\0';
-
- wstring debug_identifier = GUIDString::GUIDToSymbolServerWString(&signature);
- debug_identifier.append(age_string);
-
- return debug_identifier;
-}
-
-wstring GenerateDebugIdentifier(DWORD age, DWORD signature)
-{
- // Use the same format that the MS symbol server uses in filesystem
- // hierarchies.
- wchar_t identifier_string[17];
- swprintf(identifier_string,
- sizeof(identifier_string) / sizeof(identifier_string[0]),
- L"%08X%x", signature, age);
-
- // remove when VC++7.1 is no longer supported
- identifier_string[sizeof(identifier_string) /
- sizeof(identifier_string[0]) - 1] = L'\0';
-
- return wstring(identifier_string);
-}
-
-} // namespace google_breakpad
+// Copyright 2019 Google LLC
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google LLC nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "pe_util.h"
+
+#include <windows.h>
+#include <winnt.h>
+#include <atlbase.h>
+#include <ImageHlp.h>
+
+#include <functional>
+#include <memory>
+
+#include "common/windows/string_utils-inl.h"
+#include "common/windows/guid_string.h"
+
+namespace {
+
+/*
+ * Not defined in WinNT.h prior to SDK 10.0.20348.0 for some reason.
+ * Definitions taken from: http://uninformed.org/index.cgi?v=4&a=1&p=13
+ *
+ */
+typedef unsigned char UBYTE;
+
+#if !defined(UNW_FLAG_EHANDLER)
+#define UNW_FLAG_EHANDLER 0x01
+#endif
+#if !defined(UNW_FLAG_UHANDLER)
+#define UNW_FLAG_UHANDLER 0x02
+#endif
+#if !defined(UNW_FLAG_CHAININFO)
+#define UNW_FLAG_CHAININFO 0x04
+#endif
+
+union UnwindCode {
+ struct {
+ UBYTE offset_in_prolog;
+ UBYTE unwind_operation_code : 4;
+ UBYTE operation_info : 4;
+ };
+ USHORT frame_offset;
+};
+
+enum UnwindOperationCodes {
+ UWOP_PUSH_NONVOL = 0, /* info == register number */
+ UWOP_ALLOC_LARGE, /* no info, alloc size in next 2 slots */
+ UWOP_ALLOC_SMALL, /* info == size of allocation / 8 - 1 */
+ UWOP_SET_FPREG, /* no info, FP = RSP + UNWIND_INFO.FPRegOffset*16 */
+ UWOP_SAVE_NONVOL, /* info == register number, offset in next slot */
+ UWOP_SAVE_NONVOL_FAR, /* info == register number, offset in next 2 slots */
+ // XXX: these are missing from MSDN!
+ // See: http://www.osronline.com/ddkx/kmarch/64bitamd_4rs7.htm
+ UWOP_SAVE_XMM,
+ UWOP_SAVE_XMM_FAR,
+ UWOP_SAVE_XMM128, /* info == XMM reg number, offset in next slot */
+ UWOP_SAVE_XMM128_FAR, /* info == XMM reg number, offset in next 2 slots */
+ UWOP_PUSH_MACHFRAME /* info == 0: no error-code, 1: error-code */
+};
+
+// See: http://msdn.microsoft.com/en-us/library/ddssxxy8.aspx
+// Note: some fields removed as we don't use them.
+struct UnwindInfo {
+ UBYTE version : 3;
+ UBYTE flags : 5;
+ UBYTE size_of_prolog;
+ UBYTE count_of_codes;
+ UBYTE frame_register : 4;
+ UBYTE frame_offset : 4;
+ UnwindCode unwind_code[1];
+};
+
+struct CV_INFO_PDB70 {
+ ULONG cv_signature;
+ GUID signature;
+ ULONG age;
+ CHAR pdb_filename[ANYSIZE_ARRAY];
+};
+
+#define CV_SIGNATURE_RSDS 'SDSR'
+
+// A helper class to scope a PLOADED_IMAGE.
+class AutoImage {
+public:
+ explicit AutoImage(PLOADED_IMAGE img) : img_(img) {}
+ ~AutoImage() {
+ if (img_)
+ ImageUnload(img_);
+ }
+
+ operator PLOADED_IMAGE() { return img_; }
+ PLOADED_IMAGE operator->() { return img_; }
+
+private:
+ PLOADED_IMAGE img_;
+};
+} // namespace
+
+namespace google_breakpad {
+
+using std::unique_ptr;
+using google_breakpad::GUIDString;
+
+bool ReadModuleInfo(const wstring & pe_file, PDBModuleInfo * info) {
+ // Convert wchar to native charset because ImageLoad only takes
+ // a PSTR as input.
+ string img_file;
+ if (!WindowsStringUtils::safe_wcstombs(pe_file, &img_file)) {
+ fprintf(stderr, "Image path '%S' contains unrecognized characters.\n",
+ pe_file.c_str());
+ return false;
+ }
+
+ AutoImage img(ImageLoad((PSTR)img_file.c_str(), NULL));
+ if (!img) {
+ fprintf(stderr, "Failed to load %s\n", img_file.c_str());
+ return false;
+ }
+
+ info->cpu = FileHeaderMachineToCpuString(
+ img->FileHeader->FileHeader.Machine);
+
+ PIMAGE_OPTIONAL_HEADER64 optional_header =
+ &(reinterpret_cast<PIMAGE_NT_HEADERS64>(img->FileHeader))->OptionalHeader;
+
+ // Search debug directories for a guid signature & age
+ DWORD debug_rva = optional_header->
+ DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress;
+ DWORD debug_size = optional_header->
+ DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].Size;
+ PIMAGE_DEBUG_DIRECTORY debug_directories =
+ static_cast<PIMAGE_DEBUG_DIRECTORY>(
+ ImageRvaToVa(img->FileHeader,
+ img->MappedAddress,
+ debug_rva,
+ &img->LastRvaSection));
+
+ for (DWORD i = 0; i < debug_size / sizeof(*debug_directories); i++) {
+ if (debug_directories[i].Type != IMAGE_DEBUG_TYPE_CODEVIEW ||
+ debug_directories[i].SizeOfData < sizeof(CV_INFO_PDB70)) {
+ continue;
+ }
+
+ struct CV_INFO_PDB70* cv_info = static_cast<CV_INFO_PDB70*>(ImageRvaToVa(
+ img->FileHeader,
+ img->MappedAddress,
+ debug_directories[i].AddressOfRawData,
+ &img->LastRvaSection));
+ if (cv_info->cv_signature != CV_SIGNATURE_RSDS) {
+ continue;
+ }
+
+ info->debug_identifier = GenerateDebugIdentifier(cv_info->age,
+ cv_info->signature);
+
+ // This code assumes that the pdb_filename is stored as ASCII without
+ // multibyte characters, but it's not clear if that's true.
+ size_t debug_file_length = strnlen_s(cv_info->pdb_filename, MAX_PATH);
+ if (debug_file_length < 0 || debug_file_length >= MAX_PATH) {
+ fprintf(stderr, "PE debug directory is corrupt.\n");
+ return false;
+ }
+ std::string debug_file(cv_info->pdb_filename, debug_file_length);
+ if (!WindowsStringUtils::safe_mbstowcs(debug_file, &info->debug_file)) {
+ fprintf(stderr, "PDB filename '%s' contains unrecognized characters.\n",
+ debug_file.c_str());
+ return false;
+ }
+ info->debug_file = WindowsStringUtils::GetBaseName(info->debug_file);
+
+ return true;
+ }
+
+ fprintf(stderr, "Image is missing debug information.\n");
+ return false;
+}
+
+bool ReadPEInfo(const wstring & pe_file, PEModuleInfo * info) {
+ // Convert wchar to native charset because ImageLoad only takes
+ // a PSTR as input.
+ string img_file;
+ if (!WindowsStringUtils::safe_wcstombs(pe_file, &img_file)) {
+ fprintf(stderr, "Image path '%S' contains unrecognized characters.\n",
+ pe_file.c_str());
+ return false;
+ }
+
+ AutoImage img(ImageLoad((PSTR)img_file.c_str(), NULL));
+ if (!img) {
+ fprintf(stderr, "Failed to open PE file: %S\n", pe_file.c_str());
+ return false;
+ }
+
+ info->code_file = WindowsStringUtils::GetBaseName(pe_file);
+
+ // The date and time that the file was created by the linker.
+ DWORD TimeDateStamp = img->FileHeader->FileHeader.TimeDateStamp;
+ // The size of the file in bytes, including all headers.
+ DWORD SizeOfImage = 0;
+ PIMAGE_OPTIONAL_HEADER64 opt =
+ &((PIMAGE_NT_HEADERS64)img->FileHeader)->OptionalHeader;
+ if (opt->Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
+ // 64-bit PE file.
+ SizeOfImage = opt->SizeOfImage;
+ }
+ else {
+ // 32-bit PE file.
+ SizeOfImage = img->FileHeader->OptionalHeader.SizeOfImage;
+ }
+ wchar_t code_identifier[32];
+ swprintf(code_identifier,
+ sizeof(code_identifier) / sizeof(code_identifier[0]),
+ L"%08X%X", TimeDateStamp, SizeOfImage);
+ info->code_identifier = code_identifier;
+
+ return true;
+}
+
+bool PrintPEFrameData(const wstring & pe_file, FILE * out_file)
+{
+ // Convert wchar to native charset because ImageLoad only takes
+ // a PSTR as input.
+ string img_file;
+ if (!WindowsStringUtils::safe_wcstombs(pe_file, &img_file)) {
+ fprintf(stderr, "Image path '%S' contains unrecognized characters.\n",
+ pe_file.c_str());
+ return false;
+ }
+
+ AutoImage img(ImageLoad((PSTR)img_file.c_str(), NULL));
+ if (!img) {
+ fprintf(stderr, "Failed to load %s\n", img_file.c_str());
+ return false;
+ }
+ PIMAGE_OPTIONAL_HEADER64 optional_header =
+ &(reinterpret_cast<PIMAGE_NT_HEADERS64>(img->FileHeader))->OptionalHeader;
+ if (optional_header->Magic != IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
+ fprintf(stderr, "Not a PE32+ image\n");
+ return false;
+ }
+
+ // Read Exception Directory
+ DWORD exception_rva = optional_header->
+ DataDirectory[IMAGE_DIRECTORY_ENTRY_EXCEPTION].VirtualAddress;
+ DWORD exception_size = optional_header->
+ DataDirectory[IMAGE_DIRECTORY_ENTRY_EXCEPTION].Size;
+ PIMAGE_RUNTIME_FUNCTION_ENTRY funcs =
+ static_cast<PIMAGE_RUNTIME_FUNCTION_ENTRY>(
+ ImageRvaToVa(img->FileHeader,
+ img->MappedAddress,
+ exception_rva,
+ &img->LastRvaSection));
+ for (DWORD i = 0; i < exception_size / sizeof(*funcs); i++) {
+ DWORD unwind_rva = funcs[i].UnwindInfoAddress;
+ // handle chaining
+ while (unwind_rva & 0x1) {
+ unwind_rva ^= 0x1;
+ PIMAGE_RUNTIME_FUNCTION_ENTRY chained_func =
+ static_cast<PIMAGE_RUNTIME_FUNCTION_ENTRY>(
+ ImageRvaToVa(img->FileHeader,
+ img->MappedAddress,
+ unwind_rva,
+ &img->LastRvaSection));
+ unwind_rva = chained_func->UnwindInfoAddress;
+ }
+
+ UnwindInfo *unwind_info = static_cast<UnwindInfo*>(
+ ImageRvaToVa(img->FileHeader,
+ img->MappedAddress,
+ unwind_rva,
+ &img->LastRvaSection));
+
+ DWORD stack_size = 8; // minimal stack size is 8 for RIP
+ DWORD rip_offset = 8;
+ do {
+ for (UBYTE c = 0; c < unwind_info->count_of_codes; c++) {
+ UnwindCode *unwind_code = &unwind_info->unwind_code[c];
+ switch (unwind_code->unwind_operation_code) {
+ case UWOP_PUSH_NONVOL: {
+ stack_size += 8;
+ break;
+ }
+ case UWOP_ALLOC_LARGE: {
+ if (unwind_code->operation_info == 0) {
+ c++;
+ if (c < unwind_info->count_of_codes)
+ stack_size += (unwind_code + 1)->frame_offset * 8;
+ }
+ else {
+ c += 2;
+ if (c < unwind_info->count_of_codes)
+ stack_size += (unwind_code + 1)->frame_offset |
+ ((unwind_code + 2)->frame_offset << 16);
+ }
+ break;
+ }
+ case UWOP_ALLOC_SMALL: {
+ stack_size += unwind_code->operation_info * 8 + 8;
+ break;
+ }
+ case UWOP_SET_FPREG:
+ case UWOP_SAVE_XMM:
+ case UWOP_SAVE_XMM_FAR:
+ break;
+ case UWOP_SAVE_NONVOL:
+ case UWOP_SAVE_XMM128: {
+ c++; // skip slot with offset
+ break;
+ }
+ case UWOP_SAVE_NONVOL_FAR:
+ case UWOP_SAVE_XMM128_FAR: {
+ c += 2; // skip 2 slots with offset
+ break;
+ }
+ case UWOP_PUSH_MACHFRAME: {
+ if (unwind_code->operation_info) {
+ stack_size += 88;
+ }
+ else {
+ stack_size += 80;
+ }
+ rip_offset += 80;
+ break;
+ }
+ }
+ }
+ if (unwind_info->flags & UNW_FLAG_CHAININFO) {
+ PIMAGE_RUNTIME_FUNCTION_ENTRY chained_func =
+ reinterpret_cast<PIMAGE_RUNTIME_FUNCTION_ENTRY>(
+ (unwind_info->unwind_code +
+ ((unwind_info->count_of_codes + 1) & ~1)));
+
+ unwind_info = static_cast<UnwindInfo*>(
+ ImageRvaToVa(img->FileHeader,
+ img->MappedAddress,
+ chained_func->UnwindInfoAddress,
+ &img->LastRvaSection));
+ }
+ else {
+ unwind_info = NULL;
+ }
+ } while (unwind_info);
+ fprintf(out_file, "STACK CFI INIT %lx %lx .cfa: $rsp .ra: .cfa %lu - ^\n",
+ funcs[i].BeginAddress,
+ funcs[i].EndAddress - funcs[i].BeginAddress, rip_offset);
+ fprintf(out_file, "STACK CFI %lx .cfa: $rsp %lu +\n",
+ funcs[i].BeginAddress, stack_size);
+ }
+
+ return true;
+}
+
+wstring GenerateDebugIdentifier(DWORD age, GUID signature)
+{
+ // Use the same format that the MS symbol server uses in filesystem
+ // hierarchies.
+ wchar_t age_string[9];
+ swprintf(age_string, sizeof(age_string) / sizeof(age_string[0]),
+ L"%x", age);
+
+ // remove when VC++7.1 is no longer supported
+ age_string[sizeof(age_string) / sizeof(age_string[0]) - 1] = L'\0';
+
+ wstring debug_identifier = GUIDString::GUIDToSymbolServerWString(&signature);
+ debug_identifier.append(age_string);
+
+ return debug_identifier;
+}
+
+wstring GenerateDebugIdentifier(DWORD age, DWORD signature)
+{
+ // Use the same format that the MS symbol server uses in filesystem
+ // hierarchies.
+ wchar_t identifier_string[17];
+ swprintf(identifier_string,
+ sizeof(identifier_string) / sizeof(identifier_string[0]),
+ L"%08X%x", signature, age);
+
+ // remove when VC++7.1 is no longer supported
+ identifier_string[sizeof(identifier_string) /
+ sizeof(identifier_string[0]) - 1] = L'\0';
+
+ return wstring(identifier_string);
+}
+
+} // namespace google_breakpad
diff --git a/src/common/windows/pe_util.h b/src/common/windows/pe_util.h
index 634ba293..6c6b364f 100644
--- a/src/common/windows/pe_util.h
+++ b/src/common/windows/pe_util.h
@@ -1,78 +1,77 @@
-// Copyright (c) 2019, Google Inc.
-// All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-#ifndef COMMON_WINDOWS_PE_UTIL_H_
-#define COMMON_WINDOWS_PE_UTIL_H_
-
-#include <windows.h>
-
-#include "common/windows/module_info.h"
-
-namespace google_breakpad {
-
-using std::wstring;
-
-// Reads |pe_file| and populates |info|. Returns true on success.
-// Only supports PE32+ format, ie. a 64bit PE file.
-// Will fail if |pe_file| does not contain a valid CodeView record.
-bool ReadModuleInfo(const wstring& pe_file, PDBModuleInfo* info);
-
-// Reads |pe_file| and populates |info|. Returns true on success.
-bool ReadPEInfo(const wstring& pe_file, PEModuleInfo* info);
-
-// Reads |pe_file| and prints frame data (aka. unwind info) to |out_file|.
-// Only supports PE32+ format, ie. a 64bit PE file.
-bool PrintPEFrameData(const wstring& pe_file, FILE* out_file);
-
-// Combines a GUID |signature| and DWORD |age| to create a Breakpad debug
-// identifier.
-wstring GenerateDebugIdentifier(DWORD age, GUID signature);
-
-// Combines a DWORD |signature| and DWORD |age| to create a Breakpad debug
-// identifier.
-wstring GenerateDebugIdentifier(DWORD age, DWORD signature);
-
-// Converts |machine| enum value to the corresponding string used by Breakpad.
-// The enum is IMAGE_FILE_MACHINE_*, contained in winnt.h.
-constexpr const wchar_t* FileHeaderMachineToCpuString(WORD machine) {
- switch (machine) {
- case IMAGE_FILE_MACHINE_I386: {
- return L"x86";
- }
- case IMAGE_FILE_MACHINE_IA64:
- case IMAGE_FILE_MACHINE_AMD64: {
- return L"x86_64";
- }
- default: { return L"unknown"; }
- }
-}
-
-} // namespace google_breakpad
-
-#endif // COMMON_WINDOWS_PE_UTIL_H_
+// Copyright 2019 Google LLC
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google LLC nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef COMMON_WINDOWS_PE_UTIL_H_
+#define COMMON_WINDOWS_PE_UTIL_H_
+
+#include <windows.h>
+
+#include "common/windows/module_info.h"
+
+namespace google_breakpad {
+
+using std::wstring;
+
+// Reads |pe_file| and populates |info|. Returns true on success.
+// Only supports PE32+ format, ie. a 64bit PE file.
+// Will fail if |pe_file| does not contain a valid CodeView record.
+bool ReadModuleInfo(const wstring& pe_file, PDBModuleInfo* info);
+
+// Reads |pe_file| and populates |info|. Returns true on success.
+bool ReadPEInfo(const wstring& pe_file, PEModuleInfo* info);
+
+// Reads |pe_file| and prints frame data (aka. unwind info) to |out_file|.
+// Only supports PE32+ format, ie. a 64bit PE file.
+bool PrintPEFrameData(const wstring& pe_file, FILE* out_file);
+
+// Combines a GUID |signature| and DWORD |age| to create a Breakpad debug
+// identifier.
+wstring GenerateDebugIdentifier(DWORD age, GUID signature);
+
+// Combines a DWORD |signature| and DWORD |age| to create a Breakpad debug
+// identifier.
+wstring GenerateDebugIdentifier(DWORD age, DWORD signature);
+
+// Converts |machine| enum value to the corresponding string used by Breakpad.
+// The enum is IMAGE_FILE_MACHINE_*, contained in winnt.h.
+constexpr const wchar_t* FileHeaderMachineToCpuString(WORD machine) {
+ switch (machine) {
+ case IMAGE_FILE_MACHINE_I386: {
+ return L"x86";
+ }
+ case IMAGE_FILE_MACHINE_IA64:
+ case IMAGE_FILE_MACHINE_AMD64: {
+ return L"x86_64";
+ }
+ default: { return L"unknown"; }
+ }
+}
+
+} // namespace google_breakpad
+
+#endif // COMMON_WINDOWS_PE_UTIL_H_
diff --git a/src/common/windows/string_utils-inl.h b/src/common/windows/string_utils-inl.h
index 9b636072..c6f5e0ac 100644
--- a/src/common/windows/string_utils-inl.h
+++ b/src/common/windows/string_utils-inl.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2006, Google Inc.
-// All rights reserved.
+// Copyright 2006 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -72,26 +71,26 @@ class WindowsStringUtils {
// Roughly equivalent to MSVC8's wcscpy_s, except pre-MSVC8, this does
// not fail if source is longer than destination_size. The destination
// buffer is always 0-terminated.
- static void safe_wcscpy(wchar_t *destination, size_t destination_size,
- const wchar_t *source);
+ static void safe_wcscpy(wchar_t* destination, size_t destination_size,
+ const wchar_t* source);
// Roughly equivalent to MSVC8's wcsncpy_s, except that _TRUNCATE cannot
// be passed directly, and pre-MSVC8, this will not fail if source or count
// are longer than destination_size. The destination buffer is always
// 0-terminated.
- static void safe_wcsncpy(wchar_t *destination, size_t destination_size,
- const wchar_t *source, size_t count);
+ static void safe_wcsncpy(wchar_t* destination, size_t destination_size,
+ const wchar_t* source, size_t count);
// Performs multi-byte to wide character conversion on C++ strings, using
// mbstowcs_s (MSVC8) or mbstowcs (pre-MSVC8). Returns false on failure,
// without setting wcs.
- static bool safe_mbstowcs(const string &mbs, wstring *wcs);
+ static bool safe_mbstowcs(const string& mbs, wstring* wcs);
// The inverse of safe_mbstowcs.
- static bool safe_wcstombs(const wstring &wcs, string *mbs);
+ static bool safe_wcstombs(const wstring& wcs, string* mbs);
// Returns the base name of a file, e.g. strips off the path.
- static wstring GetBaseName(const wstring &filename);
+ static wstring GetBaseName(const wstring& filename);
private:
// Disallow instantiation and other object-based operations.
@@ -102,9 +101,9 @@ class WindowsStringUtils {
};
// static
-inline void WindowsStringUtils::safe_wcscpy(wchar_t *destination,
+inline void WindowsStringUtils::safe_wcscpy(wchar_t* destination,
size_t destination_size,
- const wchar_t *source) {
+ const wchar_t* source) {
#if _MSC_VER >= 1400 // MSVC 2005/8
wcscpy_s(destination, destination_size, source);
#else // _MSC_VER >= 1400
@@ -118,9 +117,9 @@ inline void WindowsStringUtils::safe_wcscpy(wchar_t *destination,
}
// static
-inline void WindowsStringUtils::safe_wcsncpy(wchar_t *destination,
+inline void WindowsStringUtils::safe_wcsncpy(wchar_t* destination,
size_t destination_size,
- const wchar_t *source,
+ const wchar_t* source,
size_t count) {
#if _MSC_VER >= 1400 // MSVC 2005/8
wcsncpy_s(destination, destination_size, source, count);
diff --git a/src/common/windows/string_utils.cc b/src/common/windows/string_utils.cc
index 27280003..01dca193 100644
--- a/src/common/windows/string_utils.cc
+++ b/src/common/windows/string_utils.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2006, Google Inc.
-// All rights reserved.
+// Copyright 2006 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -35,7 +34,7 @@
namespace google_breakpad {
// static
-wstring WindowsStringUtils::GetBaseName(const wstring &filename) {
+wstring WindowsStringUtils::GetBaseName(const wstring& filename) {
wstring base_name(filename);
size_t slash_pos = base_name.find_last_of(L"/\\");
if (slash_pos != wstring::npos) {
@@ -45,7 +44,7 @@ wstring WindowsStringUtils::GetBaseName(const wstring &filename) {
}
// static
-bool WindowsStringUtils::safe_mbstowcs(const string &mbs, wstring *wcs) {
+bool WindowsStringUtils::safe_mbstowcs(const string& mbs, wstring* wcs) {
assert(wcs);
// First, determine the length of the destination buffer.
@@ -88,7 +87,7 @@ bool WindowsStringUtils::safe_mbstowcs(const string &mbs, wstring *wcs) {
}
// static
-bool WindowsStringUtils::safe_wcstombs(const wstring &wcs, string *mbs) {
+bool WindowsStringUtils::safe_wcstombs(const wstring& wcs, string* mbs) {
assert(mbs);
// First, determine the length of the destination buffer.
diff --git a/src/common/windows/sym_upload_v2_protocol.cc b/src/common/windows/sym_upload_v2_protocol.cc
new file mode 100644
index 00000000..f2dc660c
--- /dev/null
+++ b/src/common/windows/sym_upload_v2_protocol.cc
@@ -0,0 +1,118 @@
+// Copyright 2022 Google LLC
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google LLC nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "common/windows/sym_upload_v2_protocol.h"
+
+#include <cstdio>
+
+#include "common/windows/http_upload.h"
+#include "common/windows/symbol_collector_client.h"
+
+using google_breakpad::CompleteUploadResult;
+using google_breakpad::HTTPUpload;
+using google_breakpad::SymbolCollectorClient;
+using google_breakpad::SymbolStatus;
+using google_breakpad::UploadUrlResponse;
+using std::wstring;
+
+namespace google_breakpad {
+
+static bool SymUploadV2ProtocolSend(const wchar_t* api_url,
+ const wchar_t* api_key,
+ int* timeout_ms,
+ const wstring& debug_file,
+ const wstring& debug_id,
+ const wstring& symbol_filename,
+ const wstring& symbol_type,
+ const wstring& product_name,
+ bool force) {
+ wstring url(api_url);
+ wstring key(api_key);
+
+ if (!force) {
+ SymbolStatus symbolStatus = SymbolCollectorClient::CheckSymbolStatus(
+ url, key, timeout_ms, debug_file, debug_id);
+ if (symbolStatus == SymbolStatus::Found) {
+ wprintf(
+ L"Symbol file already exists, upload aborted."
+ L" Use \"-f\" to overwrite.\n");
+ return true;
+ } else if (symbolStatus == SymbolStatus::Unknown) {
+ wprintf(L"Failed to get check for existing symbol.\n");
+ return false;
+ }
+ }
+
+ UploadUrlResponse uploadUrlResponse;
+ if (!SymbolCollectorClient::CreateUploadUrl(url, key, timeout_ms,
+ &uploadUrlResponse)) {
+ wprintf(L"Failed to create upload URL.\n");
+ return false;
+ }
+
+ wstring signed_url = uploadUrlResponse.upload_url;
+ wstring upload_key = uploadUrlResponse.upload_key;
+ wstring response;
+ int response_code;
+ bool success = HTTPUpload::SendPutRequest(
+ signed_url, symbol_filename, timeout_ms, &response, &response_code);
+ if (!success) {
+ wprintf(L"Failed to send symbol file.\n");
+ wprintf(L"Response code: %ld\n", response_code);
+ wprintf(L"Response:\n");
+ wprintf(L"%s\n", response.c_str());
+ return false;
+ } else if (response_code == 0) {
+ wprintf(L"Failed to send symbol file: No response code\n");
+ return false;
+ } else if (response_code != 200) {
+ wprintf(L"Failed to send symbol file: Response code %ld\n", response_code);
+ wprintf(L"Response:\n");
+ wprintf(L"%s\n", response.c_str());
+ return false;
+ }
+
+ CompleteUploadResult completeUploadResult =
+ SymbolCollectorClient::CompleteUpload(url, key, timeout_ms, upload_key,
+ debug_file, debug_id, symbol_type,
+ product_name);
+ if (completeUploadResult == CompleteUploadResult::Error) {
+ wprintf(L"Failed to complete upload.\n");
+ return false;
+ } else if (completeUploadResult == CompleteUploadResult::DuplicateData) {
+ wprintf(
+ L"Uploaded file checksum matched existing file checksum,"
+ L" no change necessary.\n");
+ } else {
+ wprintf(L"Successfully sent the symbol file.\n");
+ }
+
+ return true;
+}
+
+} // namespace google_breakpad
diff --git a/src/common/windows/sym_upload_v2_protocol.h b/src/common/windows/sym_upload_v2_protocol.h
new file mode 100644
index 00000000..19e6f87a
--- /dev/null
+++ b/src/common/windows/sym_upload_v2_protocol.h
@@ -0,0 +1,66 @@
+// Copyright 2022 Google LLC
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google LLC nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef COMMON_WINDOWS_SYM_UPLOAD_V2_PROTOCOL_H_
+#define COMMON_WINDOWS_SYM_UPLOAD_V2_PROTOCOL_H_
+
+#include <string>
+
+namespace google_breakpad {
+
+// Sends file at |symbol_filename| using the sym-upload-v2 protocol to
+// |api_url| using key |api_key|, and using identifiers |debug_file| and
+// |debug_id|. |timeout_ms| is the number of milliseconds to wait before
+// terminating the upload attempt. |symbol_type| is the type of the symbol
+// file, which is one of:
+// "BREAKPAD"
+// "ELF"
+// "PE"
+// "MACHO"
+// "DEBUG_ONLY"
+// "DWP"
+// "DSYM"
+// "PDB"
+// "SOURCE_MAP"
+// If |product_name| is non-empty then it will be sent as part of the symbol
+// metadata.
+// If |force| is set then it will overwrite an existing file with the
+// same |debug_file| and |debug_id| in the store.
+bool SymUploadV2ProtocolSend(const wchar_t* api_url,
+ const wchar_t* api_key,
+ int* timeout_ms,
+ const std::wstring& debug_file,
+ const std::wstring& debug_id,
+ const std::wstring& symbol_filename,
+ const std::wstring& symbol_type,
+ const std::wstring& product_name,
+ bool force);
+
+} // namespace google_breakpad
+
+#endif // COMMON_WINDOWS_SYM_UPLOAD_V2_PROTOCOL_H_ \ No newline at end of file
diff --git a/src/common/windows/symbol_collector_client.cc b/src/common/windows/symbol_collector_client.cc
index 30c663ed..187b100e 100644
--- a/src/common/windows/symbol_collector_client.cc
+++ b/src/common/windows/symbol_collector_client.cc
@@ -12,6 +12,7 @@ namespace google_breakpad {
bool SymbolCollectorClient::CreateUploadUrl(
wstring& api_url,
wstring& api_key,
+ int* timeout_ms,
UploadUrlResponse *uploadUrlResponse) {
wstring url = api_url +
L"/v1/uploads:create"
@@ -23,7 +24,7 @@ namespace google_breakpad {
url,
L"",
L"",
- NULL,
+ timeout_ms,
&response,
&response_code)) {
wprintf(L"Failed to create upload url.\n");
@@ -66,17 +67,35 @@ namespace google_breakpad {
CompleteUploadResult SymbolCollectorClient::CompleteUpload(
wstring& api_url,
wstring& api_key,
+ int* timeout_ms,
const wstring& upload_key,
const wstring& debug_file,
- const wstring& debug_id) {
+ const wstring& debug_id,
+ const wstring& type,
+ const wstring& product_name) {
wstring url = api_url +
L"/v1/uploads/" + upload_key + L":complete"
L"?key=" + api_key;
wstring body =
L"{ symbol_id: {"
- L"debug_file: \"" + debug_file + L"\", "
- L"debug_id: \"" + debug_id + L"\" "
- L"} }";
+ L"debug_file: \"" +
+ debug_file +
+ L"\", "
+ L"debug_id: \"" +
+ debug_id +
+ L"\" "
+ L"}, ";
+ if (!product_name.empty()) {
+ body +=
+ L"metadata: {"
+ L"product_name: \"" +
+ product_name +
+ L"\""
+ L"},";
+ }
+ body += L"symbol_upload_type: \"" + type +
+ L"\", "
+ L"use_async_processing: true }";
wstring response;
int response_code;
@@ -84,7 +103,7 @@ namespace google_breakpad {
url,
body,
L"application/json",
- NULL,
+ timeout_ms,
&response,
&response_code)) {
wprintf(L"Failed to complete upload.\n");
@@ -116,6 +135,7 @@ namespace google_breakpad {
SymbolStatus SymbolCollectorClient::CheckSymbolStatus(
wstring& api_url,
wstring& api_key,
+ int* timeout_ms,
const wstring& debug_file,
const wstring& debug_id) {
wstring response;
@@ -126,7 +146,7 @@ namespace google_breakpad {
if (!HTTPUpload::SendGetRequest(
url,
- NULL,
+ timeout_ms,
&response,
&response_code)) {
wprintf(L"Failed to check symbol status.\n");
diff --git a/src/common/windows/symbol_collector_client.h b/src/common/windows/symbol_collector_client.h
index 30e0cb32..4e9bf3b6 100644
--- a/src/common/windows/symbol_collector_client.h
+++ b/src/common/windows/symbol_collector_client.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2019, Google Inc.
-// All rights reserved.
+// Copyright 2019 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -64,22 +63,26 @@ namespace google_breakpad {
static bool CreateUploadUrl(
wstring& api_url,
wstring& api_key,
+ int* timeout_ms,
UploadUrlResponse *uploadUrlResponse);
// Notify the API that symbol file upload is finished and its contents
// are ready to be read and/or used for further processing.
- static CompleteUploadResult CompleteUpload(
- wstring& api_url,
- wstring& api_key,
- const wstring& upload_key,
- const wstring& debug_file,
- const wstring& debug_id);
+ static CompleteUploadResult CompleteUpload(wstring& api_url,
+ wstring& api_key,
+ int* timeout_ms,
+ const wstring& upload_key,
+ const wstring& debug_file,
+ const wstring& debug_id,
+ const wstring& type,
+ const wstring& product_name);
// Returns whether or not a symbol file corresponding to the debug_file/
// debug_id pair is already present in symbol storage.
static SymbolStatus CheckSymbolStatus(
wstring& api_url,
wstring& api_key,
+ int* timeout_ms,
const wstring& debug_file,
const wstring& debug_id);
};
diff --git a/src/config.h.in b/src/config.h.in
index 0553a24b..8fd7b0aa 100644
--- a/src/config.h.in
+++ b/src/config.h.in
@@ -6,8 +6,8 @@
/* Define to 1 if you have the <a.out.h> header file. */
#undef HAVE_A_OUT_H
-/* define if the compiler supports basic C++11 syntax */
-#undef HAVE_CXX11
+/* define if the compiler supports basic C++17 syntax */
+#undef HAVE_CXX17
/* Define to 1 if you have the `getcontext' function. */
#undef HAVE_GETCONTEXT
@@ -18,15 +18,24 @@
/* Define to 1 if you have the <inttypes.h> header file. */
#undef HAVE_INTTYPES_H
-/* Define to 1 if you have the <memory.h> header file. */
-#undef HAVE_MEMORY_H
+/* Define to 1 if you have the `rustc_demangle' library (-lrustc_demangle). */
+#undef HAVE_LIBRUSTC_DEMANGLE
+
+/* Define to 1 if you have the `memfd_create' function. */
+#undef HAVE_MEMFD_CREATE
/* Define if you have POSIX threads libraries and header files. */
#undef HAVE_PTHREAD
+/* Define to 1 if you have the <rustc_demangle.h> header file. */
+#undef HAVE_RUSTC_DEMANGLE_H
+
/* Define to 1 if you have the <stdint.h> header file. */
#undef HAVE_STDINT_H
+/* Define to 1 if you have the <stdio.h> header file. */
+#undef HAVE_STDIO_H
+
/* Define to 1 if you have the <stdlib.h> header file. */
#undef HAVE_STDLIB_H
@@ -36,6 +45,9 @@
/* Define to 1 if you have the <string.h> header file. */
#undef HAVE_STRING_H
+/* Define to 1 if you have the <sys/mman.h> header file. */
+#undef HAVE_SYS_MMAN_H
+
/* Define to 1 if you have the <sys/random.h> header file. */
#undef HAVE_SYS_RANDOM_H
@@ -76,17 +88,14 @@
your system. */
#undef PTHREAD_CREATE_JOINABLE
-/* Define to 1 if you have the ANSI C header files. */
+/* Define to 1 if all of the C90 standard headers exist (not just the ones
+ required in a freestanding environment). This macro is provided for
+ backward compatibility; new code need not use it. */
#undef STDC_HEADERS
/* Version number of package */
#undef VERSION
-/* Enable large inode numbers on Mac OS X 10.5. */
-#ifndef _DARWIN_USE_64_BIT_INODE
-# define _DARWIN_USE_64_BIT_INODE 1
-#endif
-
/* Number of bits in a file offset, on hosts where this is settable. */
#undef _FILE_OFFSET_BITS
diff --git a/src/google_breakpad/common/breakpad_types.h b/src/google_breakpad/common/breakpad_types.h
index d8828043..efd94e9d 100644
--- a/src/google_breakpad/common/breakpad_types.h
+++ b/src/google_breakpad/common/breakpad_types.h
@@ -1,5 +1,4 @@
-/* Copyright (c) 2006, Google Inc.
- * All rights reserved.
+/* Copyright 2006 Google LLC
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
- * * Neither the name of Google Inc. nor the names of its
+ * * Neither the name of Google LLC nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
diff --git a/src/google_breakpad/common/minidump_cpu_amd64.h b/src/google_breakpad/common/minidump_cpu_amd64.h
index 4256706d..308f21ec 100644
--- a/src/google_breakpad/common/minidump_cpu_amd64.h
+++ b/src/google_breakpad/common/minidump_cpu_amd64.h
@@ -1,5 +1,4 @@
-/* Copyright (c) 2006, Google Inc.
- * All rights reserved.
+/* Copyright 2006 Google LLC
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
- * * Neither the name of Google Inc. nor the names of its
+ * * Neither the name of Google LLC nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
diff --git a/src/google_breakpad/common/minidump_cpu_arm.h b/src/google_breakpad/common/minidump_cpu_arm.h
index 6a711383..2ac0623e 100644
--- a/src/google_breakpad/common/minidump_cpu_arm.h
+++ b/src/google_breakpad/common/minidump_cpu_arm.h
@@ -1,5 +1,4 @@
-/* Copyright (c) 2009, Google Inc.
- * All rights reserved.
+/* Copyright 2009 Google LLC
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
- * * Neither the name of Google Inc. nor the names of its
+ * * Neither the name of Google LLC nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
diff --git a/src/google_breakpad/common/minidump_cpu_arm64.h b/src/google_breakpad/common/minidump_cpu_arm64.h
index 0411bebb..96f26332 100644
--- a/src/google_breakpad/common/minidump_cpu_arm64.h
+++ b/src/google_breakpad/common/minidump_cpu_arm64.h
@@ -1,5 +1,4 @@
-/* Copyright 2013 Google Inc.
- * All rights reserved.
+/* Copyright 2013 Google LLC
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
- * * Neither the name of Google Inc. nor the names of its
+ * * Neither the name of Google LLC nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
diff --git a/src/google_breakpad/common/minidump_cpu_mips.h b/src/google_breakpad/common/minidump_cpu_mips.h
index f4e2b589..91b700af 100644
--- a/src/google_breakpad/common/minidump_cpu_mips.h
+++ b/src/google_breakpad/common/minidump_cpu_mips.h
@@ -1,5 +1,4 @@
-/* Copyright (c) 2013, Google Inc.
- * All rights reserved.
+/* Copyright 2013 Google LLC
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
- * * Neither the name of Google Inc. nor the names of its
+ * * Neither the name of Google LLC nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
diff --git a/src/google_breakpad/common/minidump_cpu_ppc.h b/src/google_breakpad/common/minidump_cpu_ppc.h
index b24cc424..17a71af7 100644
--- a/src/google_breakpad/common/minidump_cpu_ppc.h
+++ b/src/google_breakpad/common/minidump_cpu_ppc.h
@@ -1,5 +1,4 @@
-/* Copyright (c) 2006, Google Inc.
- * All rights reserved.
+/* Copyright 2006 Google LLC
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
- * * Neither the name of Google Inc. nor the names of its
+ * * Neither the name of Google LLC nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
diff --git a/src/google_breakpad/common/minidump_cpu_ppc64.h b/src/google_breakpad/common/minidump_cpu_ppc64.h
index 61f41938..75638b5d 100644
--- a/src/google_breakpad/common/minidump_cpu_ppc64.h
+++ b/src/google_breakpad/common/minidump_cpu_ppc64.h
@@ -1,5 +1,4 @@
-/* Copyright (c) 2008, Google Inc.
- * All rights reserved.
+/* Copyright 2008 Google LLC
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
- * * Neither the name of Google Inc. nor the names of its
+ * * Neither the name of Google LLC nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
diff --git a/src/google_breakpad/common/minidump_cpu_riscv.h b/src/google_breakpad/common/minidump_cpu_riscv.h
new file mode 100644
index 00000000..94d06117
--- /dev/null
+++ b/src/google_breakpad/common/minidump_cpu_riscv.h
@@ -0,0 +1,168 @@
+/* minidump_format.h: A cross-platform reimplementation of minidump-related
+ * portions of DbgHelp.h from the Windows Platform SDK.
+ *
+ * (This is C99 source, please don't corrupt it with C++.)
+ *
+ * This file contains the necessary definitions to read minidump files
+ * produced on RISCV and RISCV64. These files may be read on any platform
+ * provided that the alignments of these structures on the processing system
+ * are identical to the alignments of these structures on the producing
+ * system. For this reason, precise-sized types are used. The structures
+ * defined by this file have been laid out to minimize alignment problems by
+ * ensuring that all members are aligned on their natural boundaries.
+ * In some cases, tail-padding may be significant when different ABIs specify
+ * different tail-padding behaviors. To avoid problems when reading or
+ * writing affected structures, MD_*_SIZE macros are provided where needed,
+ * containing the useful size of the structures without padding.
+ *
+ * Structures that are defined by Microsoft to contain a zero-length array
+ * are instead defined here to contain an array with one element, as
+ * zero-length arrays are forbidden by standard C and C++. In these cases,
+ * *_minsize constants are provided to be used in place of sizeof. For a
+ * cleaner interface to these sizes when using C++, see minidump_size.h.
+ *
+ * These structures are also sufficient to populate minidump files.
+ *
+ * Because precise data type sizes are crucial for this implementation to
+ * function properly and portably, a set of primitive types with known sizes
+ * are used as the basis of each structure defined by this file.
+ *
+ * Author: Iacopo Colonnelli
+ */
+
+/*
+ * RISCV and RISCV64 support
+ */
+
+#ifndef GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_RISCV_H__
+#define GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_RISCV_H__
+
+#include "google_breakpad/common/breakpad_types.h"
+
+#define MD_FLOATINGSAVEAREA_RISCV_FPR_COUNT 32
+#if defined(__riscv)
+# if __riscv_flen == 32
+typedef uint32_t riscv_fpr_size;
+# elif __riscv_flen == 64
+typedef uint64_t riscv_fpr_size;
+# elif __riscv_flen == 128
+typedef uint128_struct riscv_fpr_size;
+# else
+# error "Unexpected __riscv_flen"
+# endif
+#else
+typedef uint32_t riscv_fpr_size;
+#endif
+
+#define MD_CONTEXT_RISCV_GPR_COUNT 32
+
+typedef struct {
+ /* 32 floating point registers, f0 .. f31. */
+ riscv_fpr_size regs[MD_FLOATINGSAVEAREA_RISCV_FPR_COUNT];
+ uint32_t fpcsr;
+} MDFloatingSaveAreaRISCV;
+
+enum MDRISCVRegisterNumbers {
+ MD_CONTEXT_RISCV_REG_PC = 0,
+ MD_CONTEXT_RISCV_REG_RA = 1,
+ MD_CONTEXT_RISCV_REG_SP = 2,
+};
+
+/* For (MDRawContextRISCV).context_flags. These values indicate the type of
+ * context stored in the structure. */
+#define MD_CONTEXT_RISCV 0x00800000
+#define MD_CONTEXT_RISCV_INTEGER (MD_CONTEXT_RISCV | 0x00000001)
+#define MD_CONTEXT_RISCV_FLOATING_POINT (MD_CONTEXT_RISCV | 0x00000004)
+#define MD_CONTEXT_RISCV_FULL (MD_CONTEXT_RISCV_INTEGER | \
+ MD_CONTEXT_RISCV_FLOATING_POINT)
+
+typedef struct {
+ /* Determines which fields of this struct are populated */
+ uint32_t context_flags;
+
+ uint32_t pc;
+ uint32_t ra;
+ uint32_t sp;
+ uint32_t gp;
+ uint32_t tp;
+ uint32_t t0;
+ uint32_t t1;
+ uint32_t t2;
+ uint32_t s0;
+ uint32_t s1;
+ uint32_t a0;
+ uint32_t a1;
+ uint32_t a2;
+ uint32_t a3;
+ uint32_t a4;
+ uint32_t a5;
+ uint32_t a6;
+ uint32_t a7;
+ uint32_t s2;
+ uint32_t s3;
+ uint32_t s4;
+ uint32_t s5;
+ uint32_t s6;
+ uint32_t s7;
+ uint32_t s8;
+ uint32_t s9;
+ uint32_t s10;
+ uint32_t s11;
+ uint32_t t3;
+ uint32_t t4;
+ uint32_t t5;
+ uint32_t t6;
+
+ MDFloatingSaveAreaRISCV float_save;
+} MDRawContextRISCV;
+
+/* For (MDRawContextRISCV64).context_flags. These values indicate the type of
+ * context stored in the structure. */
+#define MD_CONTEXT_RISCV64 0x08000000
+#define MD_CONTEXT_RISCV64_INTEGER (MD_CONTEXT_RISCV64 | 0x00000001)
+#define MD_CONTEXT_RISCV64_FLOATING_POINT (MD_CONTEXT_RISCV64 | 0x00000004)
+#define MD_CONTEXT_RISCV64_FULL (MD_CONTEXT_RISCV64_INTEGER | \
+ MD_CONTEXT_RISCV64_FLOATING_POINT)
+
+typedef struct {
+ /* Determines which fields of this struct are populated */
+ uint32_t context_flags;
+
+ uint64_t pc;
+ uint64_t ra;
+ uint64_t sp;
+ uint64_t gp;
+ uint64_t tp;
+ uint64_t t0;
+ uint64_t t1;
+ uint64_t t2;
+ uint64_t s0;
+ uint64_t s1;
+ uint64_t a0;
+ uint64_t a1;
+ uint64_t a2;
+ uint64_t a3;
+ uint64_t a4;
+ uint64_t a5;
+ uint64_t a6;
+ uint64_t a7;
+ uint64_t s2;
+ uint64_t s3;
+ uint64_t s4;
+ uint64_t s5;
+ uint64_t s6;
+ uint64_t s7;
+ uint64_t s8;
+ uint64_t s9;
+ uint64_t s10;
+ uint64_t s11;
+ uint64_t t3;
+ uint64_t t4;
+ uint64_t t5;
+ uint64_t t6;
+
+ MDFloatingSaveAreaRISCV float_save;
+} MDRawContextRISCV64;
+
+
+#endif /* GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_RISCV_H__ */
diff --git a/src/google_breakpad/common/minidump_cpu_sparc.h b/src/google_breakpad/common/minidump_cpu_sparc.h
index 95c08b17..6452588a 100644
--- a/src/google_breakpad/common/minidump_cpu_sparc.h
+++ b/src/google_breakpad/common/minidump_cpu_sparc.h
@@ -1,5 +1,4 @@
-/* Copyright (c) 2006, Google Inc.
- * All rights reserved.
+/* Copyright 2006 Google LLC
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
- * * Neither the name of Google Inc. nor the names of its
+ * * Neither the name of Google LLC nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
diff --git a/src/google_breakpad/common/minidump_cpu_x86.h b/src/google_breakpad/common/minidump_cpu_x86.h
index e09cb7cb..add1e225 100644
--- a/src/google_breakpad/common/minidump_cpu_x86.h
+++ b/src/google_breakpad/common/minidump_cpu_x86.h
@@ -1,5 +1,4 @@
-/* Copyright (c) 2006, Google Inc.
- * All rights reserved.
+/* Copyright 2006 Google LLC
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
- * * Neither the name of Google Inc. nor the names of its
+ * * Neither the name of Google LLC nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
diff --git a/src/google_breakpad/common/minidump_exception_fuchsia.h b/src/google_breakpad/common/minidump_exception_fuchsia.h
index f26a8a2a..169094b2 100644
--- a/src/google_breakpad/common/minidump_exception_fuchsia.h
+++ b/src/google_breakpad/common/minidump_exception_fuchsia.h
@@ -1,5 +1,4 @@
-/* Copyright (c) 2019, Google Inc.
- * All rights reserved.
+/* Copyright 2019 Google LLC
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
- * * Neither the name of Google Inc. nor the names of its
+ * * Neither the name of Google LLC nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
diff --git a/src/google_breakpad/common/minidump_exception_linux.h b/src/google_breakpad/common/minidump_exception_linux.h
index 6138d5d7..354cdd6b 100644
--- a/src/google_breakpad/common/minidump_exception_linux.h
+++ b/src/google_breakpad/common/minidump_exception_linux.h
@@ -1,5 +1,4 @@
-/* Copyright (c) 2006, Google Inc.
- * All rights reserved.
+/* Copyright 2006 Google LLC
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
- * * Neither the name of Google Inc. nor the names of its
+ * * Neither the name of Google LLC nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
diff --git a/src/google_breakpad/common/minidump_exception_mac.h b/src/google_breakpad/common/minidump_exception_mac.h
index fadbf4ef..acfafaa0 100644
--- a/src/google_breakpad/common/minidump_exception_mac.h
+++ b/src/google_breakpad/common/minidump_exception_mac.h
@@ -1,5 +1,4 @@
-/* Copyright (c) 2006, Google Inc.
- * All rights reserved.
+/* Copyright 2006 Google LLC
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
- * * Neither the name of Google Inc. nor the names of its
+ * * Neither the name of Google LLC nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
@@ -66,9 +65,15 @@ typedef enum {
MD_EXCEPTION_MAC_MACH_SYSCALL = 8,
/* EXC_MACH_SYSCALL */
MD_EXCEPTION_MAC_RPC_ALERT = 9,
+ /* EXC_RESOURCE */
+ MD_EXCEPTION_MAC_RESOURCE = 11,
+ /* EXC_GUARD */
+ MD_EXCEPTION_MAC_GUARD = 12,
/* EXC_RPC_ALERT */
- MD_EXCEPTION_MAC_SIMULATED = 0x43507378
+ MD_EXCEPTION_MAC_SIMULATED = 0x43507378,
/* Fake exception code used by Crashpad's SimulateCrash ('CPsx'). */
+ MD_NS_EXCEPTION_SIMULATED = 0x43506E78
+ /* Fake exception code used by Crashpad's uncaught exceptions ('CPnx'). */
} MDExceptionMac;
/* For (MDException).exception_flags. Breakpad minidump extension for Mac OS X
diff --git a/src/google_breakpad/common/minidump_exception_ps3.h b/src/google_breakpad/common/minidump_exception_ps3.h
index adff5a6b..dd87d7a7 100644
--- a/src/google_breakpad/common/minidump_exception_ps3.h
+++ b/src/google_breakpad/common/minidump_exception_ps3.h
@@ -1,5 +1,4 @@
-/* Copyright (c) 2013, Google Inc.
- * All rights reserved.
+/* Copyright 2013 Google LLC
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
- * * Neither the name of Google Inc. nor the names of its
+ * * Neither the name of Google LLC nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
diff --git a/src/google_breakpad/common/minidump_exception_solaris.h b/src/google_breakpad/common/minidump_exception_solaris.h
index f18ddf42..16641919 100644
--- a/src/google_breakpad/common/minidump_exception_solaris.h
+++ b/src/google_breakpad/common/minidump_exception_solaris.h
@@ -1,5 +1,4 @@
-/* Copyright (c) 2006, Google Inc.
- * All rights reserved.
+/* Copyright 2006 Google LLC
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
- * * Neither the name of Google Inc. nor the names of its
+ * * Neither the name of Google LLC nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
diff --git a/src/google_breakpad/common/minidump_exception_win32.h b/src/google_breakpad/common/minidump_exception_win32.h
index 4b5d57c8..0431a3fa 100644
--- a/src/google_breakpad/common/minidump_exception_win32.h
+++ b/src/google_breakpad/common/minidump_exception_win32.h
@@ -1,5 +1,4 @@
-/* Copyright (c) 2006, Google Inc.
- * All rights reserved.
+/* Copyright 2006 Google LLC
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
- * * Neither the name of Google Inc. nor the names of its
+ * * Neither the name of Google LLC nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
@@ -2266,4 +2265,77 @@ typedef enum {
MD_IN_PAGE_ERROR_WIN_EXEC = 8
} MDInPageErrorTypeWin;
+// These constants are defined in winnt.h and are used with the
+// STATUS_STACK_BUFFER_OVERRUN exception as exception subcodes.
+typedef enum {
+ MD_FAST_FAIL_LEGACY_GS_VIOLATION = 0,
+ MD_FAST_FAIL_VTGUARD_CHECK_FAILURE = 1,
+ MD_FAST_FAIL_STACK_COOKIE_CHECK_FAILURE = 2,
+ MD_FAST_FAIL_CORRUPT_LIST_ENTRY = 3,
+ MD_FAST_FAIL_INCORRECT_STACK = 4,
+ MD_FAST_FAIL_INVALID_ARG = 5,
+ MD_FAST_FAIL_GS_COOKIE_INIT = 6,
+ MD_FAST_FAIL_FATAL_APP_EXIT = 7,
+ MD_FAST_FAIL_RANGE_CHECK_FAILURE = 8,
+ MD_FAST_FAIL_UNSAFE_REGISTRY_ACCESS = 9,
+ MD_FAST_FAIL_GUARD_ICALL_CHECK_FAILURE = 10,
+ MD_FAST_FAIL_GUARD_WRITE_CHECK_FAILURE = 11,
+ MD_FAST_FAIL_INVALID_FIBER_SWITCH = 12,
+ MD_FAST_FAIL_INVALID_SET_OF_CONTEXT = 13,
+ MD_FAST_FAIL_INVALID_REFERENCE_COUNT = 14,
+ MD_FAST_FAIL_INVALID_JUMP_BUFFER = 18,
+ MD_FAST_FAIL_MRDATA_MODIFIED = 19,
+ MD_FAST_FAIL_CERTIFICATION_FAILURE = 20,
+ MD_FAST_FAIL_INVALID_EXCEPTION_CHAIN = 21,
+ MD_FAST_FAIL_CRYPTO_LIBRARY = 22,
+ MD_FAST_FAIL_INVALID_CALL_IN_DLL_CALLOUT = 23,
+ MD_FAST_FAIL_INVALID_IMAGE_BASE = 24,
+ MD_FAST_FAIL_DLOAD_PROTECTION_FAILURE = 25,
+ MD_FAST_FAIL_UNSAFE_EXTENSION_CALL = 26,
+ MD_FAST_FAIL_DEPRECATED_SERVICE_INVOKED = 27,
+ MD_FAST_FAIL_INVALID_BUFFER_ACCESS = 28,
+ MD_FAST_FAIL_INVALID_BALANCED_TREE = 29,
+ MD_FAST_FAIL_INVALID_NEXT_THREAD = 30,
+ MD_FAST_FAIL_GUARD_ICALL_CHECK_SUPPRESSED = 31,
+ MD_FAST_FAIL_APCS_DISABLED = 32,
+ MD_FAST_FAIL_INVALID_IDLE_STATE = 33,
+ MD_FAST_FAIL_MRDATA_PROTECTION_FAILURE = 34,
+ MD_FAST_FAIL_UNEXPECTED_HEAP_EXCEPTION = 35,
+ MD_FAST_FAIL_INVALID_LOCK_STATE = 36,
+ MD_FAST_FAIL_GUARD_JUMPTABLE = 37,
+ MD_FAST_FAIL_INVALID_LONGJUMP_TARGET = 38,
+ MD_FAST_FAIL_INVALID_DISPATCH_CONTEXT = 39,
+ MD_FAST_FAIL_INVALID_THREAD = 40,
+ MD_FAST_FAIL_INVALID_SYSCALL_NUMBER = 41,
+ MD_FAST_FAIL_INVALID_FILE_OPERATION = 42,
+ MD_FAST_FAIL_LPAC_ACCESS_DENIED = 43,
+ MD_FAST_FAIL_GUARD_SS_FAILURE = 44,
+ MD_FAST_FAIL_LOADER_CONTINUITY_FAILURE = 45,
+ MD_FAST_FAIL_GUARD_EXPORT_SUPPRESSION_FAILURE = 46,
+ MD_FAST_FAIL_INVALID_CONTROL_STACK = 47,
+ MD_FAST_FAIL_SET_CONTEXT_DENIED = 48,
+ MD_FAST_FAIL_INVALID_IAT = 49,
+ MD_FAST_FAIL_HEAP_METADATA_CORRUPTION = 50,
+ MD_FAST_FAIL_PAYLOAD_RESTRICTION_VIOLATION = 51,
+ MD_FAST_FAIL_LOW_LABEL_ACCESS_DENIED = 52,
+ MD_FAST_FAIL_ENCLAVE_CALL_FAILURE = 53,
+ MD_FAST_FAIL_UNHANDLED_LSS_EXCEPTON = 54,
+ MD_FAST_FAIL_ADMINLESS_ACCESS_DENIED = 55,
+ MD_FAST_FAIL_UNEXPECTED_CALL = 56,
+ MD_FAST_FAIL_CONTROL_INVALID_RETURN_ADDRESS = 57,
+ MD_FAST_FAIL_UNEXPECTED_HOST_BEHAVIOR = 58,
+ MD_FAST_FAIL_FLAGS_CORRUPTION = 59,
+ MD_FAST_FAIL_VEH_CORRUPTION = 60,
+ MD_FAST_FAIL_ETW_CORRUPTION = 61,
+ MD_FAST_FAIL_RIO_ABORT = 62,
+ MD_FAST_FAIL_INVALID_PFN = 63,
+ MD_FAST_FAIL_GUARD_ICALL_CHECK_FAILURE_XFG = 64,
+ MD_FAST_FAIL_CAST_GUARD = 65,
+ MD_FAST_FAIL_HOST_VISIBILITY_CHANGE = 66,
+ MD_FAST_FAIL_KERNEL_CET_SHADOW_STACK_ASSIST = 67,
+ MD_FAST_FAIL_PATCH_CALLBACK_FAILED = 68,
+ MD_FAST_FAIL_NTDLL_PATCH_FAILED = 69,
+ MD_FAST_FAIL_INVALID_FLS_DATA = 70
+} MDFastFailSubcodeTypeWin;
+
#endif /* GOOGLE_BREAKPAD_COMMON_MINIDUMP_EXCEPTION_WIN32_H__ */
diff --git a/src/google_breakpad/common/minidump_format.h b/src/google_breakpad/common/minidump_format.h
index 6eceddbb..1526afce 100644
--- a/src/google_breakpad/common/minidump_format.h
+++ b/src/google_breakpad/common/minidump_format.h
@@ -1,5 +1,4 @@
-/* Copyright (c) 2006, Google Inc.
- * All rights reserved.
+/* Copyright 2006 Google LLC
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
- * * Neither the name of Google Inc. nor the names of its
+ * * Neither the name of Google LLC nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
@@ -118,6 +117,7 @@ typedef struct {
#include "minidump_cpu_mips.h"
#include "minidump_cpu_ppc.h"
#include "minidump_cpu_ppc64.h"
+#include "minidump_cpu_riscv.h"
#include "minidump_cpu_sparc.h"
#include "minidump_cpu_x86.h"
@@ -239,6 +239,15 @@ typedef struct {
MDRVA rva;
} MDLocationDescriptor; /* MINIDUMP_LOCATION_DESCRIPTOR */
+/* An MDRVA64 is an 64-bit offset into the minidump file. The beginning of the
+ * MDRawHeader is at offset 0. */
+typedef uint64_t MDRVA64; /* RVA64 */
+
+typedef struct {
+ uint64_t data_size;
+ MDRVA64 rva;
+} MDLocationDescriptor64; /* MINIDUMP_LOCATION_DESCRIPTOR64 */
+
typedef struct {
/* The base address of the memory range on the host that produced the
@@ -332,6 +341,7 @@ typedef enum {
MD_JAVASCRIPT_DATA_STREAM = 20,
MD_SYSTEM_MEMORY_INFO_STREAM = 21,
MD_PROCESS_VM_COUNTERS_STREAM = 22,
+ MD_THREAD_NAME_LIST_STREAM = 24, /* MDRawThreadNameList */
MD_LAST_RESERVED_STREAM = 0x0000ffff,
/* Breakpad extension types. 0x4767 = "Gg" */
@@ -382,6 +392,20 @@ typedef struct {
static const size_t MDRawThreadList_minsize = offsetof(MDRawThreadList,
threads[0]);
+#pragma pack(push, 4)
+typedef struct {
+ uint32_t thread_id;
+ MDRVA64 thread_name_rva; /* MDString */
+} MDRawThreadName; /* MINIDUMP_THREAD_NAME */
+
+typedef struct {
+ uint32_t number_of_thread_names;
+ MDRawThreadName thread_names[1];
+} MDRawThreadNameList; /* MINIDUMP_THREAD_NAME_LIST */
+#pragma pack(pop)
+
+static const size_t MDRawThreadNameList_minsize =
+ offsetof(MDRawThreadNameList, thread_names[0]);
typedef struct {
uint64_t base_of_image;
@@ -529,7 +553,7 @@ static const size_t MDRawMemoryList_minsize = offsetof(MDRawMemoryList,
memory_ranges[0]);
-#define MD_EXCEPTION_MAXIMUM_PARAMETERS 15
+#define MD_EXCEPTION_MAXIMUM_PARAMETERS 15u
typedef struct {
uint32_t exception_code; /* Windows: MDExceptionCodeWin,
@@ -660,6 +684,8 @@ typedef enum {
MD_CPU_ARCHITECTURE_PPC64 = 0x8002, /* Breakpad-defined value for PPC64 */
MD_CPU_ARCHITECTURE_ARM64_OLD = 0x8003, /* Breakpad-defined value for ARM64 */
MD_CPU_ARCHITECTURE_MIPS64 = 0x8004, /* Breakpad-defined value for MIPS64 */
+ MD_CPU_ARCHITECTURE_RISCV = 0x8005, /* Breakpad-defined value for RISCV */
+ MD_CPU_ARCHITECTURE_RISCV64 = 0x8006, /* Breakpad-defined value for RISCV64 */
MD_CPU_ARCHITECTURE_UNKNOWN = 0xffff /* PROCESSOR_ARCHITECTURE_UNKNOWN */
} MDCPUArchitecture;
@@ -1071,9 +1097,22 @@ typedef struct {
} MDRawSimpleStringDictionary;
typedef struct {
+ MDRVA name;
+ uint16_t type;
+ uint16_t reserved;
+ MDRVA value;
+} MDRawCrashpadAnnotation;
+
+typedef struct {
+ uint32_t count;
+ MDLocationDescriptor objects[0]; /* MDRawCrashpadAnnotation */
+} MDRawCrashpadAnnotationList;
+
+typedef struct {
uint32_t version;
MDLocationDescriptor list_annotations;
MDLocationDescriptor simple_annotations; /* MDRawSimpleStringDictionary */
+ MDLocationDescriptor annotation_objects; /* MDRawCrashpadAnnotationList */
} MDRawModuleCrashpadInfo;
typedef struct {
@@ -1092,6 +1131,8 @@ typedef struct {
MDGUID client_id;
MDLocationDescriptor simple_annotations; /* MDRawSimpleStringDictionary */
MDLocationDescriptor module_list; /* MDRawModuleCrashpadInfoList */
+ uint32_t reserved;
+ uint64_t address_mask;
} MDRawCrashpadInfo;
#if defined(_MSC_VER)
diff --git a/src/google_breakpad/common/minidump_size.h b/src/google_breakpad/common/minidump_size.h
index fae57923..f9abdc36 100644
--- a/src/google_breakpad/common/minidump_size.h
+++ b/src/google_breakpad/common/minidump_size.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2007, Google Inc.
-// All rights reserved.
+// Copyright 2007 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/google_breakpad/processor/basic_source_line_resolver.h b/src/google_breakpad/processor/basic_source_line_resolver.h
index 91fb7841..e86b28d2 100644
--- a/src/google_breakpad/processor/basic_source_line_resolver.h
+++ b/src/google_breakpad/processor/basic_source_line_resolver.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2010 Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -40,6 +39,7 @@
#include <map>
#include <string>
+#include <vector>
#include "common/using_std_string.h"
#include "google_breakpad/processor/source_line_resolver_base.h"
@@ -84,15 +84,50 @@ class BasicSourceLineResolver : public SourceLineResolverBase {
// Helper class, containing useful methods for parsing of Breakpad symbol files.
class SymbolParseHelper {
public:
+ using MemAddr = SourceLineResolverInterface::MemAddr;
+
// Parses a |file_line| declaration. Returns true on success.
// Format: FILE <id> <filename>.
// Notice, that this method modifies the input |file_line| which is why it
// can't be const. On success, <id>, and <filename> are stored in |*index|,
// and |*filename|. No allocation is done, |*filename| simply points inside
// |file_line|.
- static bool ParseFile(char *file_line, // in
- long *index, // out
- char **filename); // out
+ static bool ParseFile(char* file_line, // in
+ long* index, // out
+ char** filename); // out
+
+ // Parses a |inline_origin_line| declaration. Returns true on success.
+ // Old Format: INLINE_ORIGIN <origin_id> <file_id> <name>.
+ // New Format: INLINE_ORIGIN <origin_id> <name>.
+ // Notice, that this method modifies the input |inline_origin_line| which is
+ // why it can't be const. On success, <has_file_id>, <origin_id>, <file_id>
+ // and <name> are stored in |*has_file_id*|, |*origin_id|, |*file_id|, and
+ // |*name|. No allocation is done, |*name| simply points inside
+ // |inline_origin_line|.
+ static bool ParseInlineOrigin(char* inline_origin_line, // in
+ bool* has_file_id, // out
+ long* origin_id, // out
+ long* file_id, // out
+ char** name); // out
+
+ // Parses a |inline| declaration. Returns true on success.
+ // Old Format: INLINE <inline_nest_level> <call_site_line> <origin_id>
+ // [<address> <size>]+
+ // New Format: INLINE <inline_nest_level> <call_site_line> <call_site_file_id>
+ // <origin_id> [<address> <size>]+
+ // Notice, that this method modifies the input |inline|
+ // which is why it can't be const. On success, <has_call_site_file_id>,
+ // <inline_nest_level>, <call_site_line> and <origin_id> are stored in
+ // |*has_call_site_file_id*|, |*inline_nest_level|, |*call_site_line|, and
+ // |*origin_id|, and all pairs of (<address>, <size>) are added into ranges.
+ static bool ParseInline(
+ char* inline_line, // in
+ bool* has_call_site_file_id, // out
+ long* inline_nest_level, // out
+ long* call_site_line, // out
+ long* call_site_file_id, // out
+ long* origin_id, // out
+ std::vector<std::pair<MemAddr, MemAddr>>* ranges); // out
// Parses a |function_line| declaration. Returns true on success.
// Format: FUNC [<multiple>] <address> <size> <stack_param_size> <name>.
@@ -101,12 +136,12 @@ class SymbolParseHelper {
// <stack_param_size>, and <name> are stored in |*is_multiple|, |*address|,
// |*size|, |*stack_param_size|, and |*name|. No allocation is done, |*name|
// simply points inside |function_line|.
- static bool ParseFunction(char *function_line, // in
- bool *is_multiple, // out
- uint64_t *address, // out
- uint64_t *size, // out
- long *stack_param_size, // out
- char **name); // out
+ static bool ParseFunction(char* function_line, // in
+ bool* is_multiple, // out
+ uint64_t* address, // out
+ uint64_t* size, // out
+ long* stack_param_size, // out
+ char** name); // out
// Parses a |line| declaration. Returns true on success.
// Format: <address> <size> <line number> <source file id>
@@ -114,11 +149,11 @@ class SymbolParseHelper {
// it can't be const. On success, <address>, <size>, <line number>, and
// <source file id> are stored in |*address|, |*size|, |*line_number|, and
// |*source_file|.
- static bool ParseLine(char *line_line, // in
- uint64_t *address, // out
- uint64_t *size, // out
- long *line_number, // out
- long *source_file); // out
+ static bool ParseLine(char* line_line, // in
+ uint64_t* address, // out
+ uint64_t* size, // out
+ long* line_number, // out
+ long* source_file); // out
// Parses a |public_line| declaration. Returns true on success.
// Format: PUBLIC [<multiple>] <address> <stack_param_size> <name>
@@ -127,15 +162,15 @@ class SymbolParseHelper {
// <stack_param_size>, <name> are stored in |*is_multiple|, |*address|,
// |*stack_param_size|, and |*name|. No allocation is done, |*name| simply
// points inside |public_line|.
- static bool ParsePublicSymbol(char *public_line, // in
- bool *is_multiple, // out
- uint64_t *address, // out
- long *stack_param_size, // out
- char **name); // out
+ static bool ParsePublicSymbol(char* public_line, // in
+ bool* is_multiple, // out
+ uint64_t* address, // out
+ long* stack_param_size, // out
+ char** name); // out
private:
// Used for success checks after strtoull and strtol.
- static bool IsValidAfterNumber(char *after_number);
+ static bool IsValidAfterNumber(char* after_number);
// Only allow static methods.
SymbolParseHelper();
diff --git a/src/google_breakpad/processor/call_stack.h b/src/google_breakpad/processor/call_stack.h
index c5914231..9bf062f8 100644
--- a/src/google_breakpad/processor/call_stack.h
+++ b/src/google_breakpad/processor/call_stack.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2006, Google Inc.
-// All rights reserved.
+// Copyright 2006 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/google_breakpad/processor/code_module.h b/src/google_breakpad/processor/code_module.h
index 29b8d9c9..76bbfab8 100644
--- a/src/google_breakpad/processor/code_module.h
+++ b/src/google_breakpad/processor/code_module.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2006, Google Inc.
-// All rights reserved.
+// Copyright 2006 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/google_breakpad/processor/code_modules.h b/src/google_breakpad/processor/code_modules.h
index 74f113c1..7538328b 100644
--- a/src/google_breakpad/processor/code_modules.h
+++ b/src/google_breakpad/processor/code_modules.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2006, Google Inc.
-// All rights reserved.
+// Copyright 2006 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/google_breakpad/processor/dump_context.h b/src/google_breakpad/processor/dump_context.h
index df80bf7e..7a1c643e 100644
--- a/src/google_breakpad/processor/dump_context.h
+++ b/src/google_breakpad/processor/dump_context.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2014 Google Inc.
-// All rights reserved.
+// Copyright 2014 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -54,14 +53,16 @@ class DumpContext : public DumpObject {
// Returns raw CPU-specific context data for the named CPU type. If the
// context data does not match the CPU type or does not exist, returns NULL.
- const MDRawContextAMD64* GetContextAMD64() const;
- const MDRawContextARM* GetContextARM() const;
- const MDRawContextARM64* GetContextARM64() const;
- const MDRawContextMIPS* GetContextMIPS() const;
- const MDRawContextPPC* GetContextPPC() const;
- const MDRawContextPPC64* GetContextPPC64() const;
- const MDRawContextSPARC* GetContextSPARC() const;
- const MDRawContextX86* GetContextX86() const;
+ const MDRawContextAMD64* GetContextAMD64() const;
+ const MDRawContextARM* GetContextARM() const;
+ const MDRawContextARM64* GetContextARM64() const;
+ const MDRawContextMIPS* GetContextMIPS() const;
+ const MDRawContextPPC* GetContextPPC() const;
+ const MDRawContextPPC64* GetContextPPC64() const;
+ const MDRawContextSPARC* GetContextSPARC() const;
+ const MDRawContextX86* GetContextX86() const;
+ const MDRawContextRISCV* GetContextRISCV() const;
+ const MDRawContextRISCV64* GetContextRISCV64() const;
// A convenience method to get the instruction pointer out of the
// MDRawContext, since it varies per-CPU architecture.
@@ -87,6 +88,8 @@ class DumpContext : public DumpObject {
void SetContextARM(MDRawContextARM* arm);
void SetContextARM64(MDRawContextARM64* arm64);
void SetContextMIPS(MDRawContextMIPS* ctx_mips);
+ void SetContextRISCV(MDRawContextRISCV* riscv);
+ void SetContextRISCV64(MDRawContextRISCV64* riscv64);
// Free the CPU-specific context structure.
void FreeContext();
@@ -94,17 +97,19 @@ class DumpContext : public DumpObject {
private:
// The CPU-specific context structure.
union {
- MDRawContextBase* base;
- MDRawContextX86* x86;
- MDRawContextPPC* ppc;
- MDRawContextPPC64* ppc64;
- MDRawContextAMD64* amd64;
+ MDRawContextBase* base;
+ MDRawContextX86* x86;
+ MDRawContextPPC* ppc;
+ MDRawContextPPC64* ppc64;
+ MDRawContextAMD64* amd64;
// on Solaris SPARC, sparc is defined as a numeric constant,
// so variables can NOT be named as sparc
- MDRawContextSPARC* ctx_sparc;
- MDRawContextARM* arm;
- MDRawContextARM64* arm64;
- MDRawContextMIPS* ctx_mips;
+ MDRawContextSPARC* ctx_sparc;
+ MDRawContextARM* arm;
+ MDRawContextARM64* arm64;
+ MDRawContextMIPS* ctx_mips;
+ MDRawContextRISCV* riscv;
+ MDRawContextRISCV64* riscv64;
} context_;
// Store this separately because of the weirdo AMD64 context
diff --git a/src/google_breakpad/processor/dump_object.h b/src/google_breakpad/processor/dump_object.h
index 112f687f..0b1f4884 100644
--- a/src/google_breakpad/processor/dump_object.h
+++ b/src/google_breakpad/processor/dump_object.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2014 Google Inc.
-// All rights reserved.
+// Copyright 2014 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/google_breakpad/processor/exception_record.h b/src/google_breakpad/processor/exception_record.h
index eac6c90a..aa2b0de3 100644
--- a/src/google_breakpad/processor/exception_record.h
+++ b/src/google_breakpad/processor/exception_record.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2019 Google Inc.
-// All rights reserved.
+// Copyright 2019 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/google_breakpad/processor/exploitability.h b/src/google_breakpad/processor/exploitability.h
index 014413c9..0b51ba13 100644
--- a/src/google_breakpad/processor/exploitability.h
+++ b/src/google_breakpad/processor/exploitability.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2010 Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/google_breakpad/processor/fast_source_line_resolver.h b/src/google_breakpad/processor/fast_source_line_resolver.h
index fdf91077..11cec75e 100644
--- a/src/google_breakpad/processor/fast_source_line_resolver.h
+++ b/src/google_breakpad/processor/fast_source_line_resolver.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2010 Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -79,6 +78,8 @@ class FastSourceLineResolver : public SourceLineResolverBase {
// SourceLineResolverBase.
struct Line;
struct Function;
+ struct Inline;
+ struct InlineOrigin;
struct PublicSymbol;
class Module;
diff --git a/src/google_breakpad/processor/memory_region.h b/src/google_breakpad/processor/memory_region.h
index 30f88df4..378fcc39 100644
--- a/src/google_breakpad/processor/memory_region.h
+++ b/src/google_breakpad/processor/memory_region.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2010 Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/google_breakpad/processor/microdump.h b/src/google_breakpad/processor/microdump.h
index 02ebdcd7..7c2f3e66 100644
--- a/src/google_breakpad/processor/microdump.h
+++ b/src/google_breakpad/processor/microdump.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2014 Google Inc.
-// All rights reserved.
+// Copyright 2014 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/google_breakpad/processor/microdump_processor.h b/src/google_breakpad/processor/microdump_processor.h
index 60d14a54..abf468f4 100644
--- a/src/google_breakpad/processor/microdump_processor.h
+++ b/src/google_breakpad/processor/microdump_processor.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2014, Google Inc.
-// All rights reserved.
+// Copyright 2014 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/google_breakpad/processor/minidump.h b/src/google_breakpad/processor/minidump.h
index d712cb66..934a0e3e 100644
--- a/src/google_breakpad/processor/minidump.h
+++ b/src/google_breakpad/processor/minidump.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2010 Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -291,7 +290,7 @@ class MinidumpThread : public MinidumpObject {
// so a special getter is provided to retrieve this data from the
// MDRawThread structure. Returns false if the thread ID cannot be
// determined.
- virtual bool GetThreadID(uint32_t *thread_id) const;
+ virtual bool GetThreadID(uint32_t* thread_id) const;
// Print a human-readable representation of the object to stdout.
void Print();
@@ -370,6 +369,86 @@ class MinidumpThreadList : public MinidumpStream {
DISALLOW_COPY_AND_ASSIGN(MinidumpThreadList);
};
+// MinidumpThreadName contains the name of a thread.
+class MinidumpThreadName : public MinidumpObject {
+ public:
+ virtual ~MinidumpThreadName();
+
+ const MDRawThreadName* thread_name() const {
+ return valid_ ? &thread_name_ : NULL;
+ }
+
+ // Gets the thread ID.
+ virtual bool GetThreadID(uint32_t* thread_id) const;
+
+ // Print a human-readable representation of the object to stdout.
+ void Print();
+
+ // Returns the name of the thread.
+ virtual std::string GetThreadName() const;
+
+ protected:
+ explicit MinidumpThreadName(Minidump* minidump);
+
+ private:
+ // These objects are managed by MinidumpThreadNameList.
+ friend class MinidumpThreadNameList;
+
+ // This works like MinidumpStream::Read, but is driven by
+ // MinidumpThreadNameList. No size checking is done, because
+ // MinidumpThreadNameList handles that directly.
+ bool Read();
+
+ // Reads indirectly-referenced data, including the thread name.
+ bool ReadAuxiliaryData();
+
+ // True after a successful Read. This is different from valid_, which is not
+ // set true until ReadAuxiliaryData also completes successfully.
+ // thread_name_valid_ is only used by ReadAuxiliaryData and the functions it
+ // calls to determine whether the object is ready for auxiliary data to be
+ // read.
+ bool thread_name_valid_;
+
+ MDRawThreadName thread_name_;
+
+ // Cached thread name.
+ const string* name_;
+};
+
+// MinidumpThreadNameList contains all of the names of the threads (as
+// MinidumpThreadNames) in a process.
+class MinidumpThreadNameList : public MinidumpStream {
+ public:
+ virtual ~MinidumpThreadNameList();
+
+ virtual unsigned int thread_name_count() const {
+ return valid_ ? thread_name_count_ : 0;
+ }
+
+ // Sequential access to thread names.
+ virtual MinidumpThreadName* GetThreadNameAtIndex(unsigned int index) const;
+
+ // Print a human-readable representation of the object to stdout.
+ void Print();
+
+ protected:
+ explicit MinidumpThreadNameList(Minidump* aMinidump);
+
+ private:
+ friend class Minidump;
+
+ typedef vector<MinidumpThreadName> MinidumpThreadNames;
+
+ static const uint32_t kStreamType = MD_THREAD_NAME_LIST_STREAM;
+
+ bool Read(uint32_t aExpectedSize) override;
+
+ // The list of thread names.
+ MinidumpThreadNames* thread_names_;
+ uint32_t thread_name_count_;
+
+ DISALLOW_COPY_AND_ASSIGN(MinidumpThreadNameList);
+};
// MinidumpModule wraps MDRawModule, which contains information about loaded
// code modules. Access is provided to various data referenced indirectly
@@ -549,9 +628,9 @@ class MinidumpModuleList : public MinidumpStream,
static uint32_t max_modules_;
// Access to modules using addresses as the key.
- RangeMap<uint64_t, unsigned int> *range_map_;
+ RangeMap<uint64_t, unsigned int>* range_map_;
- MinidumpModules *modules_;
+ MinidumpModules* modules_;
uint32_t module_count_;
DISALLOW_COPY_AND_ASSIGN(MinidumpModuleList);
@@ -606,16 +685,16 @@ class MinidumpMemoryList : public MinidumpStream {
static uint32_t max_regions_;
// Access to memory regions using addresses as the key.
- RangeMap<uint64_t, unsigned int> *range_map_;
+ RangeMap<uint64_t, unsigned int>* range_map_;
// The list of descriptors. This is maintained separately from the list
// of regions, because MemoryRegion doesn't own its MemoryDescriptor, it
// maintains a pointer to it. descriptors_ provides the storage for this
// purpose.
- MemoryDescriptors *descriptors_;
+ MemoryDescriptors* descriptors_;
// The list of regions.
- MemoryRegions *regions_;
+ MemoryRegions* regions_;
uint32_t region_count_;
DISALLOW_COPY_AND_ASSIGN(MinidumpMemoryList);
@@ -640,7 +719,7 @@ class MinidumpException : public MinidumpStream {
// so a special getter is provided to retrieve this data from the
// MDRawExceptionStream structure. Returns false if the thread ID cannot
// be determined.
- bool GetThreadID(uint32_t *thread_id) const;
+ bool GetThreadID(uint32_t* thread_id) const;
MinidumpContext* GetContext();
@@ -862,9 +941,9 @@ class MinidumpUnloadedModuleList : public MinidumpStream,
static uint32_t max_modules_;
// Access to module indices using addresses as the key.
- RangeMap<uint64_t, unsigned int> *range_map_;
+ RangeMap<uint64_t, unsigned int>* range_map_;
- MinidumpUnloadedModules *unloaded_modules_;
+ MinidumpUnloadedModules* unloaded_modules_;
uint32_t module_count_;
DISALLOW_COPY_AND_ASSIGN(MinidumpUnloadedModuleList);
@@ -919,8 +998,8 @@ class MinidumpBreakpadInfo : public MinidumpStream {
// treatment, so special getters are provided to retrieve this data from
// the MDRawBreakpadInfo structure. The getters return false if the thread
// IDs cannot be determined.
- bool GetDumpThreadID(uint32_t *thread_id) const;
- bool GetRequestingThreadID(uint32_t *thread_id) const;
+ bool GetDumpThreadID(uint32_t* thread_id) const;
+ bool GetRequestingThreadID(uint32_t* thread_id) const;
// Print a human-readable representation of the object to stdout.
void Print();
@@ -1003,7 +1082,7 @@ class MinidumpMemoryInfoList : public MinidumpStream {
bool Read(uint32_t expected_size) override;
// Access to memory info using addresses as the key.
- RangeMap<uint64_t, unsigned int> *range_map_;
+ RangeMap<uint64_t, unsigned int>* range_map_;
MinidumpMemoryInfos* infos_;
uint32_t info_count_;
@@ -1056,7 +1135,7 @@ class MinidumpLinuxMaps : public MinidumpObject {
friend class MinidumpLinuxMapsList;
// This caller owns the pointer.
- explicit MinidumpLinuxMaps(Minidump *minidump);
+ explicit MinidumpLinuxMaps(Minidump* minidump);
// The memory region struct that this class wraps.
MappedMemoryRegion region_;
@@ -1075,9 +1154,9 @@ class MinidumpLinuxMapsList : public MinidumpStream {
unsigned int get_maps_count() const { return valid_ ? maps_count_ : 0; }
// Get mapping at the given memory address. The caller owns the pointer.
- const MinidumpLinuxMaps *GetLinuxMapsForAddress(uint64_t address) const;
+ const MinidumpLinuxMaps* GetLinuxMapsForAddress(uint64_t address) const;
// Get mapping at the given index. The caller owns the pointer.
- const MinidumpLinuxMaps *GetLinuxMapsAtIndex(unsigned int index) const;
+ const MinidumpLinuxMaps* GetLinuxMapsAtIndex(unsigned int index) const;
// Print the contents of /proc/self/maps to stdout.
void Print() const;
@@ -1085,12 +1164,12 @@ class MinidumpLinuxMapsList : public MinidumpStream {
private:
friend class Minidump;
- typedef vector<MinidumpLinuxMaps *> MinidumpLinuxMappings;
+ typedef vector<MinidumpLinuxMaps*> MinidumpLinuxMappings;
static const uint32_t kStreamType = MD_LINUX_MAPS;
// The caller owns the pointer.
- explicit MinidumpLinuxMapsList(Minidump *minidump);
+ explicit MinidumpLinuxMapsList(Minidump* minidump);
// Read and load the contents of the process mapping data.
// The stream should have data in the form of /proc/self/maps.
@@ -1098,7 +1177,7 @@ class MinidumpLinuxMapsList : public MinidumpStream {
bool Read(uint32_t expected_size) override;
// The list of individual mappings.
- MinidumpLinuxMappings *maps_;
+ MinidumpLinuxMappings* maps_;
// The number of mappings.
uint32_t maps_count_;
@@ -1110,10 +1189,21 @@ class MinidumpLinuxMapsList : public MinidumpStream {
// at the time the minidump was generated.
class MinidumpCrashpadInfo : public MinidumpStream {
public:
+ struct AnnotationObject {
+ uint16_t type;
+ std::string name;
+ std::vector<uint8_t> value;
+ };
+
const MDRawCrashpadInfo* crashpad_info() const {
return valid_ ? &crashpad_info_ : NULL;
}
+ const std::vector<std::vector<AnnotationObject>>*
+ GetModuleCrashpadInfoAnnotationObjects() const {
+ return valid_ ? &module_crashpad_info_annotation_objects_ : NULL;
+ }
+
// Print a human-readable representation of the object to stdout.
void Print();
@@ -1132,6 +1222,9 @@ class MinidumpCrashpadInfo : public MinidumpStream {
std::vector<std::vector<std::string>> module_crashpad_info_list_annotations_;
std::vector<std::map<std::string, std::string>>
module_crashpad_info_simple_annotations_;
+ std::vector<std::vector<AnnotationObject>>
+ module_crashpad_info_annotation_objects_;
+
std::map<std::string, std::string> simple_annotations_;
};
@@ -1188,6 +1281,7 @@ class Minidump {
// to avoid exposing an ugly API (GetStream needs to accept a garbage
// parameter).
virtual MinidumpThreadList* GetThreadList();
+ virtual MinidumpThreadNameList* GetThreadNameList();
virtual MinidumpModuleList* GetModuleList();
virtual MinidumpMemoryList* GetMemoryList();
virtual MinidumpException* GetException();
@@ -1200,7 +1294,7 @@ class Minidump {
MinidumpCrashpadInfo* GetCrashpadInfo();
// The next method also calls GetStream, but is exclusive for Linux dumps.
- virtual MinidumpLinuxMapsList *GetLinuxMapsList();
+ virtual MinidumpLinuxMapsList* GetLinuxMapsList();
// The next set of methods are provided for users who wish to access
// data in minidump files directly, while leveraging the rest of
@@ -1240,6 +1334,10 @@ class Minidump {
off_t offset,
std::map<std::string, std::string>* simple_string_dictionary);
+ bool ReadCrashpadAnnotationsList(
+ off_t offset,
+ std::vector<MinidumpCrashpadInfo::AnnotationObject>* annotations_list);
+
// SeekToStreamType positions the file at the beginning of a stream
// identified by stream_type, and informs the caller of the stream's
// length by setting *stream_length. Because stream_map maps each stream
diff --git a/src/google_breakpad/processor/minidump_processor.h b/src/google_breakpad/processor/minidump_processor.h
index 387115ef..137ef444 100644
--- a/src/google_breakpad/processor/minidump_processor.h
+++ b/src/google_breakpad/processor/minidump_processor.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2006, Google Inc.
-// All rights reserved.
+// Copyright 2006 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -70,7 +69,7 @@ class MinidumpProcessor {
~MinidumpProcessor();
// Processes the minidump file and fills process_state with the result.
- ProcessResult Process(const string &minidump_file,
+ ProcessResult Process(const string& minidump_file,
ProcessState* process_state);
// Processes the minidump structure and fills process_state with the
@@ -102,8 +101,10 @@ class MinidumpProcessor {
// exception, if this information is available. This will be a code
// address when the crash was caused by problems such as illegal
// instructions or divisions by zero, or a data address when the crash
- // was caused by a memory access violation.
- static string GetCrashReason(Minidump* dump, uint64_t* address);
+ // was caused by a memory access violation. If enable_objdump is set, this
+ // may use disassembly to compute the faulting address.
+ static string GetCrashReason(Minidump* dump, uint64_t* address,
+ bool enable_objdump);
// This function returns true if the passed-in error code is
// something unrecoverable(i.e. retry should not happen). For
diff --git a/src/google_breakpad/processor/proc_maps_linux.h b/src/google_breakpad/processor/proc_maps_linux.h
index 3045daa5..b99414c3 100644
--- a/src/google_breakpad/processor/proc_maps_linux.h
+++ b/src/google_breakpad/processor/proc_maps_linux.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Copyright 2013 Google LLC
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/src/google_breakpad/processor/process_result.h b/src/google_breakpad/processor/process_result.h
index 15c7213e..780060d9 100644
--- a/src/google_breakpad/processor/process_result.h
+++ b/src/google_breakpad/processor/process_result.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2014, Google Inc.
-// All rights reserved.
+// Copyright 2014 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -56,9 +55,13 @@ enum ProcessResult {
PROCESS_ERROR_DUPLICATE_REQUESTING_THREADS, // There was more than one
// requesting thread.
- PROCESS_SYMBOL_SUPPLIER_INTERRUPTED // The dump processing was
+ PROCESS_SYMBOL_SUPPLIER_INTERRUPTED, // The dump processing was
// interrupted by the
// SymbolSupplier(not fatal).
+
+ PROCESS_ERROR_GETTING_THREAD_NAME, // There was an error getting one
+ // thread's name from the dump.
+
};
} // namespace google_breakpad
diff --git a/src/google_breakpad/processor/process_state.h b/src/google_breakpad/processor/process_state.h
index 9bc44c45..3fe6a5c2 100644
--- a/src/google_breakpad/processor/process_state.h
+++ b/src/google_breakpad/processor/process_state.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2006, Google Inc.
-// All rights reserved.
+// Copyright 2006 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -111,6 +110,7 @@ class ProcessState {
const vector<MemoryRegion*>* thread_memory_regions() const {
return &thread_memory_regions_;
}
+ const vector<string>* thread_names() const { return &thread_names_; }
const SystemInfo* system_info() const { return &system_info_; }
const CodeModules* modules() const { return modules_; }
const CodeModules* unloaded_modules() const { return unloaded_modules_; }
@@ -176,6 +176,12 @@ class ProcessState {
vector<CallStack*> threads_;
vector<MemoryRegion*> thread_memory_regions_;
+ // Names of each thread at the time of the crash, one for each entry in
+ // threads_. Note that a thread's name might be empty if there was no
+ // corresponding ThreadNamesStream in the minidump, or if a particular thread
+ // ID was not present in the THREAD_NAME_LIST.
+ vector<string> thread_names_;
+
// OS and CPU information.
SystemInfo system_info_;
diff --git a/src/google_breakpad/processor/source_line_resolver_base.h b/src/google_breakpad/processor/source_line_resolver_base.h
index c720b0c3..4c64bfc9 100644
--- a/src/google_breakpad/processor/source_line_resolver_base.h
+++ b/src/google_breakpad/processor/source_line_resolver_base.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2010 Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -41,6 +40,7 @@
#ifndef GOOGLE_BREAKPAD_PROCESSOR_SOURCE_LINE_RESOLVER_BASE_H__
#define GOOGLE_BREAKPAD_PROCESSOR_SOURCE_LINE_RESOLVER_BASE_H__
+#include <deque>
#include <map>
#include <set>
#include <string>
@@ -64,36 +64,40 @@ class SourceLineResolverBase : public SourceLineResolverInterface {
// LoadMap() method.
// Place dynamically allocated heap buffer in symbol_data. Caller has the
// ownership of the buffer, and should call delete [] to free the buffer.
- static bool ReadSymbolFile(const string &file_name,
- char **symbol_data,
- size_t *symbol_data_size);
+ static bool ReadSymbolFile(const string& file_name,
+ char** symbol_data,
+ size_t* symbol_data_size);
protected:
// Users are not allowed create SourceLineResolverBase instance directly.
- SourceLineResolverBase(ModuleFactory *module_factory);
+ SourceLineResolverBase(ModuleFactory* module_factory);
virtual ~SourceLineResolverBase();
// Virtual methods inherited from SourceLineResolverInterface.
- virtual bool LoadModule(const CodeModule *module, const string &map_file);
- virtual bool LoadModuleUsingMapBuffer(const CodeModule *module,
- const string &map_buffer);
- virtual bool LoadModuleUsingMemoryBuffer(const CodeModule *module,
- char *memory_buffer,
+ virtual bool LoadModule(const CodeModule* module, const string& map_file);
+ virtual bool LoadModuleUsingMapBuffer(const CodeModule* module,
+ const string& map_buffer);
+ virtual bool LoadModuleUsingMemoryBuffer(const CodeModule* module,
+ char* memory_buffer,
size_t memory_buffer_size);
virtual bool ShouldDeleteMemoryBufferAfterLoadModule();
- virtual void UnloadModule(const CodeModule *module);
- virtual bool HasModule(const CodeModule *module);
- virtual bool IsModuleCorrupt(const CodeModule *module);
- virtual void FillSourceLineInfo(StackFrame *frame);
- virtual WindowsFrameInfo *FindWindowsFrameInfo(const StackFrame *frame);
- virtual CFIFrameInfo *FindCFIFrameInfo(const StackFrame *frame);
+ virtual void UnloadModule(const CodeModule* module);
+ virtual bool HasModule(const CodeModule* module);
+ virtual bool IsModuleCorrupt(const CodeModule* module);
+ virtual void FillSourceLineInfo(
+ StackFrame* frame,
+ std::deque<std::unique_ptr<StackFrame>>* inlined_frames);
+ virtual WindowsFrameInfo* FindWindowsFrameInfo(const StackFrame* frame);
+ virtual CFIFrameInfo* FindCFIFrameInfo(const StackFrame* frame);
// Nested structs and classes.
+ struct InlineOrigin;
+ struct Inline;
struct Line;
struct Function;
struct PublicSymbol;
struct CompareString {
- bool operator()(const string &s1, const string &s2) const;
+ bool operator()(const string& s1, const string& s2) const;
};
// Module is an interface for an in-memory symbol file.
class Module;
@@ -101,18 +105,18 @@ class SourceLineResolverBase : public SourceLineResolverInterface {
// All of the modules that are loaded.
typedef map<string, Module*, CompareString> ModuleMap;
- ModuleMap *modules_;
+ ModuleMap* modules_;
// The loaded modules that were detecting to be corrupt during load.
typedef set<string, CompareString> ModuleSet;
- ModuleSet *corrupt_modules_;
+ ModuleSet* corrupt_modules_;
// All of heap-allocated buffers that are owned locally by resolver.
typedef std::map<string, char*, CompareString> MemoryMap;
- MemoryMap *memory_buffers_;
+ MemoryMap* memory_buffers_;
// Creates a concrete module at run-time.
- ModuleFactory *module_factory_;
+ ModuleFactory* module_factory_;
private:
// ModuleFactory needs to have access to protected type Module.
diff --git a/src/google_breakpad/processor/source_line_resolver_interface.h b/src/google_breakpad/processor/source_line_resolver_interface.h
index a694bf2e..9f1f50c9 100644
--- a/src/google_breakpad/processor/source_line_resolver_interface.h
+++ b/src/google_breakpad/processor/source_line_resolver_interface.h
@@ -1,7 +1,6 @@
// -*- mode: C++ -*-
-// Copyright (c) 2010 Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -13,7 +12,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -34,7 +33,10 @@
#ifndef GOOGLE_BREAKPAD_PROCESSOR_SOURCE_LINE_RESOLVER_INTERFACE_H__
#define GOOGLE_BREAKPAD_PROCESSOR_SOURCE_LINE_RESOLVER_INTERFACE_H__
+#include <deque>
+#include <memory>
#include <string>
+#include <vector>
#include "common/using_std_string.h"
#include "google_breakpad/common/breakpad_types.h"
@@ -58,11 +60,11 @@ class SourceLineResolverInterface {
// and debug_identifier members populated.
//
// map_file should contain line/address mappings for this module.
- virtual bool LoadModule(const CodeModule *module,
- const string &map_file) = 0;
+ virtual bool LoadModule(const CodeModule* module,
+ const string& map_file) = 0;
// Same as above, but takes the contents of a pre-read map buffer
- virtual bool LoadModuleUsingMapBuffer(const CodeModule *module,
- const string &map_buffer) = 0;
+ virtual bool LoadModuleUsingMapBuffer(const CodeModule* module,
+ const string& map_buffer) = 0;
// Add an interface to load symbol using C-String data instead of string.
// This is useful in the optimization design for avoiding unnecessary copying
@@ -70,8 +72,8 @@ class SourceLineResolverInterface {
// LoadModuleUsingMemoryBuffer() does NOT take ownership of memory_buffer.
// LoadModuleUsingMemoryBuffer() null terminates the passed in buffer, if
// the last character is not a null terminator.
- virtual bool LoadModuleUsingMemoryBuffer(const CodeModule *module,
- char *memory_buffer,
+ virtual bool LoadModuleUsingMemoryBuffer(const CodeModule* module,
+ char* memory_buffer,
size_t memory_buffer_size) = 0;
// Return true if the memory buffer should be deleted immediately after
@@ -81,31 +83,35 @@ class SourceLineResolverInterface {
// Request that the specified module be unloaded from this resolver.
// A resolver may choose to ignore such a request.
- virtual void UnloadModule(const CodeModule *module) = 0;
+ virtual void UnloadModule(const CodeModule* module) = 0;
// Returns true if the module has been loaded.
- virtual bool HasModule(const CodeModule *module) = 0;
+ virtual bool HasModule(const CodeModule* module) = 0;
// Returns true if the module has been loaded and it is corrupt.
- virtual bool IsModuleCorrupt(const CodeModule *module) = 0;
+ virtual bool IsModuleCorrupt(const CodeModule* module) = 0;
// Fills in the function_base, function_name, source_file_name,
// and source_line fields of the StackFrame. The instruction and
- // module_name fields must already be filled in.
- virtual void FillSourceLineInfo(StackFrame *frame) = 0;
+ // module_name fields must already be filled in. If inlined_frames is not
+ // nullptr, it will try to construct inlined frames by adding them into
+ // inlined_frames in an order from outermost frame to inner most frame.
+ virtual void FillSourceLineInfo(
+ StackFrame* frame,
+ std::deque<std::unique_ptr<StackFrame>>* inlined_frames) = 0;
// If Windows stack walking information is available covering
// FRAME's instruction address, return a WindowsFrameInfo structure
// describing it. If the information is not available, returns NULL.
// A NULL return value does not indicate an error. The caller takes
// ownership of any returned WindowsFrameInfo object.
- virtual WindowsFrameInfo *FindWindowsFrameInfo(const StackFrame *frame) = 0;
+ virtual WindowsFrameInfo* FindWindowsFrameInfo(const StackFrame* frame) = 0;
// If CFI stack walking information is available covering ADDRESS,
// return a CFIFrameInfo structure describing it. If the information
// is not available, return NULL. The caller takes ownership of any
// returned CFIFrameInfo object.
- virtual CFIFrameInfo *FindCFIFrameInfo(const StackFrame *frame) = 0;
+ virtual CFIFrameInfo* FindCFIFrameInfo(const StackFrame* frame) = 0;
protected:
// SourceLineResolverInterface cannot be instantiated except by subclasses
diff --git a/src/google_breakpad/processor/stack_frame.h b/src/google_breakpad/processor/stack_frame.h
index 1491d788..eebe06e6 100644
--- a/src/google_breakpad/processor/stack_frame.h
+++ b/src/google_breakpad/processor/stack_frame.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2006, Google Inc.
-// All rights reserved.
+// Copyright 2006 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -50,8 +49,12 @@ struct StackFrame {
FRAME_TRUST_CFI_SCAN, // Found while scanning stack using call frame info
FRAME_TRUST_FP, // Derived from frame pointer
FRAME_TRUST_CFI, // Derived from call frame info
- FRAME_TRUST_PREWALKED, // Explicitly provided by some external stack walker.
- FRAME_TRUST_CONTEXT // Given as instruction pointer in a context
+ // Explicitly provided by some external stack walker.
+ FRAME_TRUST_PREWALKED,
+ FRAME_TRUST_CONTEXT, // Given as instruction pointer in a context
+ FRAME_TRUST_INLINE, // Found by inline records in symbol files.
+ // Derived from leaf function by simulating a return.
+ FRAME_TRUST_LEAF,
};
StackFrame()
@@ -60,9 +63,10 @@ struct StackFrame {
function_name(),
function_base(),
source_file_name(),
- source_line(),
+ source_line(0),
source_line_base(),
- trust(FRAME_TRUST_NONE) {}
+ trust(FRAME_TRUST_NONE),
+ is_multiple(false) {}
virtual ~StackFrame() {}
// Return a string describing how this stack frame was found
@@ -81,7 +85,11 @@ struct StackFrame {
return "previous frame's frame pointer";
case StackFrame::FRAME_TRUST_SCAN:
return "stack scanning";
- default:
+ case StackFrame::FRAME_TRUST_INLINE:
+ return "inline record";
+ case StackFrame::FRAME_TRUST_LEAF:
+ return "simulating a return from leaf function";
+ default:
return "unknown";
}
}
@@ -137,6 +145,12 @@ struct StackFrame {
// Amount of trust the stack walker has in the instruction pointer
// of this frame.
FrameTrust trust;
+
+ // True if the frame corresponds to multiple functions, for example as the
+ // result of identical code folding by the linker. In that case the function
+ // name, filename, etc. information above represents the state of an arbitrary
+ // one of these functions.
+ bool is_multiple;
};
} // namespace google_breakpad
diff --git a/src/google_breakpad/processor/stack_frame_cpu.h b/src/google_breakpad/processor/stack_frame_cpu.h
index dc5d8ae6..91f1d0cb 100644
--- a/src/google_breakpad/processor/stack_frame_cpu.h
+++ b/src/google_breakpad/processor/stack_frame_cpu.h
@@ -1,7 +1,6 @@
// -*- mode: c++ -*-
-// Copyright (c) 2010 Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -13,7 +12,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -251,7 +250,10 @@ struct StackFrameARM : public StackFrame {
// Return the ContextValidity flag for register rN.
static ContextValidity RegisterValidFlag(int n) {
- return ContextValidity(1 << n);
+ if (0 <= n && n <= 15) {
+ return ContextValidity(1 << n);
+ }
+ return CONTEXT_VALID_NONE;
}
// Register state. This is only fully valid for the topmost frame in a
@@ -400,6 +402,118 @@ struct StackFrameMIPS : public StackFrame {
int context_validity;
};
+struct StackFrameRISCV : public StackFrame {
+
+ enum ContextValidity {
+ CONTEXT_VALID_NONE = 0,
+ CONTEXT_VALID_PC = 1 << 0,
+ CONTEXT_VALID_RA = 1 << 1,
+ CONTEXT_VALID_SP = 1 << 2,
+ CONTEXT_VALID_GP = 1 << 3,
+ CONTEXT_VALID_TP = 1 << 4,
+ CONTEXT_VALID_T0 = 1 << 5,
+ CONTEXT_VALID_T1 = 1 << 6,
+ CONTEXT_VALID_T2 = 1 << 7,
+ CONTEXT_VALID_S0 = 1 << 8,
+ CONTEXT_VALID_S1 = 1 << 9,
+ CONTEXT_VALID_A0 = 1 << 10,
+ CONTEXT_VALID_A1 = 1 << 11,
+ CONTEXT_VALID_A2 = 1 << 12,
+ CONTEXT_VALID_A3 = 1 << 13,
+ CONTEXT_VALID_A4 = 1 << 14,
+ CONTEXT_VALID_A5 = 1 << 15,
+ CONTEXT_VALID_A6 = 1 << 16,
+ CONTEXT_VALID_A7 = 1 << 17,
+ CONTEXT_VALID_S2 = 1 << 18,
+ CONTEXT_VALID_S3 = 1 << 19,
+ CONTEXT_VALID_S4 = 1 << 20,
+ CONTEXT_VALID_S5 = 1 << 21,
+ CONTEXT_VALID_S6 = 1 << 22,
+ CONTEXT_VALID_S7 = 1 << 23,
+ CONTEXT_VALID_S8 = 1 << 24,
+ CONTEXT_VALID_S9 = 1 << 25,
+ CONTEXT_VALID_S10 = 1 << 26,
+ CONTEXT_VALID_S11 = 1 << 27,
+ CONTEXT_VALID_T3 = 1 << 28,
+ CONTEXT_VALID_T4 = 1 << 29,
+ CONTEXT_VALID_T5 = 1 << 30,
+ CONTEXT_VALID_T6 = 1 << 31,
+ CONTEXT_VALID_ALL = ~CONTEXT_VALID_NONE
+ };
+
+ StackFrameRISCV() : context(), context_validity(CONTEXT_VALID_NONE) {}
+
+ // Register state. This is only fully valid for the topmost frame in a
+ // stack. In other frames, which registers are present depends on what
+ // debugging information were available. Refer to 'context_validity' below.
+ MDRawContextRISCV context;
+
+ // For each register in context whose value has been recovered,
+ // the corresponding CONTEXT_VALID_ bit in 'context_validity' is set.
+ //
+ // context_validity's type should actually be ContextValidity, but
+ // type int is used instead because the bitwise inclusive or operator
+ // yields an int when applied to enum values, and C++ doesn't
+ // silently convert from ints to enums.
+ int context_validity;
+};
+
+struct StackFrameRISCV64 : public StackFrame {
+
+ enum ContextValidity {
+ CONTEXT_VALID_NONE = 0,
+ CONTEXT_VALID_PC = 1 << 0,
+ CONTEXT_VALID_RA = 1 << 1,
+ CONTEXT_VALID_SP = 1 << 2,
+ CONTEXT_VALID_GP = 1 << 3,
+ CONTEXT_VALID_TP = 1 << 4,
+ CONTEXT_VALID_T0 = 1 << 5,
+ CONTEXT_VALID_T1 = 1 << 6,
+ CONTEXT_VALID_T2 = 1 << 7,
+ CONTEXT_VALID_S0 = 1 << 8,
+ CONTEXT_VALID_S1 = 1 << 9,
+ CONTEXT_VALID_A0 = 1 << 10,
+ CONTEXT_VALID_A1 = 1 << 11,
+ CONTEXT_VALID_A2 = 1 << 12,
+ CONTEXT_VALID_A3 = 1 << 13,
+ CONTEXT_VALID_A4 = 1 << 14,
+ CONTEXT_VALID_A5 = 1 << 15,
+ CONTEXT_VALID_A6 = 1 << 16,
+ CONTEXT_VALID_A7 = 1 << 17,
+ CONTEXT_VALID_S2 = 1 << 18,
+ CONTEXT_VALID_S3 = 1 << 19,
+ CONTEXT_VALID_S4 = 1 << 20,
+ CONTEXT_VALID_S5 = 1 << 21,
+ CONTEXT_VALID_S6 = 1 << 22,
+ CONTEXT_VALID_S7 = 1 << 23,
+ CONTEXT_VALID_S8 = 1 << 24,
+ CONTEXT_VALID_S9 = 1 << 25,
+ CONTEXT_VALID_S10 = 1 << 26,
+ CONTEXT_VALID_S11 = 1 << 27,
+ CONTEXT_VALID_T3 = 1 << 28,
+ CONTEXT_VALID_T4 = 1 << 29,
+ CONTEXT_VALID_T5 = 1 << 30,
+ CONTEXT_VALID_T6 = 1 << 31,
+ CONTEXT_VALID_ALL = ~CONTEXT_VALID_NONE
+ };
+
+ StackFrameRISCV64() : context(), context_validity(CONTEXT_VALID_NONE) {}
+
+ // Register state. This is only fully valid for the topmost frame in a
+ // stack. In other frames, which registers are present depends on what
+ // debugging information were available. Refer to 'context_validity' below.
+ MDRawContextRISCV64 context;
+
+ // For each register in context whose value has been recovered,
+ // the corresponding CONTEXT_VALID_ bit in 'context_validity' is set.
+ //
+ // context_validity's type should actually be ContextValidity, but
+ // type int is used instead because the bitwise inclusive or operator
+ // yields an int when applied to enum values, and C++ doesn't
+ // silently convert from ints to enums.
+ int context_validity;
+};
+
} // namespace google_breakpad
#endif // GOOGLE_BREAKPAD_PROCESSOR_STACK_FRAME_CPU_H__
diff --git a/src/google_breakpad/processor/stack_frame_symbolizer.h b/src/google_breakpad/processor/stack_frame_symbolizer.h
index 0bbaae0a..ed342ce6 100644
--- a/src/google_breakpad/processor/stack_frame_symbolizer.h
+++ b/src/google_breakpad/processor/stack_frame_symbolizer.h
@@ -1,7 +1,6 @@
// -*- mode: C++ -*-
-// Copyright (c) 2012 Google Inc.
-// All rights reserved.
+// Copyright 2012 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -13,7 +12,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -35,8 +34,11 @@
#ifndef GOOGLE_BREAKPAD_PROCESSOR_STACK_FRAME_SYMBOLIZER_H__
#define GOOGLE_BREAKPAD_PROCESSOR_STACK_FRAME_SYMBOLIZER_H__
+#include <deque>
+#include <memory>
#include <set>
#include <string>
+#include <vector>
#include "common/using_std_string.h"
#include "google_breakpad/common/breakpad_types.h"
@@ -79,7 +81,8 @@ class StackFrameSymbolizer {
const CodeModules* modules,
const CodeModules* unloaded_modules,
const SystemInfo* system_info,
- StackFrame* stack_frame);
+ StackFrame* stack_frame,
+ std::deque<std::unique_ptr<StackFrame>>* inlined_frames);
virtual WindowsFrameInfo* FindWindowsFrameInfo(const StackFrame* frame);
diff --git a/src/google_breakpad/processor/stackwalker.h b/src/google_breakpad/processor/stackwalker.h
index 0c458d50..e5d88c80 100644
--- a/src/google_breakpad/processor/stackwalker.h
+++ b/src/google_breakpad/processor/stackwalker.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2010 Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -176,8 +175,12 @@ class Stackwalker {
if (!memory_->GetMemoryAtAddress(location, &ip))
break;
- if (modules_ && modules_->GetModuleForAddress(ip) &&
- InstructionAddressSeemsValid(ip)) {
+ // The return address points to the instruction after a call. If the
+ // caller was a no return function, this might point past the end of the
+ // function. Subtract one from the instruction pointer so it points into
+ // the call instruction instead.
+ if (modules_ && modules_->GetModuleForAddress(ip - 1) &&
+ InstructionAddressSeemsValid(ip - 1)) {
*ip_found = ip;
*location_found = location;
return true;
diff --git a/src/google_breakpad/processor/symbol_supplier.h b/src/google_breakpad/processor/symbol_supplier.h
index a042081f..b1c23535 100644
--- a/src/google_breakpad/processor/symbol_supplier.h
+++ b/src/google_breakpad/processor/symbol_supplier.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2006, Google Inc.
-// All rights reserved.
+// Copyright 2006 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -63,35 +62,35 @@ class SymbolSupplier {
// to help locate the symbol file. system_info may be NULL or its
// fields may be empty if these values are unknown. symbol_file
// must be a pointer to a valid string
- virtual SymbolResult GetSymbolFile(const CodeModule *module,
- const SystemInfo *system_info,
- string *symbol_file) = 0;
+ virtual SymbolResult GetSymbolFile(const CodeModule* module,
+ const SystemInfo* system_info,
+ string* symbol_file) = 0;
// Same as above, except also places symbol data into symbol_data.
// If symbol_data is NULL, the data is not returned.
// TODO(nealsid) Once we have symbol data caching behavior implemented
// investigate making all symbol suppliers implement all methods,
// and make this pure virtual
- virtual SymbolResult GetSymbolFile(const CodeModule *module,
- const SystemInfo *system_info,
- string *symbol_file,
- string *symbol_data) = 0;
+ virtual SymbolResult GetSymbolFile(const CodeModule* module,
+ const SystemInfo* system_info,
+ string* symbol_file,
+ string* symbol_data) = 0;
// Same as above, except allocates data buffer on heap and then places the
// symbol data into the buffer as C-string.
// SymbolSupplier is responsible for deleting the data buffer. After the call
// to GetCStringSymbolData(), the caller should call FreeSymbolData(const
- // Module *module) once the data buffer is no longer needed.
+ // Module* module) once the data buffer is no longer needed.
// If symbol_data is not NULL, symbol supplier won't return FOUND unless it
// returns a valid buffer in symbol_data, e.g., returns INTERRUPT on memory
// allocation failure.
- virtual SymbolResult GetCStringSymbolData(const CodeModule *module,
- const SystemInfo *system_info,
- string *symbol_file,
- char **symbol_data,
- size_t *symbol_data_size) = 0;
+ virtual SymbolResult GetCStringSymbolData(const CodeModule* module,
+ const SystemInfo* system_info,
+ string* symbol_file,
+ char** symbol_data,
+ size_t* symbol_data_size) = 0;
// Frees the data buffer allocated for the module in GetCStringSymbolData.
- virtual void FreeSymbolData(const CodeModule *module) = 0;
+ virtual void FreeSymbolData(const CodeModule* module) = 0;
};
} // namespace google_breakpad
diff --git a/src/google_breakpad/processor/system_info.h b/src/google_breakpad/processor/system_info.h
index 8d2f60be..01c48182 100644
--- a/src/google_breakpad/processor/system_info.h
+++ b/src/google_breakpad/processor/system_info.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2006, Google Inc.
-// All rights reserved.
+// Copyright 2006 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/processor/address_map-inl.h b/src/processor/address_map-inl.h
index 251c4478..e1b944d1 100644
--- a/src/processor/address_map-inl.h
+++ b/src/processor/address_map-inl.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2006, Google Inc.
-// All rights reserved.
+// Copyright 2006 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -45,8 +44,8 @@
namespace google_breakpad {
template<typename AddressType, typename EntryType>
-bool AddressMap<AddressType, EntryType>::Store(const AddressType &address,
- const EntryType &entry) {
+bool AddressMap<AddressType, EntryType>::Store(const AddressType& address,
+ const EntryType& entry) {
// Ensure that the specified address doesn't conflict with something already
// in the map.
if (map_.find(address) != map_.end()) {
@@ -61,8 +60,8 @@ bool AddressMap<AddressType, EntryType>::Store(const AddressType &address,
template<typename AddressType, typename EntryType>
bool AddressMap<AddressType, EntryType>::Retrieve(
- const AddressType &address,
- EntryType *entry, AddressType *entry_address) const {
+ const AddressType& address,
+ EntryType* entry, AddressType* entry_address) const {
BPLOG_IF(ERROR, !entry) << "AddressMap::Retrieve requires |entry|";
assert(entry);
diff --git a/src/processor/address_map.h b/src/processor/address_map.h
index 2972cbb9..8a4f7ba8 100644
--- a/src/processor/address_map.h
+++ b/src/processor/address_map.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2006, Google Inc.
-// All rights reserved.
+// Copyright 2006 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -53,15 +52,15 @@ class AddressMap {
// Inserts an entry into the map. Returns false without storing the entry
// if an entry is already stored in the map at the same address as specified
// by the address argument.
- bool Store(const AddressType &address, const EntryType &entry);
+ bool Store(const AddressType& address, const EntryType& entry);
// Locates the entry stored at the highest address less than or equal to
// the address argument. If there is no such range, returns false. The
// entry is returned in entry, which is a required argument. If
// entry_address is not NULL, it will be set to the address that the entry
// was stored at.
- bool Retrieve(const AddressType &address,
- EntryType *entry, AddressType *entry_address) const;
+ bool Retrieve(const AddressType& address,
+ EntryType* entry, AddressType* entry_address) const;
// Empties the address map, restoring it to the same state as when it was
// initially created.
diff --git a/src/processor/address_map_unittest.cc b/src/processor/address_map_unittest.cc
index 9b4095b1..1bf0d718 100644
--- a/src/processor/address_map_unittest.cc
+++ b/src/processor/address_map_unittest.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2006, Google Inc.
-// All rights reserved.
+// Copyright 2006 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -189,7 +188,7 @@ static bool RunTests() {
} // namespace
-int main(int argc, char **argv) {
+int main(int argc, char** argv) {
BPLOG_INIT(&argc, &argv);
return RunTests() ? 0 : 1;
diff --git a/src/processor/basic_code_module.h b/src/processor/basic_code_module.h
index 35d66a60..9da62d92 100644
--- a/src/processor/basic_code_module.h
+++ b/src/processor/basic_code_module.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2006, Google Inc.
-// All rights reserved.
+// Copyright 2006 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -66,11 +65,11 @@ class BasicCodeModule : public CodeModule {
is_unloaded_(that->is_unloaded()) {}
BasicCodeModule(uint64_t base_address, uint64_t size,
- const string &code_file,
- const string &code_identifier,
- const string &debug_file,
- const string &debug_identifier,
- const string &version,
+ const string& code_file,
+ const string& code_identifier,
+ const string& debug_file,
+ const string& debug_identifier,
+ const string& version,
const bool is_unloaded = false)
: base_address_(base_address),
size_(size),
@@ -112,8 +111,8 @@ class BasicCodeModule : public CodeModule {
bool is_unloaded_;
// Disallow copy constructor and assignment operator.
- BasicCodeModule(const BasicCodeModule &that);
- void operator=(const BasicCodeModule &that);
+ BasicCodeModule(const BasicCodeModule& that);
+ void operator=(const BasicCodeModule& that);
};
} // namespace google_breakpad
diff --git a/src/processor/basic_code_modules.cc b/src/processor/basic_code_modules.cc
index f71aeb74..57021d47 100644
--- a/src/processor/basic_code_modules.cc
+++ b/src/processor/basic_code_modules.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2006, Google Inc.
-// All rights reserved.
+// Copyright 2006 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/processor/basic_code_modules.h b/src/processor/basic_code_modules.h
index 45ebc53b..e9d58f6b 100644
--- a/src/processor/basic_code_modules.h
+++ b/src/processor/basic_code_modules.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2006, Google Inc.
-// All rights reserved.
+// Copyright 2006 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -88,8 +87,8 @@ class BasicCodeModules : public CodeModules {
private:
// Disallow copy constructor and assignment operator.
- BasicCodeModules(const BasicCodeModules &that);
- void operator=(const BasicCodeModules &that);
+ BasicCodeModules(const BasicCodeModules& that);
+ void operator=(const BasicCodeModules& that);
};
} // namespace google_breakpad
diff --git a/src/processor/basic_source_line_resolver.cc b/src/processor/basic_source_line_resolver.cc
index c4aa949c..07aba6bc 100644
--- a/src/processor/basic_source_line_resolver.cc
+++ b/src/processor/basic_source_line_resolver.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2010 Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -40,6 +39,7 @@
#include <limits>
#include <map>
+#include <memory>
#include <utility>
#include <vector>
@@ -49,9 +49,11 @@
#include "processor/tokenize.h"
+using std::deque;
+using std::make_pair;
using std::map;
+using std::unique_ptr;
using std::vector;
-using std::make_pair;
namespace google_breakpad {
@@ -69,11 +71,11 @@ namespace {
// field, and max_tokens is the maximum number of tokens including the optional
// field. Refer to the documentation for Tokenize for descriptions of the other
// arguments.
-bool TokenizeWithOptionalField(char *line,
- const char *optional_field,
- const char *separators,
+bool TokenizeWithOptionalField(char* line,
+ const char* optional_field,
+ const char* separators,
int max_tokens,
- vector<char*> *tokens) {
+ vector<char*>* tokens) {
// First tokenize assuming the optional field is not present. If we then see
// the optional field, additionally tokenize the last token into two tokens.
if (!Tokenize(line, separators, max_tokens - 1, tokens)) {
@@ -98,7 +100,7 @@ bool TokenizeWithOptionalField(char *line,
} // namespace
-static const char *kWhitespace = " \r\n";
+static const char* kWhitespace = " \r\n";
static const int kMaxErrorsPrinted = 5;
static const int kMaxErrorsBeforeBailing = 100;
@@ -107,9 +109,9 @@ BasicSourceLineResolver::BasicSourceLineResolver() :
// static
void BasicSourceLineResolver::Module::LogParseError(
- const string &message,
+ const string& message,
int line_number,
- int *num_errors) {
+ int* num_errors) {
if (++(*num_errors) <= kMaxErrorsPrinted) {
if (line_number > 0) {
BPLOG(ERROR) << "Line " << line_number << ": " << message;
@@ -120,12 +122,13 @@ void BasicSourceLineResolver::Module::LogParseError(
}
bool BasicSourceLineResolver::Module::LoadMapFromMemory(
- char *memory_buffer,
+ char* memory_buffer,
size_t memory_buffer_size) {
linked_ptr<Function> cur_func;
int line_number = 0;
int num_errors = 0;
- char *save_ptr;
+ int inline_num_errors = 0;
+ char* save_ptr;
// If the length is 0, we can still pretend we have a symbol file. This is
// for scenarios that want to test symbol lookup, but don't necessarily care
@@ -160,7 +163,7 @@ bool BasicSourceLineResolver::Module::LoadMapFromMemory(
&num_errors);
}
- char *buffer;
+ char* buffer;
buffer = strtok_r(memory_buffer, "\r\n", &save_ptr);
while (buffer != NULL) {
@@ -202,12 +205,23 @@ bool BasicSourceLineResolver::Module::LoadMapFromMemory(
// Ignore these as well, they're similarly just for housekeeping.
//
// INFO CODE_ID <code id> <filename>
+ } else if (strncmp(buffer, "INLINE ", 7) == 0) {
+ linked_ptr<Inline> in = ParseInline(buffer);
+ if (!in.get())
+ LogParseError("ParseInline failed", line_number, &inline_num_errors);
+ else
+ cur_func->AppendInline(in);
+ } else if (strncmp(buffer, "INLINE_ORIGIN ", 14) == 0) {
+ if (!ParseInlineOrigin(buffer)) {
+ LogParseError("ParseInlineOrigin failed", line_number,
+ &inline_num_errors);
+ }
} else {
if (!cur_func.get()) {
LogParseError("Found source line data without a function",
line_number, &num_errors);
} else {
- Line *line = ParseLine(buffer);
+ Line* line = ParseLine(buffer);
if (!line) {
LogParseError("ParseLine failed", line_number, &num_errors);
} else {
@@ -225,7 +239,67 @@ bool BasicSourceLineResolver::Module::LoadMapFromMemory(
return true;
}
-void BasicSourceLineResolver::Module::LookupAddress(StackFrame *frame) const {
+void BasicSourceLineResolver::Module::ConstructInlineFrames(
+ StackFrame* frame,
+ MemAddr address,
+ const ContainedRangeMap<uint64_t, linked_ptr<Inline>>& inline_map,
+ deque<unique_ptr<StackFrame>>* inlined_frames) const {
+ vector<const linked_ptr<Inline>*> inlines;
+ if (!inline_map.RetrieveRanges(address, inlines)) {
+ return;
+ }
+
+ for (const linked_ptr<Inline>* const in : inlines) {
+ unique_ptr<StackFrame> new_frame =
+ unique_ptr<StackFrame>(new StackFrame(*frame));
+ auto origin = inline_origins_.find(in->get()->origin_id);
+ if (origin != inline_origins_.end()) {
+ new_frame->function_name = origin->second->name;
+ } else {
+ new_frame->function_name = "<name omitted>";
+ }
+
+ // Store call site file and line in current frame, which will be updated
+ // later.
+ new_frame->source_line = in->get()->call_site_line;
+ if (in->get()->has_call_site_file_id) {
+ auto file = files_.find(in->get()->call_site_file_id);
+ if (file != files_.end()) {
+ new_frame->source_file_name = file->second;
+ }
+ }
+
+ // Use the starting address of the inlined range as inlined function base.
+ new_frame->function_base = new_frame->module->base_address();
+ for (const auto& range : in->get()->inline_ranges) {
+ if (address >= range.first && address < range.first + range.second) {
+ new_frame->function_base += range.first;
+ break;
+ }
+ }
+ new_frame->trust = StackFrame::FRAME_TRUST_INLINE;
+
+ // The inlines vector has an order from innermost entry to outermost entry.
+ // By push_back, we will have inlined_frames with the same order.
+ inlined_frames->push_back(std::move(new_frame));
+ }
+
+ // Update the source file and source line for each inlined frame.
+ if (!inlined_frames->empty()) {
+ string parent_frame_source_file_name = frame->source_file_name;
+ int parent_frame_source_line = frame->source_line;
+ frame->source_file_name = inlined_frames->back()->source_file_name;
+ frame->source_line = inlined_frames->back()->source_line;
+ for (unique_ptr<StackFrame>& inlined_frame : *inlined_frames) {
+ std::swap(inlined_frame->source_file_name, parent_frame_source_file_name);
+ std::swap(inlined_frame->source_line, parent_frame_source_line);
+ }
+ }
+}
+
+void BasicSourceLineResolver::Module::LookupAddress(
+ StackFrame* frame,
+ deque<unique_ptr<StackFrame>>* inlined_frames) const {
MemAddr address = frame->instruction - frame->module->base_address();
// First, look for a FUNC record that covers address. Use
@@ -244,6 +318,7 @@ void BasicSourceLineResolver::Module::LookupAddress(StackFrame *frame) const {
address >= function_base && address - function_base < function_size) {
frame->function_name = func->name;
frame->function_base = frame->module->base_address() + function_base;
+ frame->is_multiple = func->is_multiple;
linked_ptr<Line> line;
MemAddr line_base;
@@ -256,16 +331,22 @@ void BasicSourceLineResolver::Module::LookupAddress(StackFrame *frame) const {
frame->source_line = line->line;
frame->source_line_base = frame->module->base_address() + line_base;
}
+
+ // Check if this is inlined function call.
+ if (inlined_frames) {
+ ConstructInlineFrames(frame, address, func->inlines, inlined_frames);
+ }
} else if (public_symbols_.Retrieve(address,
&public_symbol, &public_address) &&
(!func.get() || public_address > function_base)) {
frame->function_name = public_symbol->name;
frame->function_base = frame->module->base_address() + public_address;
+ frame->is_multiple = public_symbol->is_multiple;
}
}
-WindowsFrameInfo *BasicSourceLineResolver::Module::FindWindowsFrameInfo(
- const StackFrame *frame) const {
+WindowsFrameInfo* BasicSourceLineResolver::Module::FindWindowsFrameInfo(
+ const StackFrame* frame) const {
MemAddr address = frame->instruction - frame->module->base_address();
scoped_ptr<WindowsFrameInfo> result(new WindowsFrameInfo());
@@ -313,8 +394,8 @@ WindowsFrameInfo *BasicSourceLineResolver::Module::FindWindowsFrameInfo(
return NULL;
}
-CFIFrameInfo *BasicSourceLineResolver::Module::FindCFIFrameInfo(
- const StackFrame *frame) const {
+CFIFrameInfo* BasicSourceLineResolver::Module::FindCFIFrameInfo(
+ const StackFrame* frame) const {
MemAddr address = frame->instruction - frame->module->base_address();
MemAddr initial_base, initial_size;
string initial_rules;
@@ -347,9 +428,9 @@ CFIFrameInfo *BasicSourceLineResolver::Module::FindCFIFrameInfo(
return rules.release();
}
-bool BasicSourceLineResolver::Module::ParseFile(char *file_line) {
+bool BasicSourceLineResolver::Module::ParseFile(char* file_line) {
long index;
- char *filename;
+ char* filename;
if (SymbolParseHelper::ParseFile(file_line, &index, &filename)) {
files_.insert(make_pair(index, string(filename)));
return true;
@@ -357,13 +438,48 @@ bool BasicSourceLineResolver::Module::ParseFile(char *file_line) {
return false;
}
+bool BasicSourceLineResolver::Module::ParseInlineOrigin(
+ char* inline_origin_line) {
+ bool has_file_id;
+ long origin_id;
+ long source_file_id;
+ char* origin_name;
+ if (SymbolParseHelper::ParseInlineOrigin(inline_origin_line, &has_file_id,
+ &origin_id, &source_file_id,
+ &origin_name)) {
+ inline_origins_.insert(make_pair(
+ origin_id,
+ new InlineOrigin(has_file_id, source_file_id, origin_name)));
+ return true;
+ }
+ return false;
+}
+
+linked_ptr<BasicSourceLineResolver::Inline>
+BasicSourceLineResolver::Module::ParseInline(char* inline_line) {
+ bool has_call_site_file_id;
+ long inline_nest_level;
+ long call_site_line;
+ long call_site_file_id;
+ long origin_id;
+ vector<std::pair<MemAddr, MemAddr>> ranges;
+ if (SymbolParseHelper::ParseInline(inline_line, &has_call_site_file_id,
+ &inline_nest_level, &call_site_line,
+ &call_site_file_id, &origin_id, &ranges)) {
+ return linked_ptr<Inline>(new Inline(has_call_site_file_id,
+ inline_nest_level, call_site_line,
+ call_site_file_id, origin_id, ranges));
+ }
+ return linked_ptr<Inline>();
+}
+
BasicSourceLineResolver::Function*
-BasicSourceLineResolver::Module::ParseFunction(char *function_line) {
+BasicSourceLineResolver::Module::ParseFunction(char* function_line) {
bool is_multiple;
uint64_t address;
uint64_t size;
long stack_param_size;
- char *name;
+ char* name;
if (SymbolParseHelper::ParseFunction(function_line, &is_multiple, &address,
&size, &stack_param_size, &name)) {
return new Function(name, address, size, stack_param_size, is_multiple);
@@ -372,7 +488,7 @@ BasicSourceLineResolver::Module::ParseFunction(char *function_line) {
}
BasicSourceLineResolver::Line* BasicSourceLineResolver::Module::ParseLine(
- char *line_line) {
+ char* line_line) {
uint64_t address;
uint64_t size;
long line_number;
@@ -385,11 +501,11 @@ BasicSourceLineResolver::Line* BasicSourceLineResolver::Module::ParseLine(
return NULL;
}
-bool BasicSourceLineResolver::Module::ParsePublicSymbol(char *public_line) {
+bool BasicSourceLineResolver::Module::ParsePublicSymbol(char* public_line) {
bool is_multiple;
uint64_t address;
long stack_param_size;
- char *name;
+ char* name;
if (SymbolParseHelper::ParsePublicSymbol(public_line, &is_multiple, &address,
&stack_param_size, &name)) {
@@ -411,7 +527,7 @@ bool BasicSourceLineResolver::Module::ParsePublicSymbol(char *public_line) {
return false;
}
-bool BasicSourceLineResolver::Module::ParseStackInfo(char *stack_info_line) {
+bool BasicSourceLineResolver::Module::ParseStackInfo(char* stack_info_line) {
// Skip "STACK " prefix.
stack_info_line += 6;
@@ -419,7 +535,7 @@ bool BasicSourceLineResolver::Module::ParseStackInfo(char *stack_info_line) {
// information this is.
while (*stack_info_line == ' ')
stack_info_line++;
- const char *platform = stack_info_line;
+ const char* platform = stack_info_line;
while (!strchr(kWhitespace, *stack_info_line))
stack_info_line++;
*stack_info_line++ = '\0';
@@ -468,23 +584,23 @@ bool BasicSourceLineResolver::Module::ParseStackInfo(char *stack_info_line) {
}
bool BasicSourceLineResolver::Module::ParseCFIFrameInfo(
- char *stack_info_line) {
- char *cursor;
+ char* stack_info_line) {
+ char* cursor;
// Is this an INIT record or a delta record?
- char *init_or_address = strtok_r(stack_info_line, " \r\n", &cursor);
+ char* init_or_address = strtok_r(stack_info_line, " \r\n", &cursor);
if (!init_or_address)
return false;
if (strcmp(init_or_address, "INIT") == 0) {
// This record has the form "STACK INIT <address> <size> <rules...>".
- char *address_field = strtok_r(NULL, " \r\n", &cursor);
+ char* address_field = strtok_r(NULL, " \r\n", &cursor);
if (!address_field) return false;
- char *size_field = strtok_r(NULL, " \r\n", &cursor);
+ char* size_field = strtok_r(NULL, " \r\n", &cursor);
if (!size_field) return false;
- char *initial_rules = strtok_r(NULL, "\r\n", &cursor);
+ char* initial_rules = strtok_r(NULL, "\r\n", &cursor);
if (!initial_rules) return false;
MemAddr address = strtoul(address_field, NULL, 16);
@@ -494,17 +610,30 @@ bool BasicSourceLineResolver::Module::ParseCFIFrameInfo(
}
// This record has the form "STACK <address> <rules...>".
- char *address_field = init_or_address;
- char *delta_rules = strtok_r(NULL, "\r\n", &cursor);
+ char* address_field = init_or_address;
+ char* delta_rules = strtok_r(NULL, "\r\n", &cursor);
if (!delta_rules) return false;
MemAddr address = strtoul(address_field, NULL, 16);
cfi_delta_rules_[address] = delta_rules;
return true;
}
+bool BasicSourceLineResolver::Function::AppendInline(linked_ptr<Inline> in) {
+ // This happends if in's parent wasn't added due to a malformed INLINE record.
+ if (in->inline_nest_level > last_added_inline_nest_level + 1)
+ return false;
+
+ last_added_inline_nest_level = in->inline_nest_level;
+
+ // Store all ranges into current level of inlines.
+ for (auto range : in->inline_ranges)
+ inlines.StoreRange(range.first, range.second, in);
+ return true;
+}
+
// static
-bool SymbolParseHelper::ParseFile(char *file_line, long *index,
- char **filename) {
+bool SymbolParseHelper::ParseFile(char* file_line, long* index,
+ char** filename) {
// FILE <id> <filename>
assert(strncmp(file_line, "FILE ", 5) == 0);
file_line += 5; // skip prefix
@@ -514,7 +643,7 @@ bool SymbolParseHelper::ParseFile(char *file_line, long *index,
return false;
}
- char *after_number;
+ char* after_number;
*index = strtol(tokens[0], &after_number, 10);
if (!IsValidAfterNumber(after_number) || *index < 0 ||
*index == std::numeric_limits<long>::max()) {
@@ -530,9 +659,149 @@ bool SymbolParseHelper::ParseFile(char *file_line, long *index,
}
// static
-bool SymbolParseHelper::ParseFunction(char *function_line, bool *is_multiple,
- uint64_t *address, uint64_t *size,
- long *stack_param_size, char **name) {
+bool SymbolParseHelper::ParseInlineOrigin(char* inline_origin_line,
+ bool* has_file_id,
+ long* origin_id,
+ long* file_id,
+ char** name) {
+ // Old INLINE_ORIGIN format:
+ // INLINE_ORIGIN <origin_id> <file_id> <name>
+ // New INLINE_ORIGIN format:
+ // INLINE_ORIGIN <origin_id> <name>
+ assert(strncmp(inline_origin_line, "INLINE_ORIGIN ", 14) == 0);
+ inline_origin_line += 14; // skip prefix
+ vector<char*> tokens;
+ // Split the line into two parts so that the first token is "<origin_id>", and
+ // second token is either "<file_id> <name>"" or "<name>"" depending on the
+ // format version.
+ if (!Tokenize(inline_origin_line, kWhitespace, 2, &tokens)) {
+ return false;
+ }
+
+ char* after_number;
+ *origin_id = strtol(tokens[0], &after_number, 10);
+ if (!IsValidAfterNumber(after_number) || *origin_id < 0 ||
+ *origin_id == std::numeric_limits<long>::max()) {
+ return false;
+ }
+
+ // If the field after origin_id is a number, then it's old format.
+ char* remaining_line = tokens[1];
+ *has_file_id = true;
+ for (size_t i = 0;
+ i < strlen(remaining_line) && remaining_line[i] != ' ' && *has_file_id;
+ ++i) {
+ // If the file id is -1, it might be an artificial function that doesn't
+ // have file id. So, we consider -1 as a valid special case.
+ if (remaining_line[i] == '-' && i == 0) {
+ continue;
+ }
+ *has_file_id = isdigit(remaining_line[i]);
+ }
+
+ if (*has_file_id) {
+ // If it's old format, split "<file_id> <name>" to {"<field_id>", "<name>"}.
+ if (!Tokenize(remaining_line, kWhitespace, 2, &tokens)) {
+ return false;
+ }
+ *file_id = strtol(tokens[0], &after_number, 10);
+ // If the file id is -1, it might be an artificial function that doesn't
+ // have file id. So, we consider -1 as a valid special case.
+ if (!IsValidAfterNumber(after_number) || *file_id < -1 ||
+ *file_id == std::numeric_limits<long>::max()) {
+ return false;
+ }
+ }
+
+ *name = tokens[1];
+ if (!*name) {
+ return false;
+ }
+
+ return true;
+}
+
+// static
+bool SymbolParseHelper::ParseInline(
+ char* inline_line,
+ bool* has_call_site_file_id,
+ long* inline_nest_level,
+ long* call_site_line,
+ long* call_site_file_id,
+ long* origin_id,
+ vector<std::pair<MemAddr, MemAddr>>* ranges) {
+ // Old INLINE format:
+ // INLINE <inline_nest_level> <call_site_line> <origin_id> [<address> <size>]+
+ // New INLINE format:
+ // INLINE <inline_nest_level> <call_site_line> <call_site_file_id> <origin_id>
+ // [<address> <size>]+
+ assert(strncmp(inline_line, "INLINE ", 7) == 0);
+ inline_line += 7; // skip prefix
+
+ vector<char*> tokens;
+ // Increase max_tokens if necessary.
+ Tokenize(inline_line, kWhitespace, 512, &tokens);
+
+ // Determine the version of INLINE record by parity of the vector length.
+ *has_call_site_file_id = tokens.size() % 2 == 0;
+
+ // The length of the vector should be at least 5.
+ if (tokens.size() < 5) {
+ return false;
+ }
+
+ char* after_number;
+ size_t next_idx = 0;
+
+ *inline_nest_level = strtol(tokens[next_idx++], &after_number, 10);
+ if (!IsValidAfterNumber(after_number) || *inline_nest_level < 0 ||
+ *inline_nest_level == std::numeric_limits<long>::max()) {
+ return false;
+ }
+
+ *call_site_line = strtol(tokens[next_idx++], &after_number, 10);
+ if (!IsValidAfterNumber(after_number) || *call_site_line < 0 ||
+ *call_site_line == std::numeric_limits<long>::max()) {
+ return false;
+ }
+
+ if (*has_call_site_file_id) {
+ *call_site_file_id = strtol(tokens[next_idx++], &after_number, 10);
+ // If the file id is -1, it might be an artificial function that doesn't
+ // have file id. So, we consider -1 as a valid special case.
+ if (!IsValidAfterNumber(after_number) || *call_site_file_id < -1 ||
+ *call_site_file_id == std::numeric_limits<long>::max()) {
+ return false;
+ }
+ }
+
+ *origin_id = strtol(tokens[next_idx++], &after_number, 10);
+ if (!IsValidAfterNumber(after_number) || *origin_id < 0 ||
+ *origin_id == std::numeric_limits<long>::max()) {
+ return false;
+ }
+
+ while (next_idx < tokens.size()) {
+ MemAddr address = strtoull(tokens[next_idx++], &after_number, 16);
+ if (!IsValidAfterNumber(after_number) ||
+ address == std::numeric_limits<unsigned long long>::max()) {
+ return false;
+ }
+ MemAddr size = strtoull(tokens[next_idx++], &after_number, 16);
+ if (!IsValidAfterNumber(after_number) ||
+ size == std::numeric_limits<unsigned long long>::max()) {
+ return false;
+ }
+ ranges->push_back({address, size});
+ }
+
+ return true;
+}
+
+// static
+bool SymbolParseHelper::ParseFunction(char* function_line, bool* is_multiple,
+ uint64_t* address, uint64_t* size,
+ long* stack_param_size, char** name) {
// FUNC [<multiple>] <address> <size> <stack_param_size> <name>
assert(strncmp(function_line, "FUNC ", 5) == 0);
function_line += 5; // skip prefix
@@ -545,7 +814,7 @@ bool SymbolParseHelper::ParseFunction(char *function_line, bool *is_multiple,
*is_multiple = strcmp(tokens[0], "m") == 0;
int next_token = *is_multiple ? 1 : 0;
- char *after_number;
+ char* after_number;
*address = strtoull(tokens[next_token++], &after_number, 16);
if (!IsValidAfterNumber(after_number) ||
*address == std::numeric_limits<unsigned long long>::max()) {
@@ -568,16 +837,16 @@ bool SymbolParseHelper::ParseFunction(char *function_line, bool *is_multiple,
}
// static
-bool SymbolParseHelper::ParseLine(char *line_line, uint64_t *address,
- uint64_t *size, long *line_number,
- long *source_file) {
+bool SymbolParseHelper::ParseLine(char* line_line, uint64_t* address,
+ uint64_t* size, long* line_number,
+ long* source_file) {
// <address> <size> <line number> <source file id>
vector<char*> tokens;
if (!Tokenize(line_line, kWhitespace, 4, &tokens)) {
return false;
}
- char *after_number;
+ char* after_number;
*address = strtoull(tokens[0], &after_number, 16);
if (!IsValidAfterNumber(after_number) ||
*address == std::numeric_limits<unsigned long long>::max()) {
@@ -613,10 +882,10 @@ bool SymbolParseHelper::ParseLine(char *line_line, uint64_t *address,
}
// static
-bool SymbolParseHelper::ParsePublicSymbol(char *public_line, bool *is_multiple,
- uint64_t *address,
- long *stack_param_size,
- char **name) {
+bool SymbolParseHelper::ParsePublicSymbol(char* public_line, bool* is_multiple,
+ uint64_t* address,
+ long* stack_param_size,
+ char** name) {
// PUBLIC [<multiple>] <address> <stack_param_size> <name>
assert(strncmp(public_line, "PUBLIC ", 7) == 0);
public_line += 7; // skip prefix
@@ -629,7 +898,7 @@ bool SymbolParseHelper::ParsePublicSymbol(char *public_line, bool *is_multiple,
*is_multiple = strcmp(tokens[0], "m") == 0;
int next_token = *is_multiple ? 1 : 0;
- char *after_number;
+ char* after_number;
*address = strtoull(tokens[next_token++], &after_number, 16);
if (!IsValidAfterNumber(after_number) ||
*address == std::numeric_limits<unsigned long long>::max()) {
@@ -647,7 +916,7 @@ bool SymbolParseHelper::ParsePublicSymbol(char *public_line, bool *is_multiple,
}
// static
-bool SymbolParseHelper::IsValidAfterNumber(char *after_number) {
+bool SymbolParseHelper::IsValidAfterNumber(char* after_number) {
if (after_number != NULL && strchr(kWhitespace, *after_number) != NULL) {
return true;
}
diff --git a/src/processor/basic_source_line_resolver_types.h b/src/processor/basic_source_line_resolver_types.h
index 89eb57e8..3c8b01c7 100644
--- a/src/processor/basic_source_line_resolver_types.h
+++ b/src/processor/basic_source_line_resolver_types.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2010 Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -57,25 +56,37 @@ namespace google_breakpad {
struct
BasicSourceLineResolver::Function : public SourceLineResolverBase::Function {
- Function(const string &function_name,
+ Function(const string& function_name,
MemAddr function_address,
MemAddr code_size,
int set_parameter_size,
- bool is_mutiple) : Base(function_name,
- function_address,
- code_size,
- set_parameter_size,
- is_mutiple),
- lines() { }
- RangeMap< MemAddr, linked_ptr<Line> > lines;
+ bool is_mutiple)
+ : Base(function_name,
+ function_address,
+ code_size,
+ set_parameter_size,
+ is_mutiple),
+ inlines(true),
+ last_added_inline_nest_level(0) {}
+
+ // Append inline into corresponding RangeMap.
+ // This function assumes it's called in the order of reading INLINE records.
+ bool AppendInline(linked_ptr<Inline> in);
+
+ ContainedRangeMap<MemAddr, linked_ptr<Inline>> inlines;
+ RangeMap<MemAddr, linked_ptr<Line>> lines;
+
private:
typedef SourceLineResolverBase::Function Base;
+
+ // The last added inline_nest_level from INLINE record.
+ int last_added_inline_nest_level;
};
class BasicSourceLineResolver::Module : public SourceLineResolverBase::Module {
public:
- explicit Module(const string &name) : name_(name), is_corrupt_(false) { }
+ explicit Module(const string& name) : name_(name), is_corrupt_(false) { }
virtual ~Module() { }
// Loads a map from the given buffer in char* type.
@@ -83,7 +94,7 @@ class BasicSourceLineResolver::Module : public SourceLineResolverBase::Module {
// The passed in |memory buffer| is of size |memory_buffer_size|. If it is
// not null terminated, LoadMapFromMemory() will null terminate it by
// modifying the passed in buffer.
- virtual bool LoadMapFromMemory(char *memory_buffer,
+ virtual bool LoadMapFromMemory(char* memory_buffer,
size_t memory_buffer_size);
// Tells whether the loaded symbol data is corrupt. Return value is
@@ -92,20 +103,32 @@ class BasicSourceLineResolver::Module : public SourceLineResolverBase::Module {
// Looks up the given relative address, and fills the StackFrame struct
// with the result.
- virtual void LookupAddress(StackFrame *frame) const;
+ virtual void LookupAddress(
+ StackFrame* frame,
+ std::deque<std::unique_ptr<StackFrame>>* inlined_frame) const;
+
+ // Construct inlined frames for |frame| and store them in |inline_frames|.
+ // |frame|'s source line and source file name may be updated if an inlined
+ // frame is found inside |frame|. As a result, the innermost inlined frame
+ // will be the first one in |inline_frames|.
+ virtual void ConstructInlineFrames(
+ StackFrame* frame,
+ MemAddr address,
+ const ContainedRangeMap<uint64_t, linked_ptr<Inline>>& inline_map,
+ std::deque<std::unique_ptr<StackFrame>>* inline_frames) const;
// If Windows stack walking information is available covering ADDRESS,
// return a WindowsFrameInfo structure describing it. If the information
// is not available, returns NULL. A NULL return value does not indicate
// an error. The caller takes ownership of any returned WindowsFrameInfo
// object.
- virtual WindowsFrameInfo *FindWindowsFrameInfo(const StackFrame *frame) const;
+ virtual WindowsFrameInfo* FindWindowsFrameInfo(const StackFrame* frame) const;
// If CFI stack walking information is available covering ADDRESS,
// return a CFIFrameInfo structure describing it. If the information
// is not available, return NULL. The caller takes ownership of any
// returned CFIFrameInfo object.
- virtual CFIFrameInfo *FindCFIFrameInfo(const StackFrame *frame) const;
+ virtual CFIFrameInfo* FindCFIFrameInfo(const StackFrame* frame) const;
private:
// Friend declarations.
@@ -118,32 +141,39 @@ class BasicSourceLineResolver::Module : public SourceLineResolverBase::Module {
// Logs parse errors. |*num_errors| is increased every time LogParseError is
// called.
static void LogParseError(
- const string &message,
+ const string& message,
int line_number,
- int *num_errors);
+ int* num_errors);
// Parses a file declaration
- bool ParseFile(char *file_line);
+ bool ParseFile(char* file_line);
+
+ // Parses an inline origin declaration.
+ bool ParseInlineOrigin(char* inline_origin_line);
+
+ // Parses an inline declaration.
+ linked_ptr<Inline> ParseInline(char* inline_line);
// Parses a function declaration, returning a new Function object.
- Function* ParseFunction(char *function_line);
+ Function* ParseFunction(char* function_line);
// Parses a line declaration, returning a new Line object.
- Line* ParseLine(char *line_line);
+ Line* ParseLine(char* line_line);
// Parses a PUBLIC symbol declaration, storing it in public_symbols_.
// Returns false if an error occurs.
- bool ParsePublicSymbol(char *public_line);
+ bool ParsePublicSymbol(char* public_line);
// Parses a STACK WIN or STACK CFI frame info declaration, storing
// it in the appropriate table.
- bool ParseStackInfo(char *stack_info_line);
+ bool ParseStackInfo(char* stack_info_line);
// Parses a STACK CFI record, storing it in cfi_frame_info_.
- bool ParseCFIFrameInfo(char *stack_info_line);
+ bool ParseCFIFrameInfo(char* stack_info_line);
string name_;
FileMap files_;
+ std::map<int, linked_ptr<InlineOrigin>> inline_origins_;
RangeMap< MemAddr, linked_ptr<Function> > functions_;
AddressMap< MemAddr, linked_ptr<PublicSymbol> > public_symbols_;
bool is_corrupt_;
diff --git a/src/processor/basic_source_line_resolver_unittest.cc b/src/processor/basic_source_line_resolver_unittest.cc
index 90c34172..fba4e9a6 100644
--- a/src/processor/basic_source_line_resolver_unittest.cc
+++ b/src/processor/basic_source_line_resolver_unittest.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2010 Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -52,7 +51,6 @@ using google_breakpad::CodeModule;
using google_breakpad::MemoryRegion;
using google_breakpad::StackFrame;
using google_breakpad::WindowsFrameInfo;
-using google_breakpad::linked_ptr;
using google_breakpad::scoped_ptr;
using google_breakpad::SymbolParseHelper;
@@ -83,26 +81,26 @@ class TestCodeModule : public CodeModule {
class MockMemoryRegion: public MemoryRegion {
uint64_t GetBase() const { return 0x10000; }
uint32_t GetSize() const { return 0x01000; }
- bool GetMemoryAtAddress(uint64_t address, uint8_t *value) const {
+ bool GetMemoryAtAddress(uint64_t address, uint8_t* value) const {
*value = address & 0xff;
return true;
}
- bool GetMemoryAtAddress(uint64_t address, uint16_t *value) const {
+ bool GetMemoryAtAddress(uint64_t address, uint16_t* value) const {
*value = address & 0xffff;
return true;
}
- bool GetMemoryAtAddress(uint64_t address, uint32_t *value) const {
+ bool GetMemoryAtAddress(uint64_t address, uint32_t* value) const {
switch (address) {
- case 0x10008: *value = 0x98ecadc3; break; // saved %ebx
- case 0x1000c: *value = 0x878f7524; break; // saved %esi
- case 0x10010: *value = 0x6312f9a5; break; // saved %edi
- case 0x10014: *value = 0x10038; break; // caller's %ebp
- case 0x10018: *value = 0xf6438648; break; // return address
- default: *value = 0xdeadbeef; break; // junk
+ case 0x10008: *value = 0x98ecadc3; break; // saved %ebx
+ case 0x1000c: *value = 0x878f7524; break; // saved %esi
+ case 0x10010: *value = 0x6312f9a5; break; // saved %edi
+ case 0x10014: *value = 0x10038; break; // caller's %ebp
+ case 0x10018: *value = 0xf6438648; break; // return address
+ default: *value = 0xdeadbeef; break; // junk
}
return true;
}
- bool GetMemoryAtAddress(uint64_t address, uint64_t *value) const {
+ bool GetMemoryAtAddress(uint64_t address, uint64_t* value) const {
*value = address;
return true;
}
@@ -116,9 +114,9 @@ class MockMemoryRegion: public MemoryRegion {
// EXPECTED's.) Also verify that ACTUAL has associations for ".ra" and
// ".cfa".
static bool VerifyRegisters(
- const char *file, int line,
- const CFIFrameInfo::RegisterValueMap<uint32_t> &expected,
- const CFIFrameInfo::RegisterValueMap<uint32_t> &actual) {
+ const char* file, int line,
+ const CFIFrameInfo::RegisterValueMap<uint32_t>& expected,
+ const CFIFrameInfo::RegisterValueMap<uint32_t>& actual) {
CFIFrameInfo::RegisterValueMap<uint32_t>::const_iterator a;
a = actual.find(".cfa");
if (a == actual.end())
@@ -148,7 +146,7 @@ static bool VerifyRegisters(
}
-static bool VerifyEmpty(const StackFrame &frame) {
+static bool VerifyEmpty(const StackFrame& frame) {
if (frame.function_name.empty() &&
frame.source_file_name.empty() &&
frame.source_line == 0)
@@ -156,7 +154,7 @@ static bool VerifyEmpty(const StackFrame &frame) {
return false;
}
-static void ClearSourceLineInfo(StackFrame *frame) {
+static void ClearSourceLineInfo(StackFrame* frame) {
frame->function_name.clear();
frame->module = NULL;
frame->source_file_name.clear();
@@ -164,7 +162,7 @@ static void ClearSourceLineInfo(StackFrame *frame) {
}
class TestBasicSourceLineResolver : public ::testing::Test {
-public:
+ public:
void SetUp() {
testdata_dir = string(getenv("srcdir") ? getenv("srcdir") : ".") +
"/src/processor/testdata";
@@ -189,16 +187,17 @@ TEST_F(TestBasicSourceLineResolver, TestLoadAndResolve)
scoped_ptr<CFIFrameInfo> cfi_frame_info;
frame.instruction = 0x1000;
frame.module = NULL;
- resolver.FillSourceLineInfo(&frame);
+ resolver.FillSourceLineInfo(&frame, nullptr);
ASSERT_FALSE(frame.module);
ASSERT_TRUE(frame.function_name.empty());
ASSERT_EQ(frame.function_base, 0U);
ASSERT_TRUE(frame.source_file_name.empty());
ASSERT_EQ(frame.source_line, 0);
ASSERT_EQ(frame.source_line_base, 0U);
+ EXPECT_EQ(frame.is_multiple, false);
frame.module = &module1;
- resolver.FillSourceLineInfo(&frame);
+ resolver.FillSourceLineInfo(&frame, nullptr);
ASSERT_EQ(frame.function_name, "Function1_1");
ASSERT_TRUE(frame.module);
ASSERT_EQ(frame.module->code_file(), "module1");
@@ -206,6 +205,7 @@ TEST_F(TestBasicSourceLineResolver, TestLoadAndResolve)
ASSERT_EQ(frame.source_file_name, "file1_1.cc");
ASSERT_EQ(frame.source_line, 44);
ASSERT_EQ(frame.source_line_base, 0x1000U);
+ EXPECT_EQ(frame.is_multiple, true);
windows_frame_info.reset(resolver.FindWindowsFrameInfo(&frame));
ASSERT_TRUE(windows_frame_info.get());
ASSERT_EQ(windows_frame_info->type_, WindowsFrameInfo::STACK_INFO_FRAME_DATA);
@@ -216,13 +216,13 @@ TEST_F(TestBasicSourceLineResolver, TestLoadAndResolve)
ClearSourceLineInfo(&frame);
frame.instruction = 0x800;
frame.module = &module1;
- resolver.FillSourceLineInfo(&frame);
+ resolver.FillSourceLineInfo(&frame, nullptr);
ASSERT_TRUE(VerifyEmpty(frame));
windows_frame_info.reset(resolver.FindWindowsFrameInfo(&frame));
ASSERT_FALSE(windows_frame_info.get());
frame.instruction = 0x1280;
- resolver.FillSourceLineInfo(&frame);
+ resolver.FillSourceLineInfo(&frame, nullptr);
ASSERT_EQ(frame.function_name, "Function1_3");
ASSERT_TRUE(frame.source_file_name.empty());
ASSERT_EQ(frame.source_line, 0);
@@ -233,7 +233,7 @@ TEST_F(TestBasicSourceLineResolver, TestLoadAndResolve)
ASSERT_TRUE(windows_frame_info->program_string.empty());
frame.instruction = 0x1380;
- resolver.FillSourceLineInfo(&frame);
+ resolver.FillSourceLineInfo(&frame, nullptr);
ASSERT_EQ(frame.function_name, "Function1_4");
ASSERT_TRUE(frame.source_file_name.empty());
ASSERT_EQ(frame.source_line, 0);
@@ -342,17 +342,18 @@ TEST_F(TestBasicSourceLineResolver, TestLoadAndResolve)
frame.instruction = 0x2900;
frame.module = &module1;
- resolver.FillSourceLineInfo(&frame);
+ resolver.FillSourceLineInfo(&frame, nullptr);
ASSERT_EQ(frame.function_name, string("PublicSymbol"));
+ EXPECT_EQ(frame.is_multiple, true);
frame.instruction = 0x4000;
frame.module = &module1;
- resolver.FillSourceLineInfo(&frame);
+ resolver.FillSourceLineInfo(&frame, nullptr);
ASSERT_EQ(frame.function_name, string("LargeFunction"));
frame.instruction = 0x2181;
frame.module = &module2;
- resolver.FillSourceLineInfo(&frame);
+ resolver.FillSourceLineInfo(&frame, nullptr);
ASSERT_EQ(frame.function_name, "Function2_2");
ASSERT_EQ(frame.function_base, 0x2170U);
ASSERT_TRUE(frame.module);
@@ -360,24 +361,26 @@ TEST_F(TestBasicSourceLineResolver, TestLoadAndResolve)
ASSERT_EQ(frame.source_file_name, "file2_2.cc");
ASSERT_EQ(frame.source_line, 21);
ASSERT_EQ(frame.source_line_base, 0x2180U);
+ EXPECT_EQ(frame.is_multiple, false);
windows_frame_info.reset(resolver.FindWindowsFrameInfo(&frame));
ASSERT_TRUE(windows_frame_info.get());
ASSERT_EQ(windows_frame_info->type_, WindowsFrameInfo::STACK_INFO_FRAME_DATA);
ASSERT_EQ(windows_frame_info->prolog_size, 1U);
frame.instruction = 0x216f;
- resolver.FillSourceLineInfo(&frame);
+ resolver.FillSourceLineInfo(&frame, nullptr);
ASSERT_EQ(frame.function_name, "Public2_1");
+ EXPECT_EQ(frame.is_multiple, false);
ClearSourceLineInfo(&frame);
frame.instruction = 0x219f;
frame.module = &module2;
- resolver.FillSourceLineInfo(&frame);
+ resolver.FillSourceLineInfo(&frame, nullptr);
ASSERT_TRUE(frame.function_name.empty());
frame.instruction = 0x21a0;
frame.module = &module2;
- resolver.FillSourceLineInfo(&frame);
+ resolver.FillSourceLineInfo(&frame, nullptr);
ASSERT_EQ(frame.function_name, "Public2_2");
}
@@ -413,11 +416,101 @@ TEST_F(TestBasicSourceLineResolver, TestUnload)
ASSERT_TRUE(resolver.HasModule(&module1));
}
+TEST_F(TestBasicSourceLineResolver, TestLoadAndResolveOldInlines) {
+ TestCodeModule module("linux_inline");
+ ASSERT_TRUE(resolver.LoadModule(
+ &module, testdata_dir +
+ "/symbols/linux_inline/BBA6FA10B8AAB33D00000000000000000/"
+ "linux_inline.old.sym"));
+ ASSERT_TRUE(resolver.HasModule(&module));
+ StackFrame frame;
+ std::deque<std::unique_ptr<StackFrame>> inlined_frames;
+ frame.instruction = 0x161b6;
+ frame.module = &module;
+ // main frame.
+ resolver.FillSourceLineInfo(&frame, &inlined_frames);
+ ASSERT_EQ(frame.function_name, "main");
+ ASSERT_EQ(frame.function_base, 0x15b30U);
+ ASSERT_EQ(frame.source_file_name, "linux_inline.cpp");
+ ASSERT_EQ(frame.source_line, 42);
+ ASSERT_EQ(frame.source_line_base, 0x161b6U);
+ EXPECT_EQ(frame.is_multiple, false);
+
+ ASSERT_EQ(inlined_frames.size(), 3UL);
+
+ // Inlined frames inside main frame.
+ ASSERT_EQ(inlined_frames[2]->function_name, "foo()");
+ ASSERT_EQ(inlined_frames[2]->function_base, 0x15b45U);
+ ASSERT_EQ(inlined_frames[2]->source_file_name, "linux_inline.cpp");
+ ASSERT_EQ(inlined_frames[2]->source_line, 39);
+ ASSERT_EQ(inlined_frames[2]->source_line_base, 0x161b6U);
+ ASSERT_EQ(inlined_frames[2]->trust, StackFrame::FRAME_TRUST_INLINE);
+
+ ASSERT_EQ(inlined_frames[1]->function_name, "bar()");
+ ASSERT_EQ(inlined_frames[1]->function_base, 0x15b72U);
+ ASSERT_EQ(inlined_frames[1]->source_file_name, "linux_inline.cpp");
+ ASSERT_EQ(inlined_frames[1]->source_line, 32);
+ ASSERT_EQ(inlined_frames[1]->source_line_base, 0x161b6U);
+ ASSERT_EQ(inlined_frames[1]->trust, StackFrame::FRAME_TRUST_INLINE);
+
+ ASSERT_EQ(inlined_frames[0]->function_name, "func()");
+ ASSERT_EQ(inlined_frames[0]->function_base, 0x15b83U);
+ ASSERT_EQ(inlined_frames[0]->source_file_name, "linux_inline.cpp");
+ ASSERT_EQ(inlined_frames[0]->source_line, 27);
+ ASSERT_EQ(inlined_frames[0]->source_line_base, 0x161b6U);
+ ASSERT_EQ(inlined_frames[0]->trust, StackFrame::FRAME_TRUST_INLINE);
+}
+
+TEST_F(TestBasicSourceLineResolver, TestLoadAndResolveNewInlines) {
+ TestCodeModule module("linux_inline");
+ ASSERT_TRUE(resolver.LoadModule(
+ &module, testdata_dir +
+ "/symbols/linux_inline/BBA6FA10B8AAB33D00000000000000000/"
+ "linux_inline.new.sym"));
+ ASSERT_TRUE(resolver.HasModule(&module));
+ StackFrame frame;
+ std::deque<std::unique_ptr<StackFrame>> inlined_frames;
+ frame.instruction = 0x161b6;
+ frame.module = &module;
+ // main frame.
+ resolver.FillSourceLineInfo(&frame, &inlined_frames);
+ ASSERT_EQ(frame.function_name, "main");
+ ASSERT_EQ(frame.function_base, 0x15b30U);
+ ASSERT_EQ(frame.source_file_name, "a.cpp");
+ ASSERT_EQ(frame.source_line, 42);
+ ASSERT_EQ(frame.source_line_base, 0x161b6U);
+ EXPECT_EQ(frame.is_multiple, false);
+
+ ASSERT_EQ(inlined_frames.size(), 3UL);
+
+ // Inlined frames inside main frame.
+ ASSERT_EQ(inlined_frames[2]->function_name, "foo()");
+ ASSERT_EQ(inlined_frames[2]->function_base, 0x15b45U);
+ ASSERT_EQ(inlined_frames[2]->source_file_name, "b.cpp");
+ ASSERT_EQ(inlined_frames[2]->source_line, 39);
+ ASSERT_EQ(inlined_frames[2]->source_line_base, 0x161b6U);
+ ASSERT_EQ(inlined_frames[2]->trust, StackFrame::FRAME_TRUST_INLINE);
+
+ ASSERT_EQ(inlined_frames[1]->function_name, "bar()");
+ ASSERT_EQ(inlined_frames[1]->function_base, 0x15b72U);
+ ASSERT_EQ(inlined_frames[1]->source_file_name, "c.cpp");
+ ASSERT_EQ(inlined_frames[1]->source_line, 32);
+ ASSERT_EQ(inlined_frames[1]->source_line_base, 0x161b6U);
+ ASSERT_EQ(inlined_frames[1]->trust, StackFrame::FRAME_TRUST_INLINE);
+
+ ASSERT_EQ(inlined_frames[0]->function_name, "func()");
+ ASSERT_EQ(inlined_frames[0]->function_base, 0x15b83U);
+ ASSERT_EQ(inlined_frames[0]->source_file_name, "linux_inline.cpp");
+ ASSERT_EQ(inlined_frames[0]->source_line, 27);
+ ASSERT_EQ(inlined_frames[0]->source_line_base, 0x161b6U);
+ ASSERT_EQ(inlined_frames[0]->trust, StackFrame::FRAME_TRUST_INLINE);
+}
+
// Test parsing of valid FILE lines. The format is:
// FILE <id> <filename>
TEST(SymbolParseHelper, ParseFileValid) {
long index;
- char *filename;
+ char* filename;
char kTestLine[] = "FILE 1 file name";
ASSERT_TRUE(SymbolParseHelper::ParseFile(kTestLine, &index, &filename));
@@ -435,7 +528,7 @@ TEST(SymbolParseHelper, ParseFileValid) {
// FILE <id> <filename>
TEST(SymbolParseHelper, ParseFileInvalid) {
long index;
- char *filename;
+ char* filename;
// Test missing file name.
char kTestLine[] = "FILE 1 ";
@@ -461,7 +554,7 @@ TEST(SymbolParseHelper, ParseFunctionValid) {
uint64_t address;
uint64_t size;
long stack_param_size;
- char *name;
+ char* name;
char kTestLine[] = "FUNC 1 2 3 function name";
ASSERT_TRUE(SymbolParseHelper::ParseFunction(kTestLine, &multiple, &address,
@@ -513,7 +606,7 @@ TEST(SymbolParseHelper, ParseFunctionInvalid) {
uint64_t address;
uint64_t size;
long stack_param_size;
- char *name;
+ char* name;
// Test missing function name.
char kTestLine[] = "FUNC 1 2 3 ";
@@ -649,7 +742,7 @@ TEST(SymbolParseHelper, ParsePublicSymbolValid) {
bool multiple;
uint64_t address;
long stack_param_size;
- char *name;
+ char* name;
char kTestLine[] = "PUBLIC 1 2 3";
ASSERT_TRUE(SymbolParseHelper::ParsePublicSymbol(kTestLine, &multiple,
@@ -697,7 +790,7 @@ TEST(SymbolParseHelper, ParsePublicSymbolInvalid) {
bool multiple;
uint64_t address;
long stack_param_size;
- char *name;
+ char* name;
// Test missing source function name.
char kTestLine[] = "PUBLIC 1 2 ";
@@ -736,9 +829,179 @@ TEST(SymbolParseHelper, ParsePublicSymbolInvalid) {
&name));
}
+// Test parsing of valid INLINE_ORIGIN lines.
+// The old format:
+// INLINE_ORIGIN <origin_id> <file_id> <name>
+// The new format:
+// INLINE_ORIGIN <origin_id> <name>
+TEST(SymbolParseHelper, ParseInlineOriginValid) {
+ bool has_file_id;
+ long origin_id;
+ long file_id;
+ char* name;
+ // Test for old format.
+ char kTestLine[] = "INLINE_ORIGIN 1 1 function name";
+ ASSERT_TRUE(SymbolParseHelper::ParseInlineOrigin(
+ kTestLine, &has_file_id, &origin_id, &file_id, &name));
+ EXPECT_EQ(true, has_file_id);
+ EXPECT_EQ(1, origin_id);
+ EXPECT_EQ(1, file_id);
+ EXPECT_EQ("function name", string(name));
+
+ // -1 is a file id, which is used when the function is artifical.
+ char kTestLine1[] = "INLINE_ORIGIN 0 -1 function name";
+ ASSERT_TRUE(SymbolParseHelper::ParseInlineOrigin(
+ kTestLine1, &has_file_id, &origin_id, &file_id, &name));
+ EXPECT_EQ(true, has_file_id);
+ EXPECT_EQ(0, origin_id);
+ EXPECT_EQ(-1, file_id);
+ EXPECT_EQ("function name", string(name));
+
+ // Test for new format.
+ char kTestLine2[] = "INLINE_ORIGIN 0 function name";
+ ASSERT_TRUE(SymbolParseHelper::ParseInlineOrigin(
+ kTestLine2, &has_file_id, &origin_id, &file_id, &name));
+ EXPECT_EQ(false, has_file_id);
+ EXPECT_EQ(0, origin_id);
+ EXPECT_EQ("function name", string(name));
+
+ char kTestLine3[] = "INLINE_ORIGIN 0 function";
+ ASSERT_TRUE(SymbolParseHelper::ParseInlineOrigin(
+ kTestLine3, &has_file_id, &origin_id, &file_id, &name));
+ EXPECT_EQ(false, has_file_id);
+ EXPECT_EQ(0, origin_id);
+ EXPECT_EQ("function", string(name));
+}
+
+// Test parsing of valid INLINE ORIGIN lines. The format is:
+// INLINE_ORIGIN <origin_id> <file_id> <name>
+TEST(SymbolParseHelper, ParseInlineOriginInvalid) {
+ bool has_file_id;
+ long origin_id;
+ long file_id;
+ char* name;
+
+ // Test missing function name.
+ char kTestLine[] = "INLINE_ORIGIN 1 1";
+ ASSERT_FALSE(SymbolParseHelper::ParseInlineOrigin(
+ kTestLine, &has_file_id, &origin_id, &file_id, &name));
+
+ // Test bad origin id.
+ char kTestLine1[] = "INLINE_ORIGIN x1 1 function name";
+ ASSERT_FALSE(SymbolParseHelper::ParseInlineOrigin(
+ kTestLine1, &has_file_id, &origin_id, &file_id, &name));
+
+ // Test large origin id.
+ char kTestLine2[] = "INLINE_ORIGIN 123123123123123123123123 1 function name";
+ ASSERT_FALSE(SymbolParseHelper::ParseInlineOrigin(
+ kTestLine2, &has_file_id, &origin_id, &file_id, &name));
+
+ // Test negative origin id.
+ char kTestLine3[] = "INLINE_ORIGIN -1 1 function name";
+ ASSERT_FALSE(SymbolParseHelper::ParseInlineOrigin(
+ kTestLine3, &has_file_id, &origin_id, &file_id, &name));
+}
+
+// Test parsing of valid INLINE lines.
+// The old format:
+// INLINE <inline_nest_level> <call_site_line> <origin_id> [<address> <size>]+
+// The new format:
+// INLINE <inline_nest_level> <call_site_line> <call_site_file_id> <origin_id>
+// [<address> <size>]+
+TEST(SymbolParseHelper, ParseInlineValid) {
+ bool has_call_site_file_id;
+ long inline_nest_level;
+ long call_site_line;
+ long call_site_file_id;
+ long origin_id;
+ std::vector<std::pair<uint64_t, uint64_t>> ranges;
+
+ // Test for old format.
+ char kTestLine[] = "INLINE 0 1 2 3 4";
+ ASSERT_TRUE(SymbolParseHelper::ParseInline(
+ kTestLine, &has_call_site_file_id, &inline_nest_level, &call_site_line,
+ &call_site_file_id, &origin_id, &ranges));
+ EXPECT_EQ(false, has_call_site_file_id);
+ EXPECT_EQ(0, inline_nest_level);
+ EXPECT_EQ(1, call_site_line);
+ EXPECT_EQ(2, origin_id);
+ EXPECT_EQ(0x3ULL, ranges[0].first);
+ EXPECT_EQ(0x4ULL, ranges[0].second);
+ ranges.clear();
+
+ // Test hex and discontinuous ranges.
+ char kTestLine1[] = "INLINE 0 1 2 a b 1a 1b";
+ ASSERT_TRUE(SymbolParseHelper::ParseInline(
+ kTestLine1, &has_call_site_file_id, &inline_nest_level, &call_site_line,
+ &call_site_file_id, &origin_id, &ranges));
+ EXPECT_EQ(false, has_call_site_file_id);
+ EXPECT_EQ(0, inline_nest_level);
+ EXPECT_EQ(1, call_site_line);
+ EXPECT_EQ(2, origin_id);
+ EXPECT_EQ(0xaULL, ranges[0].first);
+ EXPECT_EQ(0xbULL, ranges[0].second);
+ EXPECT_EQ(0x1aULL, ranges[1].first);
+ EXPECT_EQ(0x1bULL, ranges[1].second);
+
+ // Test for new format.
+ char kTestLine2[] = "INLINE 0 1 2 3 a b 1a 1b";
+ ASSERT_TRUE(SymbolParseHelper::ParseInline(
+ kTestLine2, &has_call_site_file_id, &inline_nest_level, &call_site_line,
+ &call_site_file_id, &origin_id, &ranges));
+ EXPECT_EQ(true, has_call_site_file_id);
+ EXPECT_EQ(0, inline_nest_level);
+ EXPECT_EQ(1, call_site_line);
+ EXPECT_EQ(2, call_site_file_id);
+ EXPECT_EQ(3, origin_id);
+ EXPECT_EQ(0xaULL, ranges[0].first);
+ EXPECT_EQ(0xbULL, ranges[0].second);
+ EXPECT_EQ(0x1aULL, ranges[1].first);
+ EXPECT_EQ(0x1bULL, ranges[1].second);
+}
+
+// Test parsing of Invalid INLINE lines.
+TEST(SymbolParseHelper, ParseInlineInvalid) {
+ bool has_call_site_file_id;
+ long inline_nest_level;
+ long call_site_line;
+ long call_site_file_id;
+ long origin_id;
+ std::vector<std::pair<uint64_t, uint64_t>> ranges;
+
+ // Test negative inline_nest_level.
+ char kTestLine[] = "INLINE -1 1 2 3 4";
+ ASSERT_FALSE(SymbolParseHelper::ParseInline(
+ kTestLine, &has_call_site_file_id, &inline_nest_level, &call_site_line,
+ &call_site_file_id, &origin_id, &ranges));
+
+ // Test negative call_site_line.
+ char kTestLine1[] = "INLINE 0 -1 2 3 4";
+ ASSERT_FALSE(SymbolParseHelper::ParseInline(
+ kTestLine1, &has_call_site_file_id, &inline_nest_level, &call_site_line,
+ &call_site_file_id, &origin_id, &ranges));
+
+ // Test negative origin_id.
+ char kTestLine2[] = "INLINE 0 1 -2 3 4";
+ ASSERT_FALSE(SymbolParseHelper::ParseInline(
+ kTestLine2, &has_call_site_file_id, &inline_nest_level, &call_site_line,
+ &call_site_file_id, &origin_id, &ranges));
+
+ // Test missing ranges.
+ char kTestLine3[] = "INLINE 0 1 -2";
+ ASSERT_FALSE(SymbolParseHelper::ParseInline(
+ kTestLine3, &has_call_site_file_id, &inline_nest_level, &call_site_line,
+ &call_site_file_id, &origin_id, &ranges));
+
+ // Test missing size for range.
+ char kTestLine4[] = "INLINE 0 1 -2 3";
+ ASSERT_FALSE(SymbolParseHelper::ParseInline(
+ kTestLine4, &has_call_site_file_id, &inline_nest_level, &call_site_line,
+ &call_site_file_id, &origin_id, &ranges));
+}
+
} // namespace
-int main(int argc, char *argv[]) {
+int main(int argc, char* argv[]) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
diff --git a/src/processor/call_stack.cc b/src/processor/call_stack.cc
index 925f0846..87ffd1ae 100644
--- a/src/processor/call_stack.cc
+++ b/src/processor/call_stack.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2006, Google Inc.
-// All rights reserved.
+// Copyright 2006 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -43,7 +42,7 @@ CallStack::~CallStack() {
}
void CallStack::Clear() {
- for (vector<StackFrame *>::const_iterator iterator = frames_.begin();
+ for (vector<StackFrame*>::const_iterator iterator = frames_.begin();
iterator != frames_.end();
++iterator) {
delete *iterator;
diff --git a/src/processor/cfi_frame_info-inl.h b/src/processor/cfi_frame_info-inl.h
index 7e7af0af..acfc4f79 100644
--- a/src/processor/cfi_frame_info-inl.h
+++ b/src/processor/cfi_frame_info-inl.h
@@ -1,7 +1,6 @@
// -*- mode: C++ -*-
-// Copyright (c) 2010, Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -13,7 +12,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -42,12 +41,12 @@ namespace google_breakpad {
template <typename RegisterType, class RawContextType>
bool SimpleCFIWalker<RegisterType, RawContextType>::FindCallerRegisters(
- const MemoryRegion &memory,
- const CFIFrameInfo &cfi_frame_info,
- const RawContextType &callee_context,
+ const MemoryRegion& memory,
+ const CFIFrameInfo& cfi_frame_info,
+ const RawContextType& callee_context,
int callee_validity,
- RawContextType *caller_context,
- int *caller_validity) const {
+ RawContextType* caller_context,
+ int* caller_validity) const {
typedef CFIFrameInfo::RegisterValueMap<RegisterType> ValueMap;
ValueMap callee_registers;
ValueMap caller_registers;
@@ -56,7 +55,7 @@ bool SimpleCFIWalker<RegisterType, RawContextType>::FindCallerRegisters(
// Populate callee_registers with register values from callee_context.
for (size_t i = 0; i < map_size_; i++) {
- const RegisterSet &r = register_map_[i];
+ const RegisterSet& r = register_map_[i];
if (callee_validity & r.validity_flag)
callee_registers[r.name] = callee_context.*r.context_member;
}
@@ -71,7 +70,7 @@ bool SimpleCFIWalker<RegisterType, RawContextType>::FindCallerRegisters(
memset(caller_context, 0xda, sizeof(*caller_context));
*caller_validity = 0;
for (size_t i = 0; i < map_size_; i++) {
- const RegisterSet &r = register_map_[i];
+ const RegisterSet& r = register_map_[i];
typename ValueMap::const_iterator caller_entry;
// Did the rules provide a value for this register by its name?
diff --git a/src/processor/cfi_frame_info.cc b/src/processor/cfi_frame_info.cc
index 0c4af7ba..5216a44e 100644
--- a/src/processor/cfi_frame_info.cc
+++ b/src/processor/cfi_frame_info.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2010, Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -48,9 +47,9 @@ namespace google_breakpad {
#endif
template<typename V>
-bool CFIFrameInfo::FindCallerRegs(const RegisterValueMap<V> &registers,
- const MemoryRegion &memory,
- RegisterValueMap<V> *caller_registers) const {
+bool CFIFrameInfo::FindCallerRegs(const RegisterValueMap<V>& registers,
+ const MemoryRegion& memory,
+ RegisterValueMap<V>* caller_registers) const {
// If there are not rules for both .ra and .cfa in effect at this address,
// don't use this CFI data for stack walking.
if (cfa_rule_.empty() || ra_rule_.empty())
@@ -81,7 +80,7 @@ bool CFIFrameInfo::FindCallerRegs(const RegisterValueMap<V> &registers,
working = registers;
working[".cfa"] = cfa;
if (!evaluator.EvaluateForValue(it->second, &value))
- return false;
+ continue;
(*caller_registers)[it->first] = value;
}
@@ -93,13 +92,13 @@ bool CFIFrameInfo::FindCallerRegs(const RegisterValueMap<V> &registers,
// Explicit instantiations for 32-bit and 64-bit architectures.
template bool CFIFrameInfo::FindCallerRegs<uint32_t>(
- const RegisterValueMap<uint32_t> &registers,
- const MemoryRegion &memory,
- RegisterValueMap<uint32_t> *caller_registers) const;
+ const RegisterValueMap<uint32_t>& registers,
+ const MemoryRegion& memory,
+ RegisterValueMap<uint32_t>* caller_registers) const;
template bool CFIFrameInfo::FindCallerRegs<uint64_t>(
- const RegisterValueMap<uint64_t> &registers,
- const MemoryRegion &memory,
- RegisterValueMap<uint64_t> *caller_registers) const;
+ const RegisterValueMap<uint64_t>& registers,
+ const MemoryRegion& memory,
+ RegisterValueMap<uint64_t>* caller_registers) const;
string CFIFrameInfo::Serialize() const {
std::ostringstream stream;
@@ -123,7 +122,7 @@ string CFIFrameInfo::Serialize() const {
return stream.str();
}
-bool CFIRuleParser::Parse(const string &rule_set) {
+bool CFIRuleParser::Parse(const string& rule_set) {
size_t rule_set_len = rule_set.size();
scoped_array<char> working_copy(new char[rule_set_len + 1]);
memcpy(working_copy.get(), rule_set.data(), rule_set_len);
@@ -132,9 +131,9 @@ bool CFIRuleParser::Parse(const string &rule_set) {
name_.clear();
expression_.clear();
- char *cursor;
+ char* cursor;
static const char token_breaks[] = " \t\r\n";
- char *token = strtok_r(working_copy.get(), token_breaks, &cursor);
+ char* token = strtok_r(working_copy.get(), token_breaks, &cursor);
for (;;) {
// End of rule set?
@@ -170,16 +169,16 @@ bool CFIRuleParser::Report() {
return true;
}
-void CFIFrameInfoParseHandler::CFARule(const string &expression) {
+void CFIFrameInfoParseHandler::CFARule(const string& expression) {
frame_info_->SetCFARule(expression);
}
-void CFIFrameInfoParseHandler::RARule(const string &expression) {
+void CFIFrameInfoParseHandler::RARule(const string& expression) {
frame_info_->SetRARule(expression);
}
-void CFIFrameInfoParseHandler::RegisterRule(const string &name,
- const string &expression) {
+void CFIFrameInfoParseHandler::RegisterRule(const string& name,
+ const string& expression) {
frame_info_->SetRegisterRule(name, expression);
}
diff --git a/src/processor/cfi_frame_info.h b/src/processor/cfi_frame_info.h
index 90a1b3d7..08f1eb72 100644
--- a/src/processor/cfi_frame_info.h
+++ b/src/processor/cfi_frame_info.h
@@ -1,7 +1,6 @@
// -*- mode: C++ -*-
-// Copyright (c) 2010, Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -13,7 +12,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -72,9 +71,9 @@ class CFIFrameInfo {
// Set the expression for computing a call frame address, return
// address, or register's value. At least the CFA rule and the RA
// rule must be set before calling FindCallerRegs.
- void SetCFARule(const string &expression) { cfa_rule_ = expression; }
- void SetRARule(const string &expression) { ra_rule_ = expression; }
- void SetRegisterRule(const string &register_name, const string &expression) {
+ void SetCFARule(const string& expression) { cfa_rule_ = expression; }
+ void SetRARule(const string& expression) { ra_rule_ = expression; }
+ void SetRegisterRule(const string& register_name, const string& expression) {
register_rules_[register_name] = expression;
}
@@ -96,9 +95,9 @@ class CFIFrameInfo {
// These may be helpful in computing the caller's PC and stack
// pointer, if their values are not explicitly specified.
template<typename ValueType>
- bool FindCallerRegs(const RegisterValueMap<ValueType> &registers,
- const MemoryRegion &memory,
- RegisterValueMap<ValueType> *caller_registers) const;
+ bool FindCallerRegs(const RegisterValueMap<ValueType>& registers,
+ const MemoryRegion& memory,
+ RegisterValueMap<ValueType>* caller_registers) const;
// Serialize the rules in this object into a string in the format
// of STACK CFI records.
@@ -148,28 +147,28 @@ class CFIRuleParser {
virtual ~Handler() { }
// The input specifies EXPRESSION as the CFA/RA computation rule.
- virtual void CFARule(const string &expression) = 0;
- virtual void RARule(const string &expression) = 0;
+ virtual void CFARule(const string& expression) = 0;
+ virtual void RARule(const string& expression) = 0;
// The input specifies EXPRESSION as the recovery rule for register NAME.
- virtual void RegisterRule(const string &name, const string &expression) = 0;
+ virtual void RegisterRule(const string& name, const string& expression) = 0;
};
// Construct a parser which feeds its results to HANDLER.
- CFIRuleParser(Handler *handler) : handler_(handler) { }
+ CFIRuleParser(Handler* handler) : handler_(handler) { }
// Parse RULE_SET as a set of CFA computation and RA/register
// recovery rules, as appearing in STACK CFI records. Report the
// results of parsing by making the appropriate calls to handler_.
// Return true if parsing was successful, false otherwise.
- bool Parse(const string &rule_set);
+ bool Parse(const string& rule_set);
private:
// Report any accumulated rule to handler_
bool Report();
// The handler to which the parser reports its findings.
- Handler *handler_;
+ Handler* handler_;
// Working data.
string name_, expression_;
@@ -180,15 +179,15 @@ class CFIRuleParser {
class CFIFrameInfoParseHandler: public CFIRuleParser::Handler {
public:
// Populate FRAME_INFO with the results of parsing.
- CFIFrameInfoParseHandler(CFIFrameInfo *frame_info)
+ CFIFrameInfoParseHandler(CFIFrameInfo* frame_info)
: frame_info_(frame_info) { }
- void CFARule(const string &expression);
- void RARule(const string &expression);
- void RegisterRule(const string &name, const string &expression);
+ void CFARule(const string& expression);
+ void RARule(const string& expression);
+ void RegisterRule(const string& name, const string& expression);
private:
- CFIFrameInfo *frame_info_;
+ CFIFrameInfo* frame_info_;
};
// A utility class template for simple 'STACK CFI'-driven stack walkers.
@@ -212,14 +211,14 @@ class SimpleCFIWalker {
// A structure describing one architecture register.
struct RegisterSet {
// The register name, as it appears in STACK CFI rules.
- const char *name;
+ const char* name;
// An alternate name that the register's value might be found
// under in a register value dictionary, or NULL. When generating
// names, prefer NAME to this value. It's common to list ".cfa" as
// an alternative name for the stack pointer, and ".ra" as an
// alternative name for the instruction pointer.
- const char *alternate_name;
+ const char* alternate_name;
// True if the callee is expected to preserve the value of this
// register. If this flag is true for some register R, and the STACK
@@ -240,7 +239,7 @@ class SimpleCFIWalker {
// architecture's register set. REGISTER_MAP is an array of
// RegisterSet structures; MAP_SIZE is the number of elements in the
// array.
- SimpleCFIWalker(const RegisterSet *register_map, size_t map_size)
+ SimpleCFIWalker(const RegisterSet* register_map, size_t map_size)
: register_map_(register_map), map_size_(map_size) { }
// Compute the calling frame's raw context given the callee's raw
@@ -256,15 +255,15 @@ class SimpleCFIWalker {
// fill in CALLER_CONTEXT with the caller's register values, and set
// CALLER_VALIDITY to indicate which registers are valid in
// CALLER_CONTEXT. Return true on success, or false on failure.
- bool FindCallerRegisters(const MemoryRegion &memory,
- const CFIFrameInfo &cfi_frame_info,
- const RawContextType &callee_context,
+ bool FindCallerRegisters(const MemoryRegion& memory,
+ const CFIFrameInfo& cfi_frame_info,
+ const RawContextType& callee_context,
int callee_validity,
- RawContextType *caller_context,
- int *caller_validity) const;
+ RawContextType* caller_context,
+ int* caller_validity) const;
private:
- const RegisterSet *register_map_;
+ const RegisterSet* register_map_;
size_t map_size_;
};
diff --git a/src/processor/cfi_frame_info_unittest.cc b/src/processor/cfi_frame_info_unittest.cc
index 542b2849..85f970a5 100644
--- a/src/processor/cfi_frame_info_unittest.cc
+++ b/src/processor/cfi_frame_info_unittest.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2010, Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -56,10 +55,10 @@ class MockMemoryRegion: public MemoryRegion {
public:
MOCK_CONST_METHOD0(GetBase, uint64_t());
MOCK_CONST_METHOD0(GetSize, uint32_t());
- MOCK_CONST_METHOD2(GetMemoryAtAddress, bool(uint64_t, uint8_t *));
- MOCK_CONST_METHOD2(GetMemoryAtAddress, bool(uint64_t, uint16_t *));
- MOCK_CONST_METHOD2(GetMemoryAtAddress, bool(uint64_t, uint32_t *));
- MOCK_CONST_METHOD2(GetMemoryAtAddress, bool(uint64_t, uint64_t *));
+ MOCK_CONST_METHOD2(GetMemoryAtAddress, bool(uint64_t, uint8_t*));
+ MOCK_CONST_METHOD2(GetMemoryAtAddress, bool(uint64_t, uint16_t*));
+ MOCK_CONST_METHOD2(GetMemoryAtAddress, bool(uint64_t, uint32_t*));
+ MOCK_CONST_METHOD2(GetMemoryAtAddress, bool(uint64_t, uint64_t*));
MOCK_CONST_METHOD0(Print, void());
};
@@ -70,10 +69,10 @@ struct CFIFixture {
void ExpectNoMemoryReferences() {
EXPECT_CALL(memory, GetBase()).Times(0);
EXPECT_CALL(memory, GetSize()).Times(0);
- EXPECT_CALL(memory, GetMemoryAtAddress(_, A<uint8_t *>())).Times(0);
- EXPECT_CALL(memory, GetMemoryAtAddress(_, A<uint16_t *>())).Times(0);
- EXPECT_CALL(memory, GetMemoryAtAddress(_, A<uint32_t *>())).Times(0);
- EXPECT_CALL(memory, GetMemoryAtAddress(_, A<uint64_t *>())).Times(0);
+ EXPECT_CALL(memory, GetMemoryAtAddress(_, A<uint8_t*>())).Times(0);
+ EXPECT_CALL(memory, GetMemoryAtAddress(_, A<uint16_t*>())).Times(0);
+ EXPECT_CALL(memory, GetMemoryAtAddress(_, A<uint32_t*>())).Times(0);
+ EXPECT_CALL(memory, GetMemoryAtAddress(_, A<uint64_t*>())).Times(0);
}
CFIFrameInfo cfi;
@@ -254,8 +253,9 @@ TEST_F(Scope, RegsLackRA) {
cfi.SetCFARule("42740329");
cfi.SetRARule("27045204");
cfi.SetRegisterRule("$r1", ".ra");
- ASSERT_FALSE(cfi.FindCallerRegs<uint64_t>(registers, memory,
- &caller_registers));
+ ASSERT_TRUE(cfi.FindCallerRegs<uint64_t>(registers, memory,
+ &caller_registers));
+ ASSERT_EQ(caller_registers.end(), caller_registers.find("$r1"));
}
// Register rules can see the current frame's register values.
@@ -292,9 +292,9 @@ TEST_F(Scope, SeparateTempsRA) {
class MockCFIRuleParserHandler: public CFIRuleParser::Handler {
public:
- MOCK_METHOD1(CFARule, void(const string &));
- MOCK_METHOD1(RARule, void(const string &));
- MOCK_METHOD2(RegisterRule, void(const string &, const string &));
+ MOCK_METHOD1(CFARule, void(const string&));
+ MOCK_METHOD1(RARule, void(const string&));
+ MOCK_METHOD2(RegisterRule, void(const string&, const string&));
};
// A fixture class for testing CFIRuleParser.
@@ -439,6 +439,7 @@ TEST_F(ParseHandler, RegisterRules) {
handler.RARule("reg-for-ra");
handler.RegisterRule("reg1", "reg-for-reg1");
handler.RegisterRule("reg2", "reg-for-reg2");
+ handler.RegisterRule("reg3", "reg3");
registers["reg-for-cfa"] = 0x268a9a4a3821a797ULL;
registers["reg-for-ra"] = 0x6301b475b8b91c02ULL;
registers["reg-for-reg1"] = 0x06cde8e2ff062481ULL;
@@ -449,6 +450,7 @@ TEST_F(ParseHandler, RegisterRules) {
ASSERT_EQ(0x6301b475b8b91c02ULL, caller_registers[".ra"]);
ASSERT_EQ(0x06cde8e2ff062481ULL, caller_registers["reg1"]);
ASSERT_EQ(0xff0c4f76403173e2ULL, caller_registers["reg2"]);
+ ASSERT_EQ(caller_registers.end(), caller_registers.find("reg3"));
}
struct SimpleCFIWalkerFixture {
@@ -509,12 +511,12 @@ TEST_F(SimpleWalker, Walk) {
// Saved r0.
EXPECT_CALL(memory,
- GetMemoryAtAddress(stack_top, A<uint64_t *>()))
+ GetMemoryAtAddress(stack_top, A<uint64_t*>()))
.WillRepeatedly(DoAll(SetArgumentPointee<1>(0xdc1975eba8602302ULL),
Return(true)));
// Saved return address.
EXPECT_CALL(memory,
- GetMemoryAtAddress(stack_top + 16, A<uint64_t *>()))
+ GetMemoryAtAddress(stack_top + 16, A<uint64_t*>()))
.WillRepeatedly(DoAll(SetArgumentPointee<1>(0xba5ad6d9acce28deULL),
Return(true)));
diff --git a/src/processor/contained_range_map-inl.h b/src/processor/contained_range_map-inl.h
index 4c0ad41f..e085dcb4 100644
--- a/src/processor/contained_range_map-inl.h
+++ b/src/processor/contained_range_map-inl.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2006, Google Inc.
-// All rights reserved.
+// Copyright 2006 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -55,7 +54,7 @@ ContainedRangeMap<AddressType, EntryType>::~ContainedRangeMap() {
template<typename AddressType, typename EntryType>
bool ContainedRangeMap<AddressType, EntryType>::StoreRange(
- const AddressType &base, const AddressType &size, const EntryType &entry) {
+ const AddressType& base, const AddressType& size, const EntryType& entry) {
AddressType high = base + size - 1;
// Check for undersize or overflow.
@@ -84,10 +83,12 @@ bool ContainedRangeMap<AddressType, EntryType>::StoreRange(
// range's, it violates the containment rules, and an attempt to store
// it must fail. iterator_base->first contains the key, which was the
// containing child's high address.
- if (iterator_base->second->base_ == base && iterator_base->first == high) {
+ if (!allow_equal_range_ && iterator_base->second->base_ == base &&
+ iterator_base->first == high) {
// TODO(nealsid): See the TODO above on why this is commented out.
-// BPLOG(INFO) << "StoreRange failed, identical range is already "
-// "present: " << HexString(base) << "+" << HexString(size);
+ // BPLOG(INFO) << "StoreRange failed, identical range is already "
+ // "present: " << HexString(base) << "+" <<
+ // HexString(size);
return false;
}
@@ -125,7 +126,7 @@ bool ContainedRangeMap<AddressType, EntryType>::StoreRange(
// Optimization: if the iterators are equal, no child ranges would be
// moved. Create the new child range with a NULL map to conserve space
// in leaf nodes, of which there will be many.
- AddressToRangeMap *child_map = NULL;
+ AddressToRangeMap* child_map = NULL;
if (iterator_base != iterator_high) {
// The children of this range that are contained by the new range must
@@ -141,15 +142,17 @@ bool ContainedRangeMap<AddressType, EntryType>::StoreRange(
// the new child range contains were formerly children of this range but
// are now this range's grandchildren. Ownership of these is transferred
// to the new child range.
- map_->insert(MapValue(high,
- new ContainedRangeMap(base, entry, child_map)));
+ ContainedRangeMap* new_child =
+ new ContainedRangeMap(base, entry, child_map, allow_equal_range_);
+
+ map_->insert(MapValue(high, new_child));
return true;
}
template<typename AddressType, typename EntryType>
bool ContainedRangeMap<AddressType, EntryType>::RetrieveRange(
- const AddressType &address, EntryType *entry) const {
+ const AddressType& address, EntryType* entry) const {
BPLOG_IF(ERROR, !entry) << "ContainedRangeMap::RetrieveRange requires "
"|entry|";
assert(entry);
@@ -177,6 +180,20 @@ bool ContainedRangeMap<AddressType, EntryType>::RetrieveRange(
return true;
}
+template <typename AddressType, typename EntryType>
+bool ContainedRangeMap<AddressType, EntryType>::RetrieveRanges(
+ const AddressType& address,
+ std::vector<const EntryType*>& entries) const {
+ // If nothing was ever stored, then there's nothing to retrieve.
+ if (!map_)
+ return false;
+ MapIterator iterator = map_->lower_bound(address);
+ if (iterator == map_->end() || address < iterator->second->base_)
+ return false;
+ iterator->second->RetrieveRanges(address, entries);
+ entries.push_back(&iterator->second->entry_);
+ return true;
+}
template<typename AddressType, typename EntryType>
void ContainedRangeMap<AddressType, EntryType>::Clear() {
diff --git a/src/processor/contained_range_map.h b/src/processor/contained_range_map.h
index 1015ae8c..24a3bb41 100644
--- a/src/processor/contained_range_map.h
+++ b/src/processor/contained_range_map.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2006, Google Inc.
-// All rights reserved.
+// Copyright 2006 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -62,6 +61,7 @@
#include <map>
+#include <vector>
namespace google_breakpad {
@@ -75,7 +75,8 @@ class ContainedRangeMap {
// The default constructor creates a ContainedRangeMap with no geometry
// and no entry, and as such is only suitable for the root node of a
// ContainedRangeMap tree.
- ContainedRangeMap() : base_(), entry_(), map_(NULL) {}
+ explicit ContainedRangeMap(bool allow_equal_range = false)
+ : base_(), entry_(), map_(NULL), allow_equal_range_(allow_equal_range) {}
~ContainedRangeMap();
@@ -86,16 +87,21 @@ class ContainedRangeMap {
// grandchildren of this ContainedRangeMap. Returns false for a
// parameter error, or if the ContainedRangeMap hierarchy guarantees
// would be violated.
- bool StoreRange(const AddressType &base,
- const AddressType &size,
- const EntryType &entry);
+ bool StoreRange(const AddressType& base,
+ const AddressType& size,
+ const EntryType& entry);
// Retrieves the most specific (smallest) descendant range encompassing
// the specified address. This method will only return entries held by
// child ranges, and not the entry contained by |this|. This is necessary
// to support a sparsely-populated root range. If no descendant range
// encompasses the address, returns false.
- bool RetrieveRange(const AddressType &address, EntryType *entry) const;
+ bool RetrieveRange(const AddressType& address, EntryType* entries) const;
+
+ // Retrieves the vector of entries encompassing the specified address from the
+ // innermost entry to the outermost entry.
+ bool RetrieveRanges(const AddressType& address,
+ std::vector<const EntryType*>& entries) const;
// Removes all children. Note that Clear only removes descendants,
// leaving the node on which it is called intact. Because the only
@@ -110,7 +116,7 @@ class ContainedRangeMap {
// AddressToRangeMap stores pointers. This makes reparenting simpler in
// StoreRange, because it doesn't need to copy entire objects.
- typedef std::map<AddressType, ContainedRangeMap *> AddressToRangeMap;
+ typedef std::map<AddressType, ContainedRangeMap*> AddressToRangeMap;
typedef typename AddressToRangeMap::const_iterator MapConstIterator;
typedef typename AddressToRangeMap::iterator MapIterator;
typedef typename AddressToRangeMap::value_type MapValue;
@@ -118,9 +124,14 @@ class ContainedRangeMap {
// Creates a new ContainedRangeMap with the specified base address, entry,
// and initial child map, which may be NULL. This is only used internally
// by ContainedRangeMap when it creates a new child.
- ContainedRangeMap(const AddressType &base, const EntryType &entry,
- AddressToRangeMap *map)
- : base_(base), entry_(entry), map_(map) {}
+ ContainedRangeMap(const AddressType& base,
+ const EntryType& entry,
+ AddressToRangeMap* map,
+ bool allow_equal_range)
+ : base_(base),
+ entry_(entry),
+ map_(map),
+ allow_equal_range_(allow_equal_range) {}
// The base address of this range. The high address does not need to
// be stored, because it is used as the key to an object in its parent's
@@ -140,7 +151,13 @@ class ContainedRangeMap {
// The map containing child ranges, keyed by each child range's high
// address. This is a pointer to avoid allocating map structures for
// leaf nodes, where they are not needed.
- AddressToRangeMap *map_;
+ AddressToRangeMap* map_;
+
+ // Whether or not we allow storing an entry into a range that equals to
+ // existing range in the map. Default is false.
+ // If this is true, the newly added range will become a child of existing
+ // innermost range which has same base and size.
+ bool allow_equal_range_;
};
diff --git a/src/processor/contained_range_map_unittest.cc b/src/processor/contained_range_map_unittest.cc
index e5910da0..670bb189 100644
--- a/src/processor/contained_range_map_unittest.cc
+++ b/src/processor/contained_range_map_unittest.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2006, Google Inc.
-// All rights reserved.
+// Copyright 2006 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -51,9 +50,82 @@ namespace {
using google_breakpad::ContainedRangeMap;
+// The first is the querying address, the second is the entries vector result.
+using EntriesTestPair = std::pair<unsigned, std::vector<int>>;
+using EntriesTestPairVec = std::vector<EntriesTestPair>;
+static bool RunTestsWithRetrieveRange(
+ const ContainedRangeMap<unsigned int, int>& crm,
+ const int* test_data,
+ unsigned int test_length) {
+ // Now, do the RetrieveRange tests. This further validates that the
+ // objects were stored properly and that retrieval returns the correct
+ // object.
+ // If GENERATE_TEST_DATA is defined, instead of the retrieval tests, a
+ // new test_data array will be printed. Exercise caution when doing this.
+ // Be sure to verify the results manually!
+#ifdef GENERATE_TEST_DATA
+ printf(" const int test_data[] = {\n");
+#endif // GENERATE_TEST_DATA
-static bool RunTests() {
+ for (unsigned int address = 0; address < test_length; ++address) {
+ int value;
+ if (!crm.RetrieveRange(address, &value))
+ value = 0;
+
+#ifndef GENERATE_TEST_DATA
+ // Don't use ASSERT inside the loop because it won't show the failed
+ // |address|, and the line number will always be the same. That makes
+ // it difficult to figure out which test failed.
+ if (value != test_data[address]) {
+ fprintf(stderr, "FAIL: retrieve %d expected %d observed %d @ %s:%d\n",
+ address, test_data[address], value, __FILE__, __LINE__);
+ return false;
+ }
+#else // !GENERATE_TEST_DATA
+ printf(" %d%c%s // %d\n", value, address == test_high - 1 ? ' ' : ',',
+ value < 10 ? " " : "", address);
+#endif // !GENERATE_TEST_DATA
+ }
+
+#ifdef GENERATE_TEST_DATA
+ printf(" };\n");
+#endif // GENERATE_TEST_DATA
+
+ return true;
+}
+
+static bool RunTestsWithRetrieveRangeVector(
+ const ContainedRangeMap<unsigned int, int>& crm,
+ const EntriesTestPairVec& entries_tests) {
+ for (const EntriesTestPair& entries_test : entries_tests) {
+ std::vector<const int*> entries;
+ crm.RetrieveRanges(entries_test.first, entries);
+ if (entries.size() != entries_test.second.size()) {
+ fprintf(stderr,
+ "FAIL: retrieving entries at address %u has size %zu "
+ "expected to have size %zu "
+ "@ %s: %d\n",
+ entries_test.first, entries.size(), entries_test.second.size(),
+ __FILE__, __LINE__);
+ return false;
+ }
+ for (size_t i = 0; i < entries.size(); ++i) {
+ if (*entries[i] != entries_test.second[i]) {
+ fprintf(stderr,
+ "FAIL: retrieving entries at address %u entries[%zu] is %d "
+ "expected %d"
+ "@ %s: %d\n",
+ entries_test.first, i, *entries[i], entries_test.second[i],
+ __FILE__, __LINE__);
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+static bool RunTestsWithNoEqualRange() {
ContainedRangeMap<unsigned int, int> crm;
// First, do the StoreRange tests. This validates the containment
@@ -211,52 +283,96 @@ static bool RunTests() {
0, // 98
0 // 99
};
- unsigned int test_high = sizeof(test_data) / sizeof(int);
+ unsigned int test_length = sizeof(test_data) / sizeof(int);
+ return RunTestsWithRetrieveRange(crm, test_data, test_length);
+}
- // Now, do the RetrieveRange tests. This further validates that the
- // objects were stored properly and that retrieval returns the correct
- // object.
- // If GENERATE_TEST_DATA is defined, instead of the retrieval tests, a
- // new test_data array will be printed. Exercise caution when doing this.
- // Be sure to verify the results manually!
-#ifdef GENERATE_TEST_DATA
- printf(" const int test_data[] = {\n");
-#endif // GENERATE_TEST_DATA
+static bool RunTestsWithEqualRange() {
+ ContainedRangeMap<unsigned int, int> crm(true);
- for (unsigned int address = 0; address < test_high; ++address) {
- int value;
- if (!crm.RetrieveRange(address, &value))
- value = 0;
+ // First, do the StoreRange tests. This validates the containment
+ // rules.
+ ASSERT_TRUE (crm.StoreRange(1, 3, 1));
+ ASSERT_TRUE (crm.StoreRange(1, 3, 2)); // exactly equal to 1
+ ASSERT_TRUE (crm.StoreRange(1, 3, 3)); // exactly equal to 1, 2
+ ASSERT_TRUE (crm.StoreRange(1, 3, 4)); // exactly equal to 1, 2, 3
+ ASSERT_FALSE(crm.StoreRange(0, 3, 5)); // partial overlap.
+ ASSERT_FALSE(crm.StoreRange(2, 3, 6)); // partial overlap.
-#ifndef GENERATE_TEST_DATA
- // Don't use ASSERT inside the loop because it won't show the failed
- // |address|, and the line number will always be the same. That makes
- // it difficult to figure out which test failed.
- if (value != test_data[address]) {
- fprintf(stderr, "FAIL: retrieve %d expected %d observed %d @ %s:%d\n",
- address, test_data[address], value, __FILE__, __LINE__);
- return false;
- }
-#else // !GENERATE_TEST_DATA
- printf(" %d%c%s // %d\n", value,
- address == test_high - 1 ? ' ' : ',',
- value < 10 ? " " : "",
- address);
-#endif // !GENERATE_TEST_DATA
- }
+ ASSERT_TRUE (crm.StoreRange(5, 3, 7));
+ ASSERT_TRUE (crm.StoreRange(5, 3, 8)); // exactly equal to 7
+ ASSERT_TRUE (crm.StoreRange(5, 3, 9)); // exactly equal to 7, 8
+ ASSERT_TRUE (crm.StoreRange(5, 4, 10)); // encompasses 7, 8, 9
+ ASSERT_TRUE (crm.StoreRange(5, 5, 11)); // encompasses 7, 8, 9, 10
-#ifdef GENERATE_TEST_DATA
- printf(" };\n");
-#endif // GENERATE_TEST_DATA
+ ASSERT_TRUE (crm.StoreRange(10, 3, 12));
+ ASSERT_TRUE (crm.StoreRange(10, 3, 13)); // exactly equal to 12
+ ASSERT_TRUE (crm.StoreRange(11, 2, 14)); // encompasses by 12
+ ASSERT_TRUE (crm.StoreRange(11, 1, 15)); // encompasses by 12, 13
- return true;
+ ASSERT_TRUE (crm.StoreRange(14, 3, 16));
+ ASSERT_TRUE (crm.StoreRange(14, 3, 17)); // exactly equal to 14
+ ASSERT_TRUE (crm.StoreRange(14, 1, 18)); // encompasses by 14, 15
+ ASSERT_TRUE (crm.StoreRange(14, 2, 19)); // encompasses by 14, 15 and encompasses 16
+ ASSERT_TRUE (crm.StoreRange(14, 1, 20)); // exactly equal to 18
+ ASSERT_TRUE (crm.StoreRange(14, 2, 21)); // exactly equal to 19
+
+ // Each element in test_data contains the expected result when calling
+ // RetrieveRange on an address.
+ const int test_data[] = {
+ 0, // 0
+ 4, // 1
+ 4, // 2
+ 4, // 3
+ 0, // 4
+ 9, // 5
+ 9, // 6
+ 9, // 7
+ 10, // 8
+ 11, // 9
+ 13, // 10
+ 15, // 11
+ 14, // 12
+ 0, // 13
+ 20, // 14
+ 21, // 15
+ 17, // 16
+ 0, // 17
+ };
+ unsigned int test_length = sizeof(test_data) / sizeof(int);
+ EntriesTestPairVec entries_tests = {
+ {0, {}},
+ {1, {4, 3, 2, 1}},
+ {2, {4, 3, 2, 1}},
+ {3, {4, 3, 2, 1}},
+ {4, {}},
+ {5, {9, 8, 7, 10, 11}},
+ {6, {9, 8, 7, 10, 11}},
+ {7, {9, 8, 7, 10, 11}},
+ {8, {10, 11}},
+ {9, {11}},
+ {10, {13, 12}},
+ {11, {15, 14, 13, 12}},
+ {12, {14, 13, 12}},
+ {13, {}},
+ {14, {20, 18, 21, 19, 17, 16}},
+ {15, {21, 19, 17, 16}},
+ {16, {17, 16}},
+ {17, {}},
+ };
+ return RunTestsWithRetrieveRange(crm, test_data, test_length) &&
+ RunTestsWithRetrieveRangeVector(crm, entries_tests);
+}
+
+static bool RunTests() {
+ return RunTestsWithNoEqualRange() && RunTestsWithEqualRange();
}
} // namespace
-int main(int argc, char **argv) {
+int main(int argc, char** argv) {
BPLOG_INIT(&argc, &argv);
return RunTests() ? 0 : 1;
diff --git a/src/processor/convert_old_arm64_context.cc b/src/processor/convert_old_arm64_context.cc
index d4b749e7..8347064a 100644
--- a/src/processor/convert_old_arm64_context.cc
+++ b/src/processor/convert_old_arm64_context.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2018, Google Inc.
-// All rights reserved.
+// Copyright 2018 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/processor/convert_old_arm64_context.h b/src/processor/convert_old_arm64_context.h
index 8c0dfe90..241b9259 100644
--- a/src/processor/convert_old_arm64_context.h
+++ b/src/processor/convert_old_arm64_context.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2018, Google Inc.
-// All rights reserved.
+// Copyright 2018 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/processor/disassembler_objdump.cc b/src/processor/disassembler_objdump.cc
new file mode 100644
index 00000000..dfe10d58
--- /dev/null
+++ b/src/processor/disassembler_objdump.cc
@@ -0,0 +1,520 @@
+// Copyright (c) 2022, Google LLC
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google LLC nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// disassembler_objdump.: Disassembler that invokes objdump for disassembly.
+//
+// Author: Mark Brand
+
+#include "processor/disassembler_objdump.h"
+
+#ifdef __linux__
+#include <unistd.h>
+#include <fstream>
+#include <iostream>
+#include <iterator>
+#include <regex>
+#include <sstream>
+#include <vector>
+
+#include "processor/logging.h"
+
+namespace google_breakpad {
+namespace {
+const size_t kMaxX86InstructionLength = 15;
+
+// Small RAII wrapper for temporary files.
+//
+// Example:
+// ScopedTmpFile tmp("/tmp/tmpfile-XXXX");
+// if (tmp.Create()) {
+// std::cerr << tmp.path() << std::endl;
+// }
+class ScopedTmpFile {
+ public:
+ // Initialize the ScopedTmpFile object - this does not create the temporary
+ // file yet.
+ ScopedTmpFile(const char* path_format);
+ ~ScopedTmpFile();
+
+ // Creates the temporary file, returns true on success.
+ bool Create();
+
+ // Writes bytes to the temporary file, returns true on success.
+ bool Write(const uint8_t* bytes, unsigned int bytes_len);
+
+ // Returns the path of the temporary file.
+ string path() const { return path_; }
+
+ private:
+ int fd_;
+ string path_;
+};
+
+ScopedTmpFile::ScopedTmpFile(const char* path_format) : path_(path_format) {}
+
+ScopedTmpFile::~ScopedTmpFile() {
+ if (fd_) {
+ close(fd_);
+ unlink(path_.c_str());
+ }
+}
+
+bool ScopedTmpFile::Create() {
+ fd_ = mkstemp(path_.data());
+ if (fd_ < 0) {
+ unlink(path_.c_str());
+ fd_ = 0;
+ path_ = "";
+ return false;
+ }
+
+ return true;
+}
+
+bool ScopedTmpFile::Write(const uint8_t* bytes, unsigned int bytes_len) {
+ if (fd_) {
+ do {
+ ssize_t result = write(fd_, bytes, bytes_len);
+ if (result < 0) {
+ break;
+ }
+
+ bytes += result;
+ bytes_len -= result;
+ } while (bytes_len);
+ }
+
+ return bytes_len == 0;
+}
+
+bool IsInstructionPrefix(const string& token) {
+ if (token == "lock" || token == "rep" || token == "repz" ||
+ token == "repnz") {
+ return true;
+ }
+ return false;
+}
+
+bool IsOperandSize(const string& token) {
+ if (token == "BYTE" || token == "WORD" || token == "DWORD" ||
+ token == "QWORD" || token == "PTR") {
+ return true;
+ }
+ return false;
+}
+
+bool GetSegmentAddressX86(const DumpContext& context, string segment_name,
+ uint64_t& address) {
+ if (segment_name == "ds") {
+ address = context.GetContextX86()->ds;
+ } else if (segment_name == "es") {
+ address = context.GetContextX86()->es;
+ } else if (segment_name == "fs") {
+ address = context.GetContextX86()->fs;
+ } else if (segment_name == "gs") {
+ address = context.GetContextX86()->gs;
+ } else {
+ BPLOG(ERROR) << "Unsupported segment register: " << segment_name;
+ return false;
+ }
+
+ return true;
+}
+
+bool GetSegmentAddressAMD64(const DumpContext& context, string segment_name,
+ uint64_t& address) {
+ if (segment_name == "ds") {
+ address = 0;
+ } else if (segment_name == "es") {
+ address = 0;
+ } else {
+ BPLOG(ERROR) << "Unsupported segment register: " << segment_name;
+ return false;
+ }
+
+ return true;
+}
+
+bool GetSegmentAddress(const DumpContext& context, string segment_name,
+ uint64_t& address) {
+ if (context.GetContextCPU() == MD_CONTEXT_X86) {
+ return GetSegmentAddressX86(context, segment_name, address);
+ } else if (context.GetContextCPU() == MD_CONTEXT_AMD64) {
+ return GetSegmentAddressAMD64(context, segment_name, address);
+ } else {
+ BPLOG(ERROR) << "Unsupported architecture for GetSegmentAddress\n";
+ return false;
+ }
+}
+
+bool GetRegisterValueX86(const DumpContext& context, string register_name,
+ uint64_t& value) {
+ if (register_name == "eax") {
+ value = context.GetContextX86()->eax;
+ } else if (register_name == "ebx") {
+ value = context.GetContextX86()->ebx;
+ } else if (register_name == "ecx") {
+ value = context.GetContextX86()->ecx;
+ } else if (register_name == "edx") {
+ value = context.GetContextX86()->edx;
+ } else if (register_name == "edi") {
+ value = context.GetContextX86()->edi;
+ } else if (register_name == "esi") {
+ value = context.GetContextX86()->esi;
+ } else if (register_name == "ebp") {
+ value = context.GetContextX86()->ebp;
+ } else if (register_name == "esp") {
+ value = context.GetContextX86()->esp;
+ } else if (register_name == "eip") {
+ value = context.GetContextX86()->eip;
+ } else {
+ BPLOG(ERROR) << "Unsupported register: " << register_name;
+ return false;
+ }
+
+ return true;
+}
+
+bool GetRegisterValueAMD64(const DumpContext& context, string register_name,
+ uint64_t& value) {
+ if (register_name == "rax") {
+ value = context.GetContextAMD64()->rax;
+ } else if (register_name == "rbx") {
+ value = context.GetContextAMD64()->rbx;
+ } else if (register_name == "rcx") {
+ value = context.GetContextAMD64()->rcx;
+ } else if (register_name == "rdx") {
+ value = context.GetContextAMD64()->rdx;
+ } else if (register_name == "rdi") {
+ value = context.GetContextAMD64()->rdi;
+ } else if (register_name == "rsi") {
+ value = context.GetContextAMD64()->rsi;
+ } else if (register_name == "rbp") {
+ value = context.GetContextAMD64()->rbp;
+ } else if (register_name == "rsp") {
+ value = context.GetContextAMD64()->rsp;
+ } else if (register_name == "r8") {
+ value = context.GetContextAMD64()->r8;
+ } else if (register_name == "r9") {
+ value = context.GetContextAMD64()->r9;
+ } else if (register_name == "r10") {
+ value = context.GetContextAMD64()->r10;
+ } else if (register_name == "r11") {
+ value = context.GetContextAMD64()->r11;
+ } else if (register_name == "r12") {
+ value = context.GetContextAMD64()->r12;
+ } else if (register_name == "r13") {
+ value = context.GetContextAMD64()->r13;
+ } else if (register_name == "r14") {
+ value = context.GetContextAMD64()->r14;
+ } else if (register_name == "r15") {
+ value = context.GetContextAMD64()->r15;
+ } else if (register_name == "rip") {
+ value = context.GetContextAMD64()->rip;
+ } else {
+ BPLOG(ERROR) << "Unsupported register: " << register_name;
+ return false;
+ }
+
+ return true;
+}
+
+// Lookup the value of `register_name` in `context`, store it into `value` on
+// success.
+// Support for non-full-size registers not implemented, since we're only using
+// this to evaluate address expressions.
+bool GetRegisterValue(const DumpContext& context, string register_name,
+ uint64_t& value) {
+ if (context.GetContextCPU() == MD_CONTEXT_X86) {
+ return GetRegisterValueX86(context, register_name, value);
+ } else if (context.GetContextCPU() == MD_CONTEXT_AMD64) {
+ return GetRegisterValueAMD64(context, register_name, value);
+ } else {
+ BPLOG(ERROR) << "Unsupported architecture for GetRegisterValue\n";
+ return false;
+ }
+}
+} // namespace
+
+// static
+bool DisassemblerObjdump::DisassembleInstruction(uint32_t cpu,
+ const uint8_t* raw_bytes,
+ unsigned int raw_bytes_len,
+ string& instruction) {
+ // Always initialize outputs
+ instruction = "";
+
+ if (!raw_bytes || raw_bytes_len == 0) {
+ // There's no need to perform any operation in this case, as there's
+ // clearly no instruction there.
+ return false;
+ }
+
+ string architecture;
+ if (cpu == MD_CONTEXT_X86) {
+ architecture = "i386";
+ } else if (cpu == MD_CONTEXT_AMD64) {
+ architecture = "i386:x86-64";
+ } else {
+ BPLOG(ERROR) << "Unsupported architecture.";
+ return false;
+ }
+
+ // Create two temporary files, one for the raw instruction bytes to pass to
+ // objdump, and one for the output, and write the bytes to the input file.
+ ScopedTmpFile raw_bytes_file("/tmp/breakpad_mem_region-raw_bytes-XXXXXX");
+ ScopedTmpFile disassembly_file("/tmp/breakpad_mem_region-disassembly-XXXXXX");
+ if (!raw_bytes_file.Create() || !disassembly_file.Create() ||
+ !raw_bytes_file.Write(raw_bytes, raw_bytes_len)) {
+ BPLOG(ERROR) << "Failed creating temporary files.";
+ return false;
+ }
+
+ char cmd[1024] = {0};
+ snprintf(cmd, 1024,
+ "objdump -D --no-show-raw-insn -b binary -M intel -m %s %s > %s",
+ architecture.c_str(), raw_bytes_file.path().c_str(),
+ disassembly_file.path().c_str());
+ if (system(cmd)) {
+ BPLOG(ERROR) << "Failed to call objdump.";
+ return false;
+ }
+
+ // Pipe each output line into the string until the string contains the first
+ // instruction from objdump.
+ std::ifstream objdump_stream(disassembly_file.path());
+
+ // Match the instruction line, from:
+ // 0: lock cmpxchg DWORD PTR [esi+0x10],eax
+ // extract the string "lock cmpxchg DWORD PTR [esi+0x10],eax"
+ std::regex instruction_regex(
+ "^\\s+[0-9a-f]+:\\s+" // " 0:"
+ "((?:\\s*\\S*)+)$"); // "lock cmpxchg..."
+
+ std::string line;
+ std::smatch match;
+ do {
+ if (!getline(objdump_stream, line)) {
+ BPLOG(INFO) << "Failed to find instruction in objdump output.";
+ return false;
+ }
+ } while (!std::regex_match(line, match, instruction_regex));
+
+ instruction = match[1].str();
+
+ return true;
+}
+
+// static
+bool DisassemblerObjdump::TokenizeInstruction(const string& instruction,
+ string& operation, string& dest,
+ string& src) {
+ // Always initialize outputs.
+ operation = "";
+ dest = "";
+ src = "";
+
+ // Split the instruction into tokens by either whitespace or comma.
+ std::regex token_regex("((?:[^\\s,]+)|,)(?:\\s)*");
+ std::sregex_iterator tokens_begin(instruction.begin(), instruction.end(),
+ token_regex);
+
+ bool found_comma = false;
+ for (auto tokens_iter = tokens_begin; tokens_iter != std::sregex_iterator();
+ ++tokens_iter) {
+ auto token = (*tokens_iter)[1].str();
+ if (operation.size() == 0) {
+ if (IsInstructionPrefix(token))
+ continue;
+ operation = token;
+ } else if (dest.size() == 0) {
+ if (IsOperandSize(token))
+ continue;
+ dest = token;
+ } else if (!found_comma) {
+ if (token == ",") {
+ found_comma = true;
+ } else {
+ BPLOG(ERROR) << "Failed to parse operands from objdump output, expected"
+ " comma but found \""
+ << token << "\"";
+ return false;
+ }
+ } else if (src.size() == 0) {
+ if (IsOperandSize(token))
+ continue;
+ src = token;
+ } else {
+ if (token == ",") {
+ BPLOG(ERROR) << "Failed to parse operands from objdump output, found "
+ "unexpected comma after last operand.";
+ return false;
+ } else {
+ // We just ignore other junk after the last operand unless it's a
+ // comma, which would indicate we're probably still in the middle
+ // of the operands and something has gone wrong
+ }
+ }
+ }
+
+ if (found_comma && src.size() == 0) {
+ BPLOG(ERROR) << "Failed to parse operands from objdump output, found comma "
+ "but no src operand.";
+ return false;
+ }
+
+ return true;
+}
+
+// static
+bool DisassemblerObjdump::CalculateAddress(const DumpContext& context,
+ const string& expression,
+ uint64_t& address) {
+ address = 0;
+
+ // Extract the components of the expression.
+ // fs:[esi+edi*4+0x80] -> ["fs", "esi", "edi", "4", "-", "0x80"]
+ std::regex expression_regex(
+ "^(?:(\\ws):)?" // "fs:"
+ "\\[(\\w+)" // "[esi"
+ "(?:\\+(\\w+)(?:\\*(\\d+)))?" // "+edi*4"
+ "(?:([\\+-])(0x[0-9a-f]+))?" // "-0x80"
+ "\\]$"); // "]"
+
+ std::smatch match;
+ if (!std::regex_match(expression, match, expression_regex) ||
+ match.size() != 7) {
+ return false;
+ }
+
+ string segment_name = match[1].str();
+ string register_name = match[2].str();
+ string index_name = match[3].str();
+ string index_stride = match[4].str();
+ string offset_sign = match[5].str();
+ string offset = match[6].str();
+
+ uint64_t segment_address = 0;
+ uint64_t register_value = 0;
+ uint64_t index_value = 0;
+ uint64_t index_stride_value = 1;
+ uint64_t offset_value = 0;
+
+ if (segment_name.size() &&
+ !GetSegmentAddress(context, segment_name, segment_address)) {
+ return false;
+ }
+
+ if (!GetRegisterValue(context, register_name, register_value)) {
+ return false;
+ }
+
+ if (index_name.size() &&
+ !GetRegisterValue(context, index_name, index_value)) {
+ return false;
+ }
+
+ if (index_stride.size()) {
+ index_stride_value = strtoull(index_stride.c_str(), nullptr, 0);
+ }
+
+ if (offset.size()) {
+ offset_value = strtoull(offset.c_str(), nullptr, 0);
+ }
+
+ address =
+ segment_address + register_value + (index_value * index_stride_value);
+ if (offset_sign == "+") {
+ address += offset_value;
+ } else if (offset_sign == "-") {
+ address -= offset_value;
+ }
+
+ return true;
+}
+
+DisassemblerObjdump::DisassemblerObjdump(const uint32_t cpu,
+ const MemoryRegion* memory_region,
+ uint64_t address) {
+ if (address < memory_region->GetBase() ||
+ memory_region->GetBase() + memory_region->GetSize() <= address) {
+ return;
+ }
+
+ uint8_t ip_bytes[kMaxX86InstructionLength] = {0};
+ size_t ip_bytes_length;
+ for (ip_bytes_length = 0; ip_bytes_length < kMaxX86InstructionLength;
+ ++ip_bytes_length) {
+ // We have to read byte-by-byte here, since we still want to try and
+ // disassemble an instruction even if we don't have enough bytes.
+ if (!memory_region->GetMemoryAtAddress(address + ip_bytes_length,
+ &ip_bytes[ip_bytes_length])) {
+ break;
+ }
+ }
+
+ string instruction;
+ if (!DisassembleInstruction(cpu, ip_bytes, kMaxX86InstructionLength,
+ instruction)) {
+ return;
+ }
+
+ if (!TokenizeInstruction(instruction, operation_, dest_, src_)) {
+ return;
+ }
+}
+
+bool DisassemblerObjdump::CalculateSrcAddress(const DumpContext& context,
+ uint64_t& address) {
+ return CalculateAddress(context, src_, address);
+}
+
+bool DisassemblerObjdump::CalculateDestAddress(const DumpContext& context,
+ uint64_t& address) {
+ return CalculateAddress(context, dest_, address);
+}
+} // namespace google_breakpad
+
+#else // __linux__
+namespace google_breakpad {
+DisassemblerObjdump::DisassemblerObjdump(const uint32_t cpu,
+ const MemoryRegion* memory_region,
+ uint64_t address) {}
+
+bool DisassemblerObjdump::CalculateSrcAddress(const DumpContext& context,
+ uint64_t& address) {
+ return false;
+}
+
+bool DisassemblerObjdump::CalculateDestAddress(const DumpContext& context,
+ uint64_t& address) {
+ return false;
+}
+} // namespace google_breakpad
+
+#endif // __linux__
diff --git a/src/processor/disassembler_objdump.h b/src/processor/disassembler_objdump.h
new file mode 100644
index 00000000..7db1e111
--- /dev/null
+++ b/src/processor/disassembler_objdump.h
@@ -0,0 +1,142 @@
+// Copyright (c) 2022, Google LLC
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google LLC nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// disassembler_objdump.h: Disassembler that invokes objdump for disassembly.
+//
+// Author: Mark Brand
+
+#ifndef GOOGLE_BREAKPAD_PROCESSOR_DISASSEMBLER_OBJDUMP_H_
+#define GOOGLE_BREAKPAD_PROCESSOR_DISASSEMBLER_OBJDUMP_H_
+
+#include <string>
+
+#include "common/using_std_string.h"
+#include "google_breakpad/common/breakpad_types.h"
+#include "google_breakpad/processor/dump_context.h"
+#include "google_breakpad/processor/memory_region.h"
+
+namespace google_breakpad {
+
+// Uses objdump to disassemble a single instruction.
+//
+// Currently supports disassembly for x86 and x86_64 on linux hosts only; on
+// unsupported platform or for unsupported architectures disassembly will fail.
+//
+// If disassembly is successful, then this allows extracting the instruction
+// opcode, source and destination operands, and computing the source and
+// destination addresses for instructions that operate on memory.
+//
+// Example:
+// DisassemblerObjdump disassembler(context->GetContextCPU(), memory_region,
+// instruction_ptr);
+// if (disassembler.IsValid()) {
+// uint64_t src_address = 0;
+// std::cerr << disassembler.operation() << " " << disassembler.src()
+// << ", " << disassembler.dest() << std::endl;
+// if (disassembler.CalculateSrcAddress(*context, src_address)) {
+// std::cerr << "[src_address = " << std::hex << src_address << "]\n";
+// }
+// }
+class DisassemblerObjdump {
+ public:
+ // Construct an ObjdumpDisassembler for the provided `cpu` type, where this is
+ // one of MD_CONTEXT_X86 or MD_CONTEXT_AMD64. Provided that `address` is
+ // within `memory_region`, and the memory referenced is a valid instruction,
+ // this will then be initialized with the disassembly for that instruction.
+ DisassemblerObjdump(uint32_t cpu,
+ const MemoryRegion* memory_region,
+ uint64_t address);
+ ~DisassemblerObjdump() = default;
+
+ // If the source operand of the instruction is a memory operand, compute the
+ // address referred to by the operand, and store this in `address`. On success
+ // returns true, otherwise (if computation fails, or if the source operand is
+ // not a memory operand) returns false and sets `address` to 0.
+ bool CalculateSrcAddress(const DumpContext& context, uint64_t& address);
+
+ // If the destination operand of the instruction is a memory operand, compute
+ // the address referred to by the operand, and store this in `address`. On
+ // success returns true, otherwise (if computation fails, or if the source
+ // operand is not a memory operand) returns false and sets `address` to 0.
+ bool CalculateDestAddress(const DumpContext& context, uint64_t& address);
+
+ // If the instruction was disassembled successfully, this will be true.
+ bool IsValid() const { return operation_.size() != 0; }
+
+ // Returns the operation part of the disassembly, without any prefixes:
+ // "pop" eax
+ // lock "xchg" eax, edx
+ const string& operation() const { return operation_; }
+
+ // Returns the destination operand of the disassembly, without memory operand
+ // size prefixes:
+ // mov DWORD PTR "[rax + 16]", edx
+ const string& dest() const { return dest_; }
+
+ // Returns the source operand of the disassembly, without memory operand
+ // size prefixes:
+ // mov rax, QWORD PTR "[rdx]"
+ const string& src() const { return src_; }
+
+ private:
+ friend class DisassemblerObjdumpForTest;
+
+ // Writes out the provided `raw_bytes` to a temporary file, and executes objdump
+ // to disassemble according to `cpu`, which must be either MD_CONTEXT_X86 or
+ // MD_CONTEXT_AMD64. Once objdump has completed, parses out the instruction
+ // string from the first instruction in the output and stores it in
+ // `instruction`.
+ static bool DisassembleInstruction(uint32_t cpu, const uint8_t* raw_bytes,
+ unsigned int raw_bytes_len,
+ string& instruction);
+
+ // Splits an `instruction` into three parts, the "main" `operation` and
+ // the `dest` and `src` operands.
+ // Example:
+ // instruction = "lock cmpxchg QWORD PTR [rdi], rsi"
+ // operation = "cmpxchg", dest = "[rdi]", src = "rsi"
+ static bool TokenizeInstruction(const string& instruction, string& operation,
+ string& dest, string& src);
+
+ // Compute the address referenced by `expression` in `context`.
+ // Supports memory operands in the form
+ // (segment:)[base_reg(+index_reg*index_stride)(+-offset)]
+ // Returns false if evaluation fails, or if the operand is not a supported
+ // memory operand.
+ static bool CalculateAddress(const DumpContext& context,
+ const string& expression,
+ uint64_t& address);
+
+ // The parsed components of the disassembly for the instruction.
+ string operation_ = "";
+ string dest_ = "";
+ string src_ = "";
+};
+} // namespace google_breakpad
+
+#endif // GOOGLE_BREAKPAD_PROCESSOR_DISASSEMBLER_OBJDUMP_H_ \ No newline at end of file
diff --git a/src/processor/disassembler_objdump_unittest.cc b/src/processor/disassembler_objdump_unittest.cc
new file mode 100644
index 00000000..4b4ce6c3
--- /dev/null
+++ b/src/processor/disassembler_objdump_unittest.cc
@@ -0,0 +1,464 @@
+// Copyright (c) 2022, Google LLC
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google LLC nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <unistd.h>
+#include <vector>
+
+#include "breakpad_googletest_includes.h"
+
+#include "google_breakpad/common/breakpad_types.h"
+#include "google_breakpad/common/minidump_cpu_amd64.h"
+#include "google_breakpad/common/minidump_cpu_x86.h"
+#include "google_breakpad/processor/dump_context.h"
+#include "google_breakpad/processor/memory_region.h"
+#include "processor/disassembler_objdump.h"
+
+namespace google_breakpad {
+class DisassemblerObjdumpForTest : public DisassemblerObjdump {
+ public:
+ using DisassemblerObjdump::CalculateAddress;
+ using DisassemblerObjdump::DisassembleInstruction;
+ using DisassemblerObjdump::TokenizeInstruction;
+};
+
+class TestMemoryRegion : public MemoryRegion {
+ public:
+ TestMemoryRegion(uint64_t base, std::vector<uint8_t> bytes);
+ ~TestMemoryRegion() override = default;
+
+ uint64_t GetBase() const override;
+ uint32_t GetSize() const override;
+
+ bool GetMemoryAtAddress(uint64_t address, uint8_t* value) const override;
+ bool GetMemoryAtAddress(uint64_t address, uint16_t* value) const override;
+ bool GetMemoryAtAddress(uint64_t address, uint32_t* value) const override;
+ bool GetMemoryAtAddress(uint64_t address, uint64_t* value) const override;
+
+ void Print() const override;
+
+ private:
+ uint64_t base_;
+ std::vector<uint8_t> bytes_;
+};
+
+TestMemoryRegion::TestMemoryRegion(uint64_t address, std::vector<uint8_t> bytes)
+ : base_(address), bytes_(bytes) {}
+
+uint64_t TestMemoryRegion::GetBase() const {
+ return base_;
+}
+
+uint32_t TestMemoryRegion::GetSize() const {
+ return static_cast<uint32_t>(bytes_.size());
+}
+
+bool TestMemoryRegion::GetMemoryAtAddress(uint64_t address,
+ uint8_t* value) const {
+ if (address < GetBase() ||
+ address + sizeof(uint8_t) > GetBase() + GetSize()) {
+ return false;
+ }
+
+ memcpy(value, &bytes_[address - GetBase()], sizeof(uint8_t));
+ return true;
+}
+
+// We don't use the following functions, so no need to implement.
+bool TestMemoryRegion::GetMemoryAtAddress(uint64_t address,
+ uint16_t* value) const {
+ return false;
+}
+
+bool TestMemoryRegion::GetMemoryAtAddress(uint64_t address,
+ uint32_t* value) const {
+ return false;
+}
+
+bool TestMemoryRegion::GetMemoryAtAddress(uint64_t address,
+ uint64_t* value) const {
+ return false;
+}
+
+void TestMemoryRegion::Print() const {}
+
+const uint32_t kX86TestDs = 0x01000000;
+const uint32_t kX86TestEs = 0x02000000;
+const uint32_t kX86TestFs = 0x03000000;
+const uint32_t kX86TestGs = 0x04000000;
+const uint32_t kX86TestEax = 0x00010101;
+const uint32_t kX86TestEbx = 0x00020202;
+const uint32_t kX86TestEcx = 0x00030303;
+const uint32_t kX86TestEdx = 0x00040404;
+const uint32_t kX86TestEsi = 0x00050505;
+const uint32_t kX86TestEdi = 0x00060606;
+const uint32_t kX86TestEsp = 0x00070707;
+const uint32_t kX86TestEbp = 0x00080808;
+const uint32_t kX86TestEip = 0x23230000;
+
+const uint64_t kAMD64TestRax = 0x0000010101010101ul;
+const uint64_t kAMD64TestRbx = 0x0000020202020202ul;
+const uint64_t kAMD64TestRcx = 0x0000030303030303ul;
+const uint64_t kAMD64TestRdx = 0x0000040404040404ul;
+const uint64_t kAMD64TestRsi = 0x0000050505050505ul;
+const uint64_t kAMD64TestRdi = 0x0000060606060606ul;
+const uint64_t kAMD64TestRsp = 0x0000070707070707ul;
+const uint64_t kAMD64TestRbp = 0x0000080808080808ul;
+const uint64_t kAMD64TestR8 = 0x0000090909090909ul;
+const uint64_t kAMD64TestR9 = 0x00000a0a0a0a0a0aul;
+const uint64_t kAMD64TestR10 = 0x00000b0b0b0b0b0bul;
+const uint64_t kAMD64TestR11 = 0x00000c0c0c0c0c0cul;
+const uint64_t kAMD64TestR12 = 0x00000d0d0d0d0d0dul;
+const uint64_t kAMD64TestR13 = 0x00000e0e0e0e0e0eul;
+const uint64_t kAMD64TestR14 = 0x00000f0f0f0f0f0ful;
+const uint64_t kAMD64TestR15 = 0x0000001010101010ul;
+const uint64_t kAMD64TestRip = 0x0000000023230000ul;
+
+class TestDumpContext : public DumpContext {
+ public:
+ TestDumpContext(bool x86_64 = false);
+ ~TestDumpContext() override;
+};
+
+TestDumpContext::TestDumpContext(bool x86_64) {
+ if (!x86_64) {
+ MDRawContextX86* raw_context = new MDRawContextX86();
+ memset(raw_context, 0, sizeof(*raw_context));
+
+ raw_context->context_flags = MD_CONTEXT_X86_FULL;
+
+ raw_context->ds = kX86TestDs;
+ raw_context->es = kX86TestEs;
+ raw_context->fs = kX86TestFs;
+ raw_context->gs = kX86TestGs;
+ raw_context->eax = kX86TestEax;
+ raw_context->ebx = kX86TestEbx;
+ raw_context->ecx = kX86TestEcx;
+ raw_context->edx = kX86TestEdx;
+ raw_context->esi = kX86TestEsi;
+ raw_context->edi = kX86TestEdi;
+ raw_context->esp = kX86TestEsp;
+ raw_context->ebp = kX86TestEbp;
+ raw_context->eip = kX86TestEip;
+
+ SetContextFlags(raw_context->context_flags);
+ SetContextX86(raw_context);
+ this->valid_ = true;
+ } else {
+ MDRawContextAMD64* raw_context = new MDRawContextAMD64();
+ memset(raw_context, 0, sizeof(*raw_context));
+
+ raw_context->context_flags = MD_CONTEXT_AMD64_FULL;
+
+ raw_context->rax = kAMD64TestRax;
+ raw_context->rbx = kAMD64TestRbx;
+ raw_context->rcx = kAMD64TestRcx;
+ raw_context->rdx = kAMD64TestRdx;
+ raw_context->rsi = kAMD64TestRsi;
+ raw_context->rdi = kAMD64TestRdi;
+ raw_context->rsp = kAMD64TestRsp;
+ raw_context->rbp = kAMD64TestRbp;
+ raw_context->r8 = kAMD64TestR8;
+ raw_context->r9 = kAMD64TestR9;
+ raw_context->r10 = kAMD64TestR10;
+ raw_context->r11 = kAMD64TestR11;
+ raw_context->r12 = kAMD64TestR12;
+ raw_context->r13 = kAMD64TestR13;
+ raw_context->r14 = kAMD64TestR14;
+ raw_context->r15 = kAMD64TestR15;
+ raw_context->rip = kAMD64TestRip;
+
+ SetContextFlags(raw_context->context_flags);
+ SetContextAMD64(raw_context);
+ this->valid_ = true;
+ }
+}
+
+TestDumpContext::~TestDumpContext() {
+ FreeContext();
+}
+
+TEST(DisassemblerObjdumpTest, DisassembleInstructionX86) {
+ string instruction;
+ ASSERT_FALSE(DisassemblerObjdumpForTest::DisassembleInstruction(
+ MD_CONTEXT_X86, nullptr, 0, instruction));
+ std::vector<uint8_t> pop_eax = {0x58};
+ ASSERT_TRUE(DisassemblerObjdumpForTest::DisassembleInstruction(
+ MD_CONTEXT_X86, pop_eax.data(), pop_eax.size(), instruction));
+ ASSERT_EQ(instruction, "pop eax");
+}
+
+TEST(DisassemblerObjdumpTest, DisassembleInstructionAMD64) {
+ string instruction;
+ ASSERT_FALSE(DisassemblerObjdumpForTest::DisassembleInstruction(
+ MD_CONTEXT_AMD64, nullptr, 0, instruction));
+ std::vector<uint8_t> pop_rax = {0x58};
+ ASSERT_TRUE(DisassemblerObjdumpForTest::DisassembleInstruction(
+ MD_CONTEXT_AMD64, pop_rax.data(), pop_rax.size(), instruction));
+ ASSERT_EQ(instruction, "pop rax");
+}
+
+TEST(DisassemblerObjdumpTest, TokenizeInstruction) {
+ string operation, dest, src;
+ ASSERT_TRUE(DisassemblerObjdumpForTest::TokenizeInstruction(
+ "pop eax", operation, dest, src));
+ ASSERT_EQ(operation, "pop");
+ ASSERT_EQ(dest, "eax");
+
+ ASSERT_TRUE(DisassemblerObjdumpForTest::TokenizeInstruction(
+ "mov eax, ebx", operation, dest, src));
+ ASSERT_EQ(operation, "mov");
+ ASSERT_EQ(dest, "eax");
+ ASSERT_EQ(src, "ebx");
+
+ ASSERT_TRUE(DisassemblerObjdumpForTest::TokenizeInstruction(
+ "pop rax", operation, dest, src));
+ ASSERT_EQ(operation, "pop");
+ ASSERT_EQ(dest, "rax");
+
+ ASSERT_TRUE(DisassemblerObjdumpForTest::TokenizeInstruction(
+ "mov rax, rbx", operation, dest, src));
+ ASSERT_EQ(operation, "mov");
+ ASSERT_EQ(dest, "rax");
+ ASSERT_EQ(src, "rbx");
+
+ // Test the three parsing failure paths
+ ASSERT_FALSE(DisassemblerObjdumpForTest::TokenizeInstruction(
+ "mov rax,", operation, dest, src));
+ ASSERT_FALSE(DisassemblerObjdumpForTest::TokenizeInstruction(
+ "mov rax rbx", operation, dest, src));
+ ASSERT_FALSE(DisassemblerObjdumpForTest::TokenizeInstruction(
+ "mov rax, rbx, rcx", operation, dest, src));
+
+ // This is of course a nonsense instruction, but test that we do remove
+ // multiple instruction prefixes and can handle multiple memory operands.
+ ASSERT_TRUE(DisassemblerObjdumpForTest::TokenizeInstruction(
+ "rep lock mov DWORD PTR rax, QWORD PTR rbx", operation, dest, src));
+ ASSERT_EQ(operation, "mov");
+ ASSERT_EQ(dest, "rax");
+ ASSERT_EQ(src, "rbx");
+
+ // Test that we ignore junk following a valid instruction
+ ASSERT_TRUE(DisassemblerObjdumpForTest::TokenizeInstruction(
+ "mov rax, rbx ; junk here", operation, dest, src));
+ ASSERT_EQ(operation, "mov");
+ ASSERT_EQ(dest, "rax");
+ ASSERT_EQ(src, "rbx");
+}
+
+namespace x86 {
+const TestMemoryRegion load_reg(kX86TestEip, {0x8b, 0x06}); // mov eax, [esi];
+
+const TestMemoryRegion load_reg_index(kX86TestEip,
+ {0x8b, 0x04,
+ 0xbe}); // mov eax, [esi+edi*4];
+
+const TestMemoryRegion load_reg_offset(kX86TestEip,
+ {0x8b, 0x46,
+ 0x10}); // mov eax, [esi+0x10];
+
+const TestMemoryRegion load_reg_index_offset(
+ kX86TestEip,
+ {0x8b, 0x44, 0xbe, 0xf0}); // mov eax, [esi+edi*4-0x10];
+
+const TestMemoryRegion rep_stosb(kX86TestEip, {0xf3, 0xaa}); // rep stosb;
+
+const TestMemoryRegion lock_cmpxchg(kX86TestEip,
+ {0xf0, 0x0f, 0xb1, 0x46,
+ 0x10}); // lock cmpxchg [esi + 0x10], eax;
+
+const TestMemoryRegion call_reg_offset(kX86TestEip,
+ {0xff, 0x96, 0x99, 0x99, 0x99,
+ 0x09}); // call [esi+0x9999999];
+} // namespace x86
+
+TEST(DisassemblerObjdumpTest, X86LoadReg) {
+ TestDumpContext context;
+ DisassemblerObjdump dis(context.GetContextCPU(), &x86::load_reg, kX86TestEip);
+ uint64_t src_address = 0, dest_address = 0;
+ ASSERT_FALSE(dis.CalculateDestAddress(context, dest_address));
+ ASSERT_TRUE(dis.CalculateSrcAddress(context, src_address));
+ ASSERT_EQ(src_address, kX86TestEsi);
+}
+
+TEST(DisassemblerObjdumpTest, X86LoadRegIndex) {
+ TestDumpContext context;
+ DisassemblerObjdump dis(context.GetContextCPU(), &x86::load_reg_index,
+ kX86TestEip);
+ uint64_t src_address = 0, dest_address = 0;
+ ASSERT_FALSE(dis.CalculateDestAddress(context, dest_address));
+ ASSERT_TRUE(dis.CalculateSrcAddress(context, src_address));
+ ASSERT_EQ(src_address, kX86TestEsi + (kX86TestEdi * 4));
+}
+
+TEST(DisassemblerObjdumpTest, X86LoadRegOffset) {
+ TestDumpContext context;
+ DisassemblerObjdump dis(context.GetContextCPU(), &x86::load_reg_offset,
+ kX86TestEip);
+ uint64_t src_address = 0, dest_address = 0;
+ ASSERT_FALSE(dis.CalculateDestAddress(context, dest_address));
+ ASSERT_TRUE(dis.CalculateSrcAddress(context, src_address));
+ ASSERT_EQ(src_address, kX86TestEsi + 0x10);
+}
+
+TEST(DisassemblerObjdumpTest, X86LoadRegIndexOffset) {
+ TestDumpContext context;
+ DisassemblerObjdump dis(context.GetContextCPU(), &x86::load_reg_index_offset,
+ kX86TestEip);
+ uint64_t src_address = 0, dest_address = 0;
+ ASSERT_FALSE(dis.CalculateDestAddress(context, dest_address));
+ ASSERT_TRUE(dis.CalculateSrcAddress(context, src_address));
+ ASSERT_EQ(src_address, kX86TestEsi + (kX86TestEdi * 4) - 0x10);
+}
+
+TEST(DisassemblerObjdumpTest, X86RepStosb) {
+ TestDumpContext context;
+ DisassemblerObjdump dis(context.GetContextCPU(), &x86::rep_stosb,
+ kX86TestEip);
+ uint64_t src_address = 0, dest_address = 0;
+ ASSERT_TRUE(dis.CalculateDestAddress(context, dest_address));
+ ASSERT_FALSE(dis.CalculateSrcAddress(context, src_address));
+ ASSERT_EQ(dest_address, kX86TestEs + kX86TestEdi);
+}
+
+TEST(DisassemblerObjdumpTest, X86LockCmpxchg) {
+ TestDumpContext context;
+ DisassemblerObjdump dis(context.GetContextCPU(), &x86::lock_cmpxchg,
+ kX86TestEip);
+ uint64_t src_address = 0, dest_address = 0;
+ ASSERT_TRUE(dis.CalculateDestAddress(context, dest_address));
+ ASSERT_FALSE(dis.CalculateSrcAddress(context, src_address));
+ ASSERT_EQ(dest_address, kX86TestEsi + 0x10);
+}
+
+TEST(DisassemblerObjdumpTest, X86CallRegOffset) {
+ TestDumpContext context;
+ DisassemblerObjdump dis(context.GetContextCPU(), &x86::call_reg_offset,
+ kX86TestEip);
+ uint64_t src_address = 0, dest_address = 0;
+ ASSERT_TRUE(dis.CalculateDestAddress(context, dest_address));
+ ASSERT_FALSE(dis.CalculateSrcAddress(context, src_address));
+ ASSERT_EQ(dest_address, kX86TestEsi + 0x9999999);
+}
+
+namespace amd64 {
+const TestMemoryRegion load_reg(kAMD64TestRip,
+ {0x48, 0x8b, 0x06}); // mov rax, [rsi];
+
+const TestMemoryRegion load_reg_index(kAMD64TestRip,
+ {0x48, 0x8b, 0x04,
+ 0xbe}); // mov rax, [rsi+rdi*4];
+
+const TestMemoryRegion load_rip_relative(kAMD64TestRip,
+ {0x48, 0x8b, 0x05, 0x10, 0x00, 0x00,
+ 0x00}); // mov rax, [rip+0x10];
+
+const TestMemoryRegion load_reg_index_offset(
+ kAMD64TestRip,
+ {0x48, 0x8b, 0x44, 0xbe, 0xf0}); // mov rax, [rsi+rdi*4-0x10];
+
+const TestMemoryRegion rep_stosb(kAMD64TestRip, {0xf3, 0xaa}); // rep stosb;
+
+const TestMemoryRegion lock_cmpxchg(kAMD64TestRip,
+ {0xf0, 0x48, 0x0f, 0xb1, 0x46,
+ 0x10}); // lock cmpxchg [rsi + 0x10], rax;
+
+const TestMemoryRegion call_reg_offset(kAMD64TestRip,
+ {0xff, 0x96, 0x99, 0x99, 0x99,
+ 0x09}); // call [rsi+0x9999999];
+} // namespace amd64
+
+TEST(DisassemblerObjdumpTest, AMD64LoadReg) {
+ TestDumpContext context(true);
+ DisassemblerObjdump dis(context.GetContextCPU(), &amd64::load_reg,
+ kAMD64TestRip);
+ uint64_t src_address = 0, dest_address = 0;
+ ASSERT_FALSE(dis.CalculateDestAddress(context, dest_address));
+ ASSERT_TRUE(dis.CalculateSrcAddress(context, src_address));
+ ASSERT_EQ(src_address, kAMD64TestRsi);
+}
+
+TEST(DisassemblerObjdumpTest, AMD64LoadRegIndex) {
+ TestDumpContext context(true);
+ DisassemblerObjdump dis(context.GetContextCPU(), &amd64::load_reg_index,
+ kAMD64TestRip);
+ uint64_t src_address = 0, dest_address = 0;
+ ASSERT_FALSE(dis.CalculateDestAddress(context, dest_address));
+ ASSERT_TRUE(dis.CalculateSrcAddress(context, src_address));
+ ASSERT_EQ(src_address, kAMD64TestRsi + (kAMD64TestRdi * 4));
+}
+
+TEST(DisassemblerObjdumpTest, AMD64LoadRipRelative) {
+ TestDumpContext context(true);
+ DisassemblerObjdump dis(context.GetContextCPU(), &amd64::load_rip_relative,
+ kAMD64TestRip);
+ uint64_t src_address = 0, dest_address = 0;
+ ASSERT_FALSE(dis.CalculateDestAddress(context, dest_address));
+ ASSERT_TRUE(dis.CalculateSrcAddress(context, src_address));
+ ASSERT_EQ(src_address, kAMD64TestRip + 0x10);
+}
+
+TEST(DisassemblerObjdumpTest, AMD64LoadRegIndexOffset) {
+ TestDumpContext context(true);
+ DisassemblerObjdump dis(context.GetContextCPU(),
+ &amd64::load_reg_index_offset, kAMD64TestRip);
+ uint64_t src_address = 0, dest_address = 0;
+ ASSERT_FALSE(dis.CalculateDestAddress(context, dest_address));
+ ASSERT_TRUE(dis.CalculateSrcAddress(context, src_address));
+ ASSERT_EQ(src_address, kAMD64TestRsi + (kAMD64TestRdi * 4) - 0x10);
+}
+
+TEST(DisassemblerObjdumpTest, AMD64RepStosb) {
+ TestDumpContext context(true);
+ DisassemblerObjdump dis(context.GetContextCPU(), &amd64::rep_stosb,
+ kAMD64TestRip);
+ uint64_t src_address = 0, dest_address = 0;
+ ASSERT_TRUE(dis.CalculateDestAddress(context, dest_address));
+ ASSERT_FALSE(dis.CalculateSrcAddress(context, src_address));
+ ASSERT_EQ(dest_address, kAMD64TestRdi);
+}
+
+TEST(DisassemblerObjdumpTest, AMD64LockCmpxchg) {
+ TestDumpContext context(true);
+ DisassemblerObjdump dis(context.GetContextCPU(), &amd64::lock_cmpxchg,
+ kAMD64TestRip);
+ uint64_t src_address = 0, dest_address = 0;
+ ASSERT_TRUE(dis.CalculateDestAddress(context, dest_address));
+ ASSERT_FALSE(dis.CalculateSrcAddress(context, src_address));
+ ASSERT_EQ(dest_address, kAMD64TestRsi + 0x10);
+}
+
+TEST(DisassemblerObjdumpTest, AMD64CallRegOffset) {
+ TestDumpContext context(true);
+ DisassemblerObjdump dis(context.GetContextCPU(), &amd64::call_reg_offset,
+ kAMD64TestRip);
+ uint64_t src_address = 0, dest_address = 0;
+ ASSERT_TRUE(dis.CalculateDestAddress(context, dest_address));
+ ASSERT_FALSE(dis.CalculateSrcAddress(context, src_address));
+ ASSERT_EQ(dest_address, kAMD64TestRsi + 0x9999999);
+}
+} // namespace google_breakpad
diff --git a/src/processor/disassembler_x86.cc b/src/processor/disassembler_x86.cc
index 55902240..dffb996d 100644
--- a/src/processor/disassembler_x86.cc
+++ b/src/processor/disassembler_x86.cc
@@ -1,7 +1,16 @@
+// Copyright 2010 Google LLC
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -30,7 +39,7 @@
namespace google_breakpad {
-DisassemblerX86::DisassemblerX86(const uint8_t *bytecode,
+DisassemblerX86::DisassemblerX86(const uint8_t* bytecode,
uint32_t size,
uint32_t virtual_address) :
bytecode_(bytecode),
@@ -62,7 +71,7 @@ uint32_t DisassemblerX86::NextInstruction() {
return 0;
}
uint32_t instr_size = 0;
- instr_size = libdis::x86_disasm((unsigned char *)bytecode_, size_,
+ instr_size = libdis::x86_disasm((unsigned char*)bytecode_, size_,
virtual_address_, current_byte_offset_,
&current_instr_);
if (instr_size == 0) {
@@ -78,8 +87,8 @@ uint32_t DisassemblerX86::NextInstruction() {
if (current_instr_.type == libdis::insn_return)
end_of_block_ = true;
- libdis::x86_op_t *src = libdis::x86_get_src_operand(&current_instr_);
- libdis::x86_op_t *dest = libdis::x86_get_dest_operand(&current_instr_);
+ libdis::x86_op_t* src = libdis::x86_get_src_operand(&current_instr_);
+ libdis::x86_op_t* dest = libdis::x86_get_dest_operand(&current_instr_);
if (register_valid_) {
switch (current_instr_.group) {
@@ -213,7 +222,7 @@ bool DisassemblerX86::setBadRead() {
if (!instr_valid_)
return false;
- libdis::x86_op_t *operand = libdis::x86_get_src_operand(&current_instr_);
+ libdis::x86_op_t* operand = libdis::x86_get_src_operand(&current_instr_);
if (!operand || operand->type != libdis::op_expression)
return false;
@@ -227,7 +236,7 @@ bool DisassemblerX86::setBadWrite() {
if (!instr_valid_)
return false;
- libdis::x86_op_t *operand = libdis::x86_get_dest_operand(&current_instr_);
+ libdis::x86_op_t* operand = libdis::x86_get_dest_operand(&current_instr_);
if (!operand || operand->type != libdis::op_expression)
return false;
diff --git a/src/processor/disassembler_x86.h b/src/processor/disassembler_x86.h
index 71069410..493f7f2e 100644
--- a/src/processor/disassembler_x86.h
+++ b/src/processor/disassembler_x86.h
@@ -1,4 +1,4 @@
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -10,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -63,7 +63,7 @@ class DisassemblerX86 {
// TODO(cdn): Modify this class to take a MemoryRegion instead of just
// a raw buffer. This will make it easier to use this on arbitrary
// minidumps without first copying out the code segment.
- DisassemblerX86(const uint8_t *bytecode, uint32_t, uint32_t);
+ DisassemblerX86(const uint8_t* bytecode, uint32_t, uint32_t);
~DisassemblerX86();
// This walks to the next instruction in the memory region and
@@ -102,7 +102,7 @@ class DisassemblerX86 {
bool setBadWrite();
protected:
- const uint8_t *bytecode_;
+ const uint8_t* bytecode_;
uint32_t size_;
uint32_t virtual_address_;
uint32_t current_byte_offset_;
diff --git a/src/processor/disassembler_x86_unittest.cc b/src/processor/disassembler_x86_unittest.cc
index 352905f2..117b3bf8 100644
--- a/src/processor/disassembler_x86_unittest.cc
+++ b/src/processor/disassembler_x86_unittest.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2010, Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -25,7 +24,7 @@
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <unistd.h>
diff --git a/src/processor/dump_context.cc b/src/processor/dump_context.cc
index da531b74..a8ab0084 100644
--- a/src/processor/dump_context.cc
+++ b/src/processor/dump_context.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2010 Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -140,6 +139,24 @@ const MDRawContextMIPS* DumpContext::GetContextMIPS() const {
return context_.ctx_mips;
}
+const MDRawContextRISCV* DumpContext::GetContextRISCV() const {
+ if (GetContextCPU() != MD_CONTEXT_RISCV) {
+ BPLOG(ERROR) << "DumpContext cannot get RISCV context";
+ return NULL;
+ }
+
+ return context_.riscv;
+}
+
+const MDRawContextRISCV64* DumpContext::GetContextRISCV64() const {
+ if (GetContextCPU() != MD_CONTEXT_RISCV64) {
+ BPLOG(ERROR) << "DumpContext cannot get RISCV64 context";
+ return NULL;
+ }
+
+ return context_.riscv64;
+}
+
bool DumpContext::GetInstructionPointer(uint64_t* ip) const {
BPLOG_IF(ERROR, !ip) << "DumpContext::GetInstructionPointer requires |ip|";
assert(ip);
@@ -176,6 +193,12 @@ bool DumpContext::GetInstructionPointer(uint64_t* ip) const {
case MD_CONTEXT_MIPS64:
*ip = GetContextMIPS()->epc;
break;
+ case MD_CONTEXT_RISCV:
+ *ip = GetContextRISCV()->pc;
+ break;
+ case MD_CONTEXT_RISCV64:
+ *ip = GetContextRISCV64()->pc;
+ break;
default:
// This should never happen.
BPLOG(ERROR) << "Unknown CPU architecture in GetInstructionPointer";
@@ -220,6 +243,12 @@ bool DumpContext::GetStackPointer(uint64_t* sp) const {
case MD_CONTEXT_MIPS64:
*sp = GetContextMIPS()->iregs[MD_CONTEXT_MIPS_REG_SP];
break;
+ case MD_CONTEXT_RISCV:
+ *sp = GetContextRISCV()->sp;
+ break;
+ case MD_CONTEXT_RISCV64:
+ *sp = GetContextRISCV64()->sp;
+ break;
default:
// This should never happen.
BPLOG(ERROR) << "Unknown CPU architecture in GetStackPointer";
@@ -264,6 +293,14 @@ void DumpContext::SetContextMIPS(MDRawContextMIPS* ctx_mips) {
context_.ctx_mips = ctx_mips;
}
+void DumpContext::SetContextRISCV(MDRawContextRISCV* riscv) {
+ context_.riscv = riscv;
+}
+
+void DumpContext::SetContextRISCV64(MDRawContextRISCV64* riscv64) {
+ context_.riscv64 = riscv64;
+}
+
void DumpContext::FreeContext() {
switch (GetContextCPU()) {
case MD_CONTEXT_X86:
@@ -299,6 +336,14 @@ void DumpContext::FreeContext() {
delete context_.ctx_mips;
break;
+ case MD_CONTEXT_RISCV:
+ delete context_.riscv;
+ break;
+
+ case MD_CONTEXT_RISCV64:
+ delete context_.riscv64;
+ break;
+
default:
// There is no context record (valid_ is false) or there's a
// context record for an unknown CPU (shouldn't happen, only known
@@ -655,6 +700,195 @@ void DumpContext::Print() {
break;
}
+ case MD_CONTEXT_RISCV: {
+ const MDRawContextRISCV* context_riscv = GetContextRISCV();
+ printf("MDRawContextRISCV\n");
+ printf(" context_flags = 0x%x\n",
+ context_riscv->context_flags);
+
+ printf(" pc = 0x%" PRIx32 "\n",
+ context_riscv->pc);
+ printf(" ra = 0x%" PRIx32 "\n",
+ context_riscv->ra);
+ printf(" sp = 0x%" PRIx32 "\n",
+ context_riscv->sp);
+ printf(" gp = 0x%" PRIx32 "\n",
+ context_riscv->gp);
+ printf(" tp = 0x%" PRIx32 "\n",
+ context_riscv->tp);
+ printf(" t0 = 0x%" PRIx32 "\n",
+ context_riscv->t0);
+ printf(" t1 = 0x%" PRIx32 "\n",
+ context_riscv->t1);
+ printf(" t2 = 0x%" PRIx32 "\n",
+ context_riscv->t2);
+ printf(" s0 = 0x%" PRIx32 "\n",
+ context_riscv->s0);
+ printf(" s1 = 0x%" PRIx32 "\n",
+ context_riscv->s1);
+ printf(" a0 = 0x%" PRIx32 "\n",
+ context_riscv->a0);
+ printf(" a1 = 0x%" PRIx32 "\n",
+ context_riscv->a1);
+ printf(" a2 = 0x%" PRIx32 "\n",
+ context_riscv->a2);
+ printf(" a3 = 0x%" PRIx32 "\n",
+ context_riscv->a3);
+ printf(" a4 = 0x%" PRIx32 "\n",
+ context_riscv->a4);
+ printf(" a5 = 0x%" PRIx32 "\n",
+ context_riscv->a5);
+ printf(" a6 = 0x%" PRIx32 "\n",
+ context_riscv->a6);
+ printf(" a7 = 0x%" PRIx32 "\n",
+ context_riscv->a7);
+ printf(" s2 = 0x%" PRIx32 "\n",
+ context_riscv->s2);
+ printf(" s3 = 0x%" PRIx32 "\n",
+ context_riscv->s3);
+ printf(" s4 = 0x%" PRIx32 "\n",
+ context_riscv->s4);
+ printf(" s5 = 0x%" PRIx32 "\n",
+ context_riscv->s5);
+ printf(" s6 = 0x%" PRIx32 "\n",
+ context_riscv->s6);
+ printf(" s7 = 0x%" PRIx32 "\n",
+ context_riscv->s7);
+ printf(" s8 = 0x%" PRIx32 "\n",
+ context_riscv->s8);
+ printf(" s9 = 0x%" PRIx32 "\n",
+ context_riscv->s9);
+ printf(" s10 = 0x%" PRIx32 "\n",
+ context_riscv->s10);
+ printf(" s11 = 0x%" PRIx32 "\n",
+ context_riscv->s11);
+ printf(" t3 = 0x%" PRIx32 "\n",
+ context_riscv->t3);
+ printf(" t4 = 0x%" PRIx32 "\n",
+ context_riscv->t4);
+ printf(" t5 = 0x%" PRIx32 "\n",
+ context_riscv->t5);
+ printf(" t6 = 0x%" PRIx32 "\n",
+ context_riscv->t6);
+
+#if defined(__riscv)
+ for (unsigned int freg_index = 0;
+ freg_index < MD_FLOATINGSAVEAREA_RISCV_FPR_COUNT; ++freg_index) {
+ riscv_fpr_size fp_value = context_riscv->float_save.regs[freg_index];
+# if __riscv_flen == 32
+ printf(" float_save.regs[%2d] = 0x%" PRIx32 "\n",
+ freg_index, fp_value);
+# elif __riscv_flen == 64
+ printf(" float_save.regs[%2d] = 0x%" PRIx64 "\n",
+ freg_index, fp_value);
+# elif __riscv_flen == 128
+ printf(" float_save.regs[%2d] = 0x%" PRIx64 "%" PRIx64 "\n",
+ freg_index, fp_value.high, fp_value.low);
+# else
+# error "Unexpected __riscv_flen"
+# endif
+ }
+ printf(" float_save.fpcsr = 0x%" PRIx32 "\n",
+ context_riscv->float_save.fpcsr);
+#endif
+ break;
+ }
+
+ case MD_CONTEXT_RISCV64: {
+ const MDRawContextRISCV64* context_riscv64 = GetContextRISCV64();
+ printf("MDRawContextRISCV64\n");
+ printf(" context_flags = 0x%x\n",
+ context_riscv64->context_flags);
+
+ printf(" pc = 0x%" PRIx64 "\n",
+ context_riscv64->pc);
+ printf(" ra = 0x%" PRIx64 "\n",
+ context_riscv64->ra);
+ printf(" sp = 0x%" PRIx64 "\n",
+ context_riscv64->sp);
+ printf(" gp = 0x%" PRIx64 "\n",
+ context_riscv64->gp);
+ printf(" tp = 0x%" PRIx64 "\n",
+ context_riscv64->tp);
+ printf(" t0 = 0x%" PRIx64 "\n",
+ context_riscv64->t0);
+ printf(" t1 = 0x%" PRIx64 "\n",
+ context_riscv64->t1);
+ printf(" t2 = 0x%" PRIx64 "\n",
+ context_riscv64->t2);
+ printf(" s0 = 0x%" PRIx64 "\n",
+ context_riscv64->s0);
+ printf(" s1 = 0x%" PRIx64 "\n",
+ context_riscv64->s1);
+ printf(" a0 = 0x%" PRIx64 "\n",
+ context_riscv64->a0);
+ printf(" a1 = 0x%" PRIx64 "\n",
+ context_riscv64->a1);
+ printf(" a2 = 0x%" PRIx64 "\n",
+ context_riscv64->a2);
+ printf(" a3 = 0x%" PRIx64 "\n",
+ context_riscv64->a3);
+ printf(" a4 = 0x%" PRIx64 "\n",
+ context_riscv64->a4);
+ printf(" a5 = 0x%" PRIx64 "\n",
+ context_riscv64->a5);
+ printf(" a6 = 0x%" PRIx64 "\n",
+ context_riscv64->a6);
+ printf(" a7 = 0x%" PRIx64 "\n",
+ context_riscv64->a7);
+ printf(" s2 = 0x%" PRIx64 "\n",
+ context_riscv64->s2);
+ printf(" s3 = 0x%" PRIx64 "\n",
+ context_riscv64->s3);
+ printf(" s4 = 0x%" PRIx64 "\n",
+ context_riscv64->s4);
+ printf(" s5 = 0x%" PRIx64 "\n",
+ context_riscv64->s5);
+ printf(" s6 = 0x%" PRIx64 "\n",
+ context_riscv64->s6);
+ printf(" s7 = 0x%" PRIx64 "\n",
+ context_riscv64->s7);
+ printf(" s8 = 0x%" PRIx64 "\n",
+ context_riscv64->s8);
+ printf(" s9 = 0x%" PRIx64 "\n",
+ context_riscv64->s9);
+ printf(" s10 = 0x%" PRIx64 "\n",
+ context_riscv64->s10);
+ printf(" s11 = 0x%" PRIx64 "\n",
+ context_riscv64->s11);
+ printf(" t3 = 0x%" PRIx64 "\n",
+ context_riscv64->t3);
+ printf(" t4 = 0x%" PRIx64 "\n",
+ context_riscv64->t4);
+ printf(" t5 = 0x%" PRIx64 "\n",
+ context_riscv64->t5);
+ printf(" t6 = 0x%" PRIx64 "\n",
+ context_riscv64->t6);
+
+#if defined(__riscv)
+ for (unsigned int freg_index = 0;
+ freg_index < MD_FLOATINGSAVEAREA_RISCV_FPR_COUNT; ++freg_index) {
+ riscv_fpr_size fp_value = context_riscv64->float_save.regs[freg_index];
+# if __riscv_flen == 32
+ printf(" float_save.regs[%2d] = 0x%" PRIx32 "\n",
+ freg_index, fp_value);
+# elif __riscv_flen == 64
+ printf(" float_save.regs[%2d] = 0x%" PRIx64 "\n",
+ freg_index, fp_value);
+# elif __riscv_flen == 128
+ printf(" float_save.regs[%2d] = 0x%"
+ PRIx64 "%" PRIx64 "\n",
+ freg_index, fp_value.high, fp_value.low);
+# else
+# error "Unexpected __riscv_flen"
+# endif
+ }
+ printf(" float_save.fpcsr = 0x%" PRIx32 "\n",
+ context_riscv64->float_save.fpcsr);
+#endif
+ break;
+ }
+
default: {
break;
}
diff --git a/src/processor/dump_object.cc b/src/processor/dump_object.cc
index 2c82b200..6186c8fa 100644
--- a/src/processor/dump_object.cc
+++ b/src/processor/dump_object.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2010 Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/processor/exploitability.cc b/src/processor/exploitability.cc
index 5f05b510..7a4107bf 100644
--- a/src/processor/exploitability.cc
+++ b/src/processor/exploitability.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2010 Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/processor/exploitability_linux.cc b/src/processor/exploitability_linux.cc
index ccc9f145..63a12656 100644
--- a/src/processor/exploitability_linux.cc
+++ b/src/processor/exploitability_linux.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2013 Google Inc.
-// All rights reserved.
+// Copyright 2013 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -36,21 +35,13 @@
#include "processor/exploitability_linux.h"
-#ifndef _WIN32
-#include <regex.h>
-#include <stdio.h>
-#include <stdlib.h>
-
-#include <sstream>
-#include <iterator>
-#endif // _WIN32
-
#include <string.h>
#include "google_breakpad/common/minidump_exception_linux.h"
#include "google_breakpad/processor/call_stack.h"
#include "google_breakpad/processor/process_state.h"
#include "google_breakpad/processor/stack_frame.h"
+#include "processor/disassembler_objdump.h"
#include "processor/logging.h"
namespace {
@@ -68,22 +59,17 @@ constexpr char kStackCheckFailureFunction[] = "__stack_chk_fail";
// can determine that the call would overflow the target buffer.
constexpr char kBoundsCheckFailureFunction[] = "__chk_fail";
-#ifndef _WIN32
-const unsigned int MAX_INSTRUCTION_LEN = 15;
-const unsigned int MAX_OBJDUMP_BUFFER_LEN = 4096;
-#endif // _WIN32
-
} // namespace
namespace google_breakpad {
-ExploitabilityLinux::ExploitabilityLinux(Minidump *dump,
- ProcessState *process_state)
+ExploitabilityLinux::ExploitabilityLinux(Minidump* dump,
+ ProcessState* process_state)
: Exploitability(dump, process_state),
enable_objdump_(false) { }
-ExploitabilityLinux::ExploitabilityLinux(Minidump *dump,
- ProcessState *process_state,
+ExploitabilityLinux::ExploitabilityLinux(Minidump* dump,
+ ProcessState* process_state,
bool enable_objdump)
: Exploitability(dump, process_state),
enable_objdump_(enable_objdump) { }
@@ -111,12 +97,12 @@ ExploitabilityRating ExploitabilityLinux::CheckPlatformExploitability() {
}
// Getting exception data. (It should exist for all minidumps.)
- MinidumpException *exception = dump_->GetException();
+ MinidumpException* exception = dump_->GetException();
if (exception == NULL) {
BPLOG(INFO) << "No exception record.";
return EXPLOITABILITY_ERR_PROCESSING;
}
- const MDRawExceptionStream *raw_exception_stream = exception->exception();
+ const MDRawExceptionStream* raw_exception_stream = exception->exception();
if (raw_exception_stream == NULL) {
BPLOG(INFO) << "No raw exception stream.";
return EXPLOITABILITY_ERR_PROCESSING;
@@ -132,7 +118,7 @@ ExploitabilityRating ExploitabilityLinux::CheckPlatformExploitability() {
uint64_t instruction_ptr = 0;
uint64_t stack_ptr = 0;
- const MinidumpContext *context = exception->GetContext();
+ const MinidumpContext* context = exception->GetContext();
if (context == NULL) {
BPLOG(INFO) << "No exception context.";
return EXPLOITABILITY_ERR_PROCESSING;
@@ -172,10 +158,11 @@ ExploitabilityRating ExploitabilityLinux::CheckPlatformExploitability() {
bool ExploitabilityLinux::EndedOnIllegalWrite(uint64_t instruction_ptr) {
#ifdef _WIN32
BPLOG(INFO) << "MinGW does not support fork and exec. Terminating method.";
+ return false;
#else
// Get memory region containing instruction pointer.
- MinidumpMemoryList *memory_list = dump_->GetMemoryList();
- MinidumpMemoryRegion *memory_region =
+ MinidumpMemoryList* memory_list = dump_->GetMemoryList();
+ MinidumpMemoryRegion* memory_region =
memory_list ?
memory_list->GetMemoryRegionForAddress(instruction_ptr) : NULL;
if (!memory_region) {
@@ -185,83 +172,44 @@ bool ExploitabilityLinux::EndedOnIllegalWrite(uint64_t instruction_ptr) {
// Get exception data to find architecture.
string architecture = "";
- MinidumpException *exception = dump_->GetException();
+ MinidumpException* exception = dump_->GetException();
// This should never evaluate to true, since this should not be reachable
// without checking for exception data earlier.
if (!exception) {
BPLOG(INFO) << "No exception data.";
return false;
}
- const MDRawExceptionStream *raw_exception_stream = exception->exception();
- const MinidumpContext *context = exception->GetContext();
+ const MDRawExceptionStream* raw_exception_stream = exception->exception();
+ const MinidumpContext* context = exception->GetContext();
// This should not evaluate to true, for the same reason mentioned above.
if (!raw_exception_stream || !context) {
BPLOG(INFO) << "No exception or architecture data.";
return false;
}
- // Check architecture and set architecture variable to corresponding flag
- // in objdump.
- switch (context->GetContextCPU()) {
- case MD_CONTEXT_X86:
- architecture = "i386";
- break;
- case MD_CONTEXT_AMD64:
- architecture = "i386:x86-64";
- break;
- default:
- // Unsupported architecture. Note that ARM architectures are not
- // supported because objdump does not support ARM.
- return false;
- break;
- }
- // Get memory region around instruction pointer and the number of bytes
- // before and after the instruction pointer in the memory region.
- const uint8_t *raw_memory = memory_region->GetMemory();
- const uint64_t base = memory_region->GetBase();
- if (base > instruction_ptr) {
- BPLOG(ERROR) << "Memory region base value exceeds instruction pointer.";
- return false;
- }
- const uint64_t offset = instruction_ptr - base;
- if (memory_region->GetSize() < MAX_INSTRUCTION_LEN + offset) {
- BPLOG(INFO) << "Not enough bytes left to guarantee complete instruction.";
- return false;
- }
-
- // Convert bytes into objdump output.
- char objdump_output_buffer[MAX_OBJDUMP_BUFFER_LEN] = {0};
- DisassembleBytes(architecture,
- raw_memory + offset,
- MAX_OBJDUMP_BUFFER_LEN,
- objdump_output_buffer);
-
- string line;
- if (!GetObjdumpInstructionLine(objdump_output_buffer, &line)) {
+ DisassemblerObjdump disassembler(context->GetContextCPU(), memory_region,
+ instruction_ptr);
+ if (!disassembler.IsValid()) {
+ BPLOG(INFO) << "Disassembling fault instruction failed.";
return false;
}
- // Convert objdump instruction line into the operation and operands.
- string instruction = "";
- string dest = "";
- string src = "";
- TokenizeObjdumpInstruction(line, &instruction, &dest, &src);
-
- // Check if the operation is a write to memory. First, the instruction
- // must one that can write to memory. Second, the write destination
- // must be a spot in memory rather than a register. Since there are no
- // symbols from objdump, the destination will be enclosed by brackets.
- if (dest.size() > 2 && dest.at(0) == '[' && dest.at(dest.size() - 1) == ']' &&
- (!instruction.compare("mov") || !instruction.compare("inc") ||
- !instruction.compare("dec") || !instruction.compare("and") ||
- !instruction.compare("or") || !instruction.compare("xor") ||
- !instruction.compare("not") || !instruction.compare("neg") ||
- !instruction.compare("add") || !instruction.compare("sub") ||
- !instruction.compare("shl") || !instruction.compare("shr"))) {
- // Strip away enclosing brackets from the destination address.
- dest = dest.substr(1, dest.size() - 2);
+ // Check if the operation is a write to memory.
+ // First, the instruction must one that can write to memory.
+ auto instruction = disassembler.operation();
+ if (!instruction.compare("mov") || !instruction.compare("inc") ||
+ !instruction.compare("dec") || !instruction.compare("and") ||
+ !instruction.compare("or") || !instruction.compare("xor") ||
+ !instruction.compare("not") || !instruction.compare("neg") ||
+ !instruction.compare("add") || !instruction.compare("sub") ||
+ !instruction.compare("shl") || !instruction.compare("shr")) {
uint64_t write_address = 0;
- CalculateAddress(dest, *context, &write_address);
+
+ // Check that the destination is a memory address. CalculateDestAddress will
+ // return false if the destination is not a memory address.
+ if (!disassembler.CalculateDestAddress(*context, write_address)) {
+ return false;
+ }
// If the program crashed as a result of a write, the destination of
// the write must have been an address that did not permit writing.
@@ -269,277 +217,19 @@ bool ExploitabilityLinux::EndedOnIllegalWrite(uint64_t instruction_ptr) {
// the crash does not suggest exploitability for writes with such a
// low target address.
return write_address > 4096;
- }
-#endif // _WIN32
- return false;
-}
-
-#ifndef _WIN32
-bool ExploitabilityLinux::CalculateAddress(const string &address_expression,
- const DumpContext &context,
- uint64_t *write_address) {
- // The destination should be the format reg+a or reg-a, where reg
- // is a register and a is a hexadecimal constant. Although more complex
- // expressions can make valid instructions, objdump's disassembly outputs
- // it in this simpler format.
- // TODO(liuandrew): Handle more complex formats, should they arise.
-
- if (!write_address) {
- BPLOG(ERROR) << "Null parameter.";
+ } else {
return false;
}
-
- // Clone parameter into a non-const string.
- string expression = address_expression;
-
- // Parse out the constant that is added to the address (if it exists).
- size_t delim = expression.find('+');
- bool positive_add_constant = true;
- // Check if constant is subtracted instead of added.
- if (delim == string::npos) {
- positive_add_constant = false;
- delim = expression.find('-');
- }
- uint32_t add_constant = 0;
- // Save constant and remove it from the expression.
- if (delim != string::npos) {
- if (!sscanf(expression.substr(delim + 1).c_str(), "%x", &add_constant)) {
- BPLOG(ERROR) << "Failed to scan constant.";
- return false;
- }
- expression = expression.substr(0, delim);
- }
-
- // Set the the write address to the corresponding register.
- // TODO(liuandrew): Add support for partial registers, such as
- // the rax/eax/ax/ah/al chain.
- switch (context.GetContextCPU()) {
- case MD_CONTEXT_X86:
- if (!expression.compare("eax")) {
- *write_address = context.GetContextX86()->eax;
- } else if (!expression.compare("ebx")) {
- *write_address = context.GetContextX86()->ebx;
- } else if (!expression.compare("ecx")) {
- *write_address = context.GetContextX86()->ecx;
- } else if (!expression.compare("edx")) {
- *write_address = context.GetContextX86()->edx;
- } else if (!expression.compare("edi")) {
- *write_address = context.GetContextX86()->edi;
- } else if (!expression.compare("esi")) {
- *write_address = context.GetContextX86()->esi;
- } else if (!expression.compare("ebp")) {
- *write_address = context.GetContextX86()->ebp;
- } else if (!expression.compare("esp")) {
- *write_address = context.GetContextX86()->esp;
- } else if (!expression.compare("eip")) {
- *write_address = context.GetContextX86()->eip;
- } else {
- BPLOG(ERROR) << "Unsupported register";
- return false;
- }
- break;
- case MD_CONTEXT_AMD64:
- if (!expression.compare("rax")) {
- *write_address = context.GetContextAMD64()->rax;
- } else if (!expression.compare("rbx")) {
- *write_address = context.GetContextAMD64()->rbx;
- } else if (!expression.compare("rcx")) {
- *write_address = context.GetContextAMD64()->rcx;
- } else if (!expression.compare("rdx")) {
- *write_address = context.GetContextAMD64()->rdx;
- } else if (!expression.compare("rdi")) {
- *write_address = context.GetContextAMD64()->rdi;
- } else if (!expression.compare("rsi")) {
- *write_address = context.GetContextAMD64()->rsi;
- } else if (!expression.compare("rbp")) {
- *write_address = context.GetContextAMD64()->rbp;
- } else if (!expression.compare("rsp")) {
- *write_address = context.GetContextAMD64()->rsp;
- } else if (!expression.compare("rip")) {
- *write_address = context.GetContextAMD64()->rip;
- } else if (!expression.compare("r8")) {
- *write_address = context.GetContextAMD64()->r8;
- } else if (!expression.compare("r9")) {
- *write_address = context.GetContextAMD64()->r9;
- } else if (!expression.compare("r10")) {
- *write_address = context.GetContextAMD64()->r10;
- } else if (!expression.compare("r11")) {
- *write_address = context.GetContextAMD64()->r11;
- } else if (!expression.compare("r12")) {
- *write_address = context.GetContextAMD64()->r12;
- } else if (!expression.compare("r13")) {
- *write_address = context.GetContextAMD64()->r13;
- } else if (!expression.compare("r14")) {
- *write_address = context.GetContextAMD64()->r14;
- } else if (!expression.compare("r15")) {
- *write_address = context.GetContextAMD64()->r15;
- } else {
- BPLOG(ERROR) << "Unsupported register";
- return false;
- }
- break;
- default:
- // This should not occur since the same switch condition
- // should have terminated this method.
- return false;
- break;
- }
-
- // Add or subtract constant from write address (if applicable).
- *write_address =
- positive_add_constant ?
- *write_address + add_constant : *write_address - add_constant;
-
- return true;
-}
-
-// static
-bool ExploitabilityLinux::GetObjdumpInstructionLine(
- const char *objdump_output_buffer,
- string *instruction_line) {
- // Put buffer data into stream to output line-by-line.
- std::stringstream objdump_stream;
- objdump_stream.str(string(objdump_output_buffer));
-
- // Pipe each output line into the string until the string contains the first
- // instruction from objdump. All lines before the "<.data>:" section are
- // skipped. Loop until the line shows the first instruction or there are no
- // lines left.
- bool data_section_seen = false;
- do {
- if (!getline(objdump_stream, *instruction_line)) {
- BPLOG(INFO) << "Objdump instructions not found";
- return false;
- }
- if (instruction_line->find("<.data>:") != string::npos) {
- data_section_seen = true;
- }
- } while (!data_section_seen || instruction_line->find("0:") == string::npos);
- // This first instruction contains the above substring.
-
- return true;
-}
-
-bool ExploitabilityLinux::TokenizeObjdumpInstruction(const string &line,
- string *operation,
- string *dest,
- string *src) {
- if (!operation || !dest || !src) {
- BPLOG(ERROR) << "Null parameters passed.";
- return false;
- }
-
- // Set all pointer values to empty strings.
- *operation = "";
- *dest = "";
- *src = "";
-
- // Tokenize the objdump line.
- vector<string> tokens;
- std::istringstream line_stream(line);
- copy(std::istream_iterator<string>(line_stream),
- std::istream_iterator<string>(),
- std::back_inserter(tokens));
-
- // Regex for the data in hex form. Each byte is two hex digits.
- regex_t regex;
- regcomp(&regex, "^[[:xdigit:]]{2}$", REG_EXTENDED | REG_NOSUB);
-
- // Find and set the location of the operator. The operator appears
- // directly after the chain of bytes that define the instruction. The
- // operands will be the last token, given that the instruction has operands.
- // If not, the operator is the last token. The loop skips the first token
- // because the first token is the instruction number (namely "0:").
- string operands = "";
- for (size_t i = 1; i < tokens.size(); i++) {
- // Check if current token no longer is in byte format.
- if (regexec(&regex, tokens[i].c_str(), 0, NULL, 0)) {
- // instruction = tokens[i];
- *operation = tokens[i];
- // If the operator is the last token, there are no operands.
- if (i != tokens.size() - 1) {
- operands = tokens[tokens.size() - 1];
- }
- break;
- }
- }
- regfree(&regex);
-
- if (operation->empty()) {
- BPLOG(ERROR) << "Failed to parse out operation from objdump instruction.";
- return false;
- }
-
- // Split operands into source and destination (if applicable).
- if (!operands.empty()) {
- size_t delim = operands.find(',');
- if (delim == string::npos) {
- *dest = operands;
- } else {
- *dest = operands.substr(0, delim);
- *src = operands.substr(delim + 1);
- }
- }
- return true;
-}
-
-bool ExploitabilityLinux::DisassembleBytes(const string &architecture,
- const uint8_t *raw_bytes,
- const unsigned int buffer_len,
- char *objdump_output_buffer) {
- if (!raw_bytes || !objdump_output_buffer) {
- BPLOG(ERROR) << "Bad input parameters.";
- return false;
- }
-
- // Write raw bytes around instruction pointer to a temporary file to
- // pass as an argument to objdump.
- char raw_bytes_tmpfile[] = "/tmp/breakpad_mem_region-raw_bytes-XXXXXX";
- int raw_bytes_fd = mkstemp(raw_bytes_tmpfile);
- if (raw_bytes_fd < 0) {
- BPLOG(ERROR) << "Failed to create tempfile.";
- unlink(raw_bytes_tmpfile);
- return false;
- }
- if (write(raw_bytes_fd, raw_bytes, MAX_INSTRUCTION_LEN)
- != MAX_INSTRUCTION_LEN) {
- BPLOG(ERROR) << "Writing of raw bytes failed.";
- unlink(raw_bytes_tmpfile);
- return false;
- }
-
- char cmd[1024] = {0};
- snprintf(cmd,
- 1024,
- "objdump -D -b binary -M intel -m %s %s",
- architecture.c_str(),
- raw_bytes_tmpfile);
- FILE *objdump_fp = popen(cmd, "r");
- if (!objdump_fp) {
- fclose(objdump_fp);
- unlink(raw_bytes_tmpfile);
- BPLOG(ERROR) << "Failed to call objdump.";
- return false;
- }
- if (fread(objdump_output_buffer, 1, buffer_len, objdump_fp) <= 0) {
- fclose(objdump_fp);
- unlink(raw_bytes_tmpfile);
- BPLOG(ERROR) << "Failed to read objdump output.";
- return false;
- }
- fclose(objdump_fp);
- unlink(raw_bytes_tmpfile);
- return true;
-}
#endif // _WIN32
+}
bool ExploitabilityLinux::StackPointerOffStack(uint64_t stack_ptr) {
- MinidumpLinuxMapsList *linux_maps_list = dump_->GetLinuxMapsList();
+ MinidumpLinuxMapsList* linux_maps_list = dump_->GetLinuxMapsList();
// Inconclusive if there are no mappings available.
if (!linux_maps_list) {
return false;
}
- const MinidumpLinuxMaps *linux_maps =
+ const MinidumpLinuxMaps* linux_maps =
linux_maps_list->GetLinuxMapsForAddress(stack_ptr);
// Checks if the stack pointer maps to a valid mapping and if the mapping
// is not the stack. If the mapping has no name, it is inconclusive whether
@@ -550,10 +240,10 @@ bool ExploitabilityLinux::StackPointerOffStack(uint64_t stack_ptr) {
}
bool ExploitabilityLinux::ExecutableStackOrHeap() {
- MinidumpLinuxMapsList *linux_maps_list = dump_->GetLinuxMapsList();
+ MinidumpLinuxMapsList* linux_maps_list = dump_->GetLinuxMapsList();
if (linux_maps_list) {
for (size_t i = 0; i < linux_maps_list->get_maps_count(); i++) {
- const MinidumpLinuxMaps *linux_maps =
+ const MinidumpLinuxMaps* linux_maps =
linux_maps_list->GetLinuxMapsAtIndex(i);
// Check for executable stack or heap for each mapping.
if (linux_maps && (!linux_maps->GetPathname().compare(
@@ -574,15 +264,15 @@ bool ExploitabilityLinux::InstructionPointerInCode(uint64_t instruction_ptr) {
// whether it is in a valid code region. If there is no mapping for the
// instruction pointer, it is indicative that the instruction pointer is
// not within a module, which implies that it is outside a valid area.
- MinidumpLinuxMapsList *linux_maps_list = dump_->GetLinuxMapsList();
- const MinidumpLinuxMaps *linux_maps =
+ MinidumpLinuxMapsList* linux_maps_list = dump_->GetLinuxMapsList();
+ const MinidumpLinuxMaps* linux_maps =
linux_maps_list ?
linux_maps_list->GetLinuxMapsForAddress(instruction_ptr) : NULL;
return linux_maps ? linux_maps->IsExecutable() : false;
}
-bool ExploitabilityLinux::BenignCrashTrigger(const MDRawExceptionStream
- *raw_exception_stream) {
+bool ExploitabilityLinux::BenignCrashTrigger(
+ const MDRawExceptionStream* raw_exception_stream) {
// Check the cause of crash.
// If the exception of the crash is a benign exception,
// it is probably not exploitable.
@@ -616,10 +306,8 @@ bool ExploitabilityLinux::BenignCrashTrigger(const MDRawExceptionStream
case MD_EXCEPTION_CODE_LIN_SIGSYS:
case MD_EXCEPTION_CODE_LIN_DUMP_REQUESTED:
return true;
- break;
default:
return false;
- break;
}
}
diff --git a/src/processor/exploitability_linux.h b/src/processor/exploitability_linux.h
index e3ff13b6..7603e456 100644
--- a/src/processor/exploitability_linux.h
+++ b/src/processor/exploitability_linux.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2013 Google Inc.
-// All rights reserved.
+// Copyright 2013 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -44,8 +43,8 @@ namespace google_breakpad {
class ExploitabilityLinux : public Exploitability {
public:
- ExploitabilityLinux(Minidump *dump,
- ProcessState *process_state);
+ ExploitabilityLinux(Minidump* dump,
+ ProcessState* process_state);
// Parameters are the minidump to analyze, the object representing process
// state, and whether to enable objdump disassembly.
@@ -53,8 +52,8 @@ class ExploitabilityLinux : public Exploitability {
// objdump for diassembly. It is used to check the identity of the
// instruction that caused the program to crash. If there are any
// portability concerns, this should not be enabled.
- ExploitabilityLinux(Minidump *dump,
- ProcessState *process_state,
+ ExploitabilityLinux(Minidump* dump,
+ ProcessState* process_state,
bool enable_objdump);
virtual ExploitabilityRating CheckPlatformExploitability();
@@ -68,7 +67,7 @@ class ExploitabilityLinux : public Exploitability {
// Checks the exception that triggered the creation of the
// minidump and reports whether the exception suggests no exploitability.
- bool BenignCrashTrigger(const MDRawExceptionStream *raw_exception_stream);
+ bool BenignCrashTrigger(const MDRawExceptionStream* raw_exception_stream);
// This method checks if the crash occurred during a write to read-only or
// invalid memory. It does so by checking if the instruction at the
@@ -76,41 +75,6 @@ class ExploitabilityLinux : public Exploitability {
// instruction is at a spot in memory that prohibits writes.
bool EndedOnIllegalWrite(uint64_t instruction_ptr);
-#ifndef _WIN32
- // Disassembles raw bytes via objdump and pipes the output into the provided
- // buffer, given the desired architecture, the file from which objdump will
- // read, and the buffer length. The method returns whether the disassembly
- // was a success, and the caller owns all pointers.
- static bool DisassembleBytes(const string &architecture,
- const uint8_t *raw_bytes,
- const unsigned int MAX_OBJDUMP_BUFFER_LEN,
- char *objdump_output_buffer);
-
- // Parses the objdump output given in |objdump_output_buffer| and extracts
- // the line of the first instruction into |instruction_line|. Returns true
- // when the instruction line is successfully extracted.
- static bool GetObjdumpInstructionLine(
- const char *objdump_output_buffer,
- string *instruction_line);
-
- // Tokenizes out the operation and operands from a line of instruction
- // disassembled by objdump. This method modifies the pointers to match the
- // tokens of the instruction, and returns if the tokenizing was a success.
- // The caller owns all pointers.
- static bool TokenizeObjdumpInstruction(const string &line,
- string *operation,
- string *dest,
- string *src);
-
- // Calculates the effective address of an expression in the form reg+a or
- // reg-a, where 'reg' is a register and 'a' is a constant, and writes the
- // result in the pointer. The method returns whether the calculation was
- // a success. The caller owns the pointer.
- static bool CalculateAddress(const string &address_expression,
- const DumpContext &context,
- uint64_t *write_address);
-#endif // _WIN32
-
// Checks if the stack pointer points to a memory mapping that is not
// labelled as the stack.
bool StackPointerOffStack(uint64_t stack_ptr);
diff --git a/src/processor/exploitability_unittest.cc b/src/processor/exploitability_unittest.cc
index 528ee5f2..bc1823c6 100644
--- a/src/processor/exploitability_unittest.cc
+++ b/src/processor/exploitability_unittest.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2010, Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -25,11 +24,12 @@
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <stdlib.h>
#include <unistd.h>
+#include <type_traits>
#include <string>
#include "breakpad_googletest_includes.h"
@@ -37,22 +37,13 @@
#include "google_breakpad/processor/basic_source_line_resolver.h"
#include "google_breakpad/processor/minidump_processor.h"
#include "google_breakpad/processor/process_state.h"
-#ifndef _WIN32
+#ifdef __linux__
#include "processor/exploitability_linux.h"
-#endif // _WIN32
+#endif // __linux__
#include "processor/simple_symbol_supplier.h"
-#ifndef _WIN32
+#ifdef __linux__
namespace google_breakpad {
-
-class ExploitabilityLinuxTest : public ExploitabilityLinux {
- public:
- using ExploitabilityLinux::CalculateAddress;
- using ExploitabilityLinux::DisassembleBytes;
- using ExploitabilityLinux::GetObjdumpInstructionLine;
- using ExploitabilityLinux::TokenizeObjdumpInstruction;
-};
-
class ExploitabilityLinuxTestMinidumpContext : public MinidumpContext {
public:
explicit ExploitabilityLinuxTestMinidumpContext(
@@ -64,15 +55,14 @@ class ExploitabilityLinuxTestMinidumpContext : public MinidumpContext {
};
} // namespace google_breakpad
-#endif // _WIN32
+#endif // __linux__
namespace {
using google_breakpad::BasicSourceLineResolver;
-#ifndef _WIN32
-using google_breakpad::ExploitabilityLinuxTest;
+#ifdef __linux__
using google_breakpad::ExploitabilityLinuxTestMinidumpContext;
-#endif // _WIN32
+#endif // __linux__
using google_breakpad::MinidumpProcessor;
using google_breakpad::ProcessState;
using google_breakpad::SimpleSymbolSupplier;
@@ -171,7 +161,7 @@ TEST(ExploitabilityTest, TestLinuxEngine) {
ExploitabilityFor("linux_executable_heap.dmp"));
ASSERT_EQ(google_breakpad::EXPLOITABILITY_HIGH,
ExploitabilityFor("linux_jmp_to_module_not_exe_region.dmp"));
-#ifndef _WIN32
+#ifdef __linux__
ASSERT_EQ(google_breakpad::EXPLOITABILITY_HIGH,
ExploitabilityFor("linux_write_to_nonwritable_module.dmp"));
ASSERT_EQ(google_breakpad::EXPLOITABILITY_HIGH,
@@ -182,125 +172,7 @@ TEST(ExploitabilityTest, TestLinuxEngine) {
ExploitabilityFor("linux_write_to_outside_module_via_math.dmp"));
ASSERT_EQ(google_breakpad::EXPLOITABILITY_INTERESTING,
ExploitabilityFor("linux_write_to_under_4k.dmp"));
-#endif // _WIN32
-}
-
-#ifndef _WIN32
-TEST(ExploitabilityLinuxUtilsTest, DisassembleBytesTest) {
- ASSERT_FALSE(ExploitabilityLinuxTest::DisassembleBytes("", NULL, 5, NULL));
- uint8_t bytes[6] = {0xc7, 0x0, 0x5, 0x0, 0x0, 0x0};
- char buffer[1024] = {0};
- ASSERT_TRUE(ExploitabilityLinuxTest::DisassembleBytes("i386:x86-64",
- bytes,
- 1024,
- buffer));
- std::stringstream objdump_stream;
- objdump_stream.str(string(buffer));
- string line = "";
- while (line.find("<.data>") == string::npos)
- getline(objdump_stream, line);
- getline(objdump_stream, line);
- ASSERT_EQ(line, " 0:\tc7 00 05 00 00 00 \tmov DWORD PTR [rax],0x5");
-}
-
-TEST(ExploitabilityLinuxUtilsTest, GetObjdumpInstructionLine) {
- string disassebly =
- "\n"
- "/tmp/breakpad_mem_region-raw_bytes-tMmMo0: file format binary\n"
- "// Trying to confuse the parser 0:\n"
- "\n"
- "Disassembly of section .data:\n"
- "\n"
- "0000000000000000 <.data>:\n"
- " 0:\tc7 00 01 00 00 00 \tmov DWORD PTR [rax],0x1\n"
- " 6:\t5d \tpop rbp\n"
- " 7:\tc3 \tret \n"
- " 8:\t55 \tpush rbp\n"
- " 9:\t48 89 e5 \tmov rbp,rsp\n"
- " c:\t53 \tpush rbx\n"
- " d:\t48 \trex.W\n"
- " e:\t81 \t.byte 0x81\n";
- string line;
- EXPECT_TRUE(ExploitabilityLinuxTest::GetObjdumpInstructionLine(
- disassebly.c_str(), &line));
- EXPECT_EQ(" 0:\tc7 00 01 00 00 00 \tmov DWORD PTR [rax],0x1", line);
-
- // There is no "0:" after "<.data>:". Expected to return false.
- disassebly =
- "\n"
- "/tmp/breakpad_mem_region-raw_bytes-tMmMo0: file format binary\n"
- "// Trying to confuse the parser 0:\n"
- "\n"
- "Disassembly of section .data:\n"
- "\n"
- " 0:\tc7 00 01 00 00 00 \tmov DWORD PTR [rax],0x1\n"
- " 6:\t5d \tpop rbp\n"
- " 7:\tc3 \tret \n"
- " 8:\t55 \tpush rbp\n"
- " 9:\t48 89 e5 \tmov rbp,rsp\n"
- " d:\t48 \trex.W\n"
- "0000000000000000 <.data>:\n"
- " c:\t53 \tpush rbx\n";
- EXPECT_FALSE(ExploitabilityLinuxTest::GetObjdumpInstructionLine(
- disassebly.c_str(), &line));
-}
-
-TEST(ExploitabilityLinuxUtilsTest, TokenizeObjdumpInstructionTest) {
- ASSERT_FALSE(ExploitabilityLinuxTest::TokenizeObjdumpInstruction("",
- NULL,
- NULL,
- NULL));
- string line = "0: c7 00 05 00 00 00 mov DWORD PTR [rax],0x5";
- string operation = "";
- string dest = "";
- string src = "";
- ASSERT_TRUE(ExploitabilityLinuxTest::TokenizeObjdumpInstruction(line,
- &operation,
- &dest,
- &src));
- ASSERT_EQ(operation, "mov");
- ASSERT_EQ(dest, "[rax]");
- ASSERT_EQ(src, "0x5");
- line = "0: c3 ret";
- ASSERT_TRUE(ExploitabilityLinuxTest::TokenizeObjdumpInstruction(line,
- &operation,
- &dest,
- &src));
- ASSERT_EQ(operation, "ret");
- ASSERT_EQ(dest, "");
- ASSERT_EQ(src, "");
- line = "0: 5f pop rdi";
- ASSERT_TRUE(ExploitabilityLinuxTest::TokenizeObjdumpInstruction(line,
- &operation,
- &dest,
- &src));
- ASSERT_EQ(operation, "pop");
- ASSERT_EQ(dest, "rdi");
- ASSERT_EQ(src, "");
-}
-
-TEST(ExploitabilityLinuxUtilsTest, CalculateAddressTest) {
- MDRawContextAMD64 raw_context;
- raw_context.rdx = 12345;
- ExploitabilityLinuxTestMinidumpContext context(raw_context);
- ASSERT_EQ(context.GetContextAMD64()->rdx, 12345U);
- ASSERT_FALSE(ExploitabilityLinuxTest::CalculateAddress("", context, NULL));
- uint64_t write_address = 0;
- ASSERT_TRUE(ExploitabilityLinuxTest::CalculateAddress("rdx-0x4D2",
- context,
- &write_address));
- ASSERT_EQ(write_address, 11111U);
- ASSERT_TRUE(ExploitabilityLinuxTest::CalculateAddress("rdx+0x4D2",
- context,
- &write_address));
- ASSERT_EQ(write_address, 13579U);
- ASSERT_FALSE(ExploitabilityLinuxTest::CalculateAddress("rdx+rax",
- context,
- &write_address));
- ASSERT_FALSE(ExploitabilityLinuxTest::CalculateAddress("0x3482+0x4D2",
- context,
- &write_address));
+#endif // __linux__
}
-#endif // _WIN32
} // namespace
diff --git a/src/processor/exploitability_win.cc b/src/processor/exploitability_win.cc
index a1f8703a..accaadd3 100644
--- a/src/processor/exploitability_win.cc
+++ b/src/processor/exploitability_win.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2010 Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -69,30 +68,30 @@ static const size_t kHugeBump = 90;
// The maximum number of bytes to disassemble past the program counter.
static const size_t kDisassembleBytesBeyondPC = 2048;
-ExploitabilityWin::ExploitabilityWin(Minidump *dump,
- ProcessState *process_state)
+ExploitabilityWin::ExploitabilityWin(Minidump* dump,
+ ProcessState* process_state)
: Exploitability(dump, process_state) { }
ExploitabilityRating ExploitabilityWin::CheckPlatformExploitability() {
- MinidumpException *exception = dump_->GetException();
+ MinidumpException* exception = dump_->GetException();
if (!exception) {
BPLOG(INFO) << "Minidump does not have exception record.";
return EXPLOITABILITY_ERR_PROCESSING;
}
- const MDRawExceptionStream *raw_exception = exception->exception();
+ const MDRawExceptionStream* raw_exception = exception->exception();
if (!raw_exception) {
BPLOG(INFO) << "Could not obtain raw exception info.";
return EXPLOITABILITY_ERR_PROCESSING;
}
- const MinidumpContext *context = exception->GetContext();
+ const MinidumpContext* context = exception->GetContext();
if (!context) {
BPLOG(INFO) << "Could not obtain exception context.";
return EXPLOITABILITY_ERR_PROCESSING;
}
- MinidumpMemoryList *memory_list = dump_->GetMemoryList();
+ MinidumpMemoryList* memory_list = dump_->GetMemoryList();
bool memory_available = true;
if (!memory_list) {
BPLOG(INFO) << "Minidump memory segments not available.";
@@ -193,9 +192,8 @@ ExploitabilityRating ExploitabilityWin::CheckPlatformExploitability() {
default:
BPLOG(INFO) << "Unrecognized access violation type.";
return EXPLOITABILITY_ERR_PROCESSING;
- break;
}
- MinidumpMemoryRegion *instruction_region = 0;
+ MinidumpMemoryRegion* instruction_region = 0;
if (memory_available) {
instruction_region =
memory_list->GetMemoryRegionForAddress(instruction_ptr);
@@ -211,7 +209,7 @@ ExploitabilityRating ExploitabilityWin::CheckPlatformExploitability() {
available_memory = available_memory > kDisassembleBytesBeyondPC ?
kDisassembleBytesBeyondPC : available_memory;
if (available_memory) {
- const uint8_t *raw_memory =
+ const uint8_t* raw_memory =
instruction_region->GetMemory() + memory_offset;
DisassemblerX86 disassembler(raw_memory,
available_memory,
diff --git a/src/processor/exploitability_win.h b/src/processor/exploitability_win.h
index 4e08aef0..52cff8b7 100644
--- a/src/processor/exploitability_win.h
+++ b/src/processor/exploitability_win.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2010 Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/processor/fast_source_line_resolver.cc b/src/processor/fast_source_line_resolver.cc
index 4a3d0007..0d1ebc6b 100644
--- a/src/processor/fast_source_line_resolver.cc
+++ b/src/processor/fast_source_line_resolver.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2010 Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -40,17 +39,19 @@
#include "google_breakpad/processor/fast_source_line_resolver.h"
#include "processor/fast_source_line_resolver_types.h"
+#include <cassert>
#include <map>
#include <string>
#include <utility>
#include "common/scoped_ptr.h"
#include "common/using_std_string.h"
+#include "processor/logging.h"
#include "processor/module_factory.h"
#include "processor/simple_serializer-inl.h"
-using std::map;
-using std::make_pair;
+using std::deque;
+using std::unique_ptr;
namespace google_breakpad {
@@ -61,7 +62,9 @@ bool FastSourceLineResolver::ShouldDeleteMemoryBufferAfterLoadModule() {
return false;
}
-void FastSourceLineResolver::Module::LookupAddress(StackFrame *frame) const {
+void FastSourceLineResolver::Module::LookupAddress(
+ StackFrame* frame,
+ std::deque<std::unique_ptr<StackFrame>>* inlined_frames) const {
MemAddr address = frame->instruction - frame->module->base_address();
// First, look for a FUNC record that covers address. Use
@@ -81,15 +84,16 @@ void FastSourceLineResolver::Module::LookupAddress(StackFrame *frame) const {
if (functions_.RetrieveNearestRange(address, func_ptr,
&function_base, &function_size) &&
address >= function_base && address - function_base < function_size) {
- func.get()->CopyFrom(func_ptr);
+ func->CopyFrom(func_ptr);
frame->function_name = func->name;
frame->function_base = frame->module->base_address() + function_base;
+ frame->is_multiple = func->is_multiple;
scoped_ptr<Line> line(new Line);
const Line* line_ptr = 0;
MemAddr line_base;
if (func->lines.RetrieveRange(address, line_ptr, &line_base, NULL)) {
- line.get()->CopyFrom(line_ptr);
+ line->CopyFrom(line_ptr);
FileMap::iterator it = files_.find(line->source_file_id);
if (it != files_.end()) {
frame->source_file_name =
@@ -98,18 +102,85 @@ void FastSourceLineResolver::Module::LookupAddress(StackFrame *frame) const {
frame->source_line = line->line;
frame->source_line_base = frame->module->base_address() + line_base;
}
+ // Check if this is inlined function call.
+ if (inlined_frames) {
+ ConstructInlineFrames(frame, address, func->inlines, inlined_frames);
+ }
} else if (public_symbols_.Retrieve(address,
public_symbol_ptr, &public_address) &&
(!func_ptr || public_address > function_base)) {
- public_symbol.get()->CopyFrom(public_symbol_ptr);
+ public_symbol->CopyFrom(public_symbol_ptr);
frame->function_name = public_symbol->name;
frame->function_base = frame->module->base_address() + public_address;
+ frame->is_multiple = public_symbol->is_multiple;
+ }
+}
+
+void FastSourceLineResolver::Module::ConstructInlineFrames(
+ StackFrame* frame,
+ MemAddr address,
+ const StaticContainedRangeMap<MemAddr, char>& inline_map,
+ std::deque<std::unique_ptr<StackFrame>>* inlined_frames) const {
+ std::vector<const char*> inline_ptrs;
+ if (!inline_map.RetrieveRanges(address, inline_ptrs)) {
+ return;
+ }
+
+ for (const char* inline_ptr : inline_ptrs) {
+ scoped_ptr<Inline> in(new Inline);
+ in->CopyFrom(inline_ptr);
+ unique_ptr<StackFrame> new_frame =
+ unique_ptr<StackFrame>(new StackFrame(*frame));
+ auto origin_iter = inline_origins_.find(in->origin_id);
+ if (origin_iter != inline_origins_.end()) {
+ scoped_ptr<InlineOrigin> origin(new InlineOrigin);
+ origin->CopyFrom(origin_iter.GetValuePtr());
+ new_frame->function_name = origin->name;
+ } else {
+ new_frame->function_name = "<name omitted>";
+ }
+
+ // Store call site file and line in current frame, which will be updated
+ // later.
+ new_frame->source_line = in->call_site_line;
+ if (in->has_call_site_file_id) {
+ auto file_iter = files_.find(in->call_site_file_id);
+ if (file_iter != files_.end()) {
+ new_frame->source_file_name = file_iter.GetValuePtr();
+ }
+ }
+
+ // Use the starting adress of the inlined range as inlined function base.
+ new_frame->function_base = new_frame->module->base_address();
+ for (const auto& range : in->inline_ranges) {
+ if (address >= range.first && address < range.first + range.second) {
+ new_frame->function_base += range.first;
+ break;
+ }
+ }
+ new_frame->trust = StackFrame::FRAME_TRUST_INLINE;
+
+ // The inlines vector has an order from innermost entry to outermost entry.
+ // By push_back, we will have inlined_frames with the same order.
+ inlined_frames->push_back(std::move(new_frame));
+ }
+
+ // Update the source file and source line for each inlined frame.
+ if (!inlined_frames->empty()) {
+ string parent_frame_source_file_name = frame->source_file_name;
+ int parent_frame_source_line = frame->source_line;
+ frame->source_file_name = inlined_frames->back()->source_file_name;
+ frame->source_line = inlined_frames->back()->source_line;
+ for (unique_ptr<StackFrame>& inlined_frame : *inlined_frames) {
+ std::swap(inlined_frame->source_file_name, parent_frame_source_file_name);
+ std::swap(inlined_frame->source_line, parent_frame_source_line);
+ }
}
}
// WFI: WindowsFrameInfo.
// Returns a WFI object reading from a raw memory chunk of data
-WindowsFrameInfo FastSourceLineResolver::CopyWFI(const char *raw) {
+WindowsFrameInfo FastSourceLineResolver::CopyWFI(const char* raw) {
const WindowsFrameInfo::StackInfoTypes type =
static_cast<const WindowsFrameInfo::StackInfoTypes>(
*reinterpret_cast<const int32_t*>(raw));
@@ -117,7 +188,7 @@ WindowsFrameInfo FastSourceLineResolver::CopyWFI(const char *raw) {
// The first 8 bytes of int data are unused.
// They correspond to "StackInfoTypes type_;" and "int valid;"
// data member of WFI.
- const uint32_t *para_uint32 = reinterpret_cast<const uint32_t*>(
+ const uint32_t* para_uint32 = reinterpret_cast<const uint32_t*>(
raw + 2 * sizeof(int32_t));
uint32_t prolog_size = para_uint32[0];;
@@ -126,7 +197,7 @@ WindowsFrameInfo FastSourceLineResolver::CopyWFI(const char *raw) {
uint32_t saved_register_size = para_uint32[3];
uint32_t local_size = para_uint32[4];
uint32_t max_stack_size = para_uint32[5];
- const char *boolean = reinterpret_cast<const char*>(para_uint32 + 6);
+ const char* boolean = reinterpret_cast<const char*>(para_uint32 + 6);
bool allocates_base_pointer = (*boolean != 0);
string program_string = boolean + 1;
@@ -145,15 +216,15 @@ WindowsFrameInfo FastSourceLineResolver::CopyWFI(const char *raw) {
// Does NOT take ownership of mem_buffer.
// In addition, treat mem_buffer as const char*.
bool FastSourceLineResolver::Module::LoadMapFromMemory(
- char *memory_buffer,
+ char* memory_buffer,
size_t memory_buffer_size) {
if (!memory_buffer) return false;
// Read the "is_corrupt" flag.
- const char *mem_buffer = memory_buffer;
+ const char* mem_buffer = memory_buffer;
mem_buffer = SimpleSerializer<bool>::Read(mem_buffer, &is_corrupt_);
- const uint32_t *map_sizes = reinterpret_cast<const uint32_t*>(mem_buffer);
+ const uint32_t* map_sizes = reinterpret_cast<const uint32_t*>(mem_buffer);
unsigned int header_size = kNumberMaps_ * sizeof(unsigned int);
@@ -166,6 +237,19 @@ bool FastSourceLineResolver::Module::LoadMapFromMemory(
for (int i = 1; i < kNumberMaps_; ++i) {
offsets[i] = offsets[i - 1] + map_sizes[i - 1];
}
+ unsigned int expected_size = sizeof(bool) + offsets[kNumberMaps_ - 1] +
+ map_sizes[kNumberMaps_ - 1] + 1;
+ if (expected_size != memory_buffer_size &&
+ // Allow for having an extra null terminator.
+ expected_size != memory_buffer_size - 1) {
+ // This could either be a random corruption or the serialization format was
+ // changed without updating the version in kSerializedBreakpadFileExtension.
+ BPLOG(ERROR) << "Memory buffer is either corrupt or an unsupported version"
+ << ", expected size: " << expected_size
+ << ", actual size: " << memory_buffer_size;
+ return false;
+ }
+ BPLOG(INFO) << "Memory buffer size looks good, size: " << memory_buffer_size;
// Use pointers to construct Static*Map data members in Module:
int map_id = 0;
@@ -174,19 +258,20 @@ bool FastSourceLineResolver::Module::LoadMapFromMemory(
StaticRangeMap<MemAddr, Function>(mem_buffer + offsets[map_id++]);
public_symbols_ =
StaticAddressMap<MemAddr, PublicSymbol>(mem_buffer + offsets[map_id++]);
- for (int i = 0; i < WindowsFrameInfo::STACK_INFO_LAST; ++i)
+ for (int i = 0; i < WindowsFrameInfo::STACK_INFO_LAST; ++i) {
windows_frame_info_[i] =
StaticContainedRangeMap<MemAddr, char>(mem_buffer + offsets[map_id++]);
+ }
cfi_initial_rules_ =
StaticRangeMap<MemAddr, char>(mem_buffer + offsets[map_id++]);
cfi_delta_rules_ = StaticMap<MemAddr, char>(mem_buffer + offsets[map_id++]);
-
+ inline_origins_ = StaticMap<int, char>(mem_buffer + offsets[map_id++]);
return true;
}
-WindowsFrameInfo *FastSourceLineResolver::Module::FindWindowsFrameInfo(
- const StackFrame *frame) const {
+WindowsFrameInfo* FastSourceLineResolver::Module::FindWindowsFrameInfo(
+ const StackFrame* frame) const {
MemAddr address = frame->instruction - frame->module->base_address();
scoped_ptr<WindowsFrameInfo> result(new WindowsFrameInfo());
@@ -218,7 +303,7 @@ WindowsFrameInfo *FastSourceLineResolver::Module::FindWindowsFrameInfo(
if (functions_.RetrieveNearestRange(address, function_ptr,
&function_base, &function_size) &&
address >= function_base && address - function_base < function_size) {
- function.get()->CopyFrom(function_ptr);
+ function->CopyFrom(function_ptr);
result->parameter_size = function->parameter_size;
result->valid |= WindowsFrameInfo::VALID_PARAMETER_SIZE;
return result.release();
@@ -231,15 +316,15 @@ WindowsFrameInfo *FastSourceLineResolver::Module::FindWindowsFrameInfo(
MemAddr public_address;
if (public_symbols_.Retrieve(address, public_symbol_ptr, &public_address) &&
(!function_ptr || public_address > function_base)) {
- public_symbol.get()->CopyFrom(public_symbol_ptr);
+ public_symbol->CopyFrom(public_symbol_ptr);
result->parameter_size = public_symbol->parameter_size;
}
return NULL;
}
-CFIFrameInfo *FastSourceLineResolver::Module::FindCFIFrameInfo(
- const StackFrame *frame) const {
+CFIFrameInfo* FastSourceLineResolver::Module::FindCFIFrameInfo(
+ const StackFrame* frame) const {
MemAddr address = frame->instruction - frame->module->base_address();
MemAddr initial_base, initial_size;
const char* initial_rules = NULL;
diff --git a/src/processor/fast_source_line_resolver_types.h b/src/processor/fast_source_line_resolver_types.h
index 2c010470..75b9004f 100644
--- a/src/processor/fast_source_line_resolver_types.h
+++ b/src/processor/fast_source_line_resolver_types.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2010 Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -37,14 +36,16 @@
#ifndef PROCESSOR_FAST_SOURCE_LINE_RESOLVER_TYPES_H__
#define PROCESSOR_FAST_SOURCE_LINE_RESOLVER_TYPES_H__
-#include "google_breakpad/processor/fast_source_line_resolver.h"
-#include "processor/source_line_resolver_base_types.h"
-
+#include <cstdint>
#include <map>
#include <string>
+#include "google_breakpad/processor/fast_source_line_resolver.h"
#include "google_breakpad/processor/stack_frame.h"
#include "processor/cfi_frame_info.h"
+#include "processor/contained_range_map.h"
+#include "processor/simple_serializer-inl.h"
+#include "processor/source_line_resolver_base_types.h"
#include "processor/static_address_map-inl.h"
#include "processor/static_contained_range_map-inl.h"
#include "processor/static_map.h"
@@ -53,74 +54,133 @@
namespace google_breakpad {
+#define DESERIALIZE(raw_ptr, field) \
+ field = *(reinterpret_cast<const decltype(field)*>(raw_ptr)); \
+ raw_ptr += sizeof(field);
+
struct FastSourceLineResolver::Line : public SourceLineResolverBase::Line {
- void CopyFrom(const Line *line_ptr) {
- const char *raw = reinterpret_cast<const char*>(line_ptr);
+ void CopyFrom(const Line* line_ptr) {
+ const char* raw = reinterpret_cast<const char*>(line_ptr);
CopyFrom(raw);
}
// De-serialize the memory data of a Line.
- void CopyFrom(const char *raw) {
- address = *(reinterpret_cast<const MemAddr*>(raw));
- size = *(reinterpret_cast<const MemAddr*>(raw + sizeof(address)));
- source_file_id = *(reinterpret_cast<const int32_t *>(
- raw + 2 * sizeof(address)));
- line = *(reinterpret_cast<const int32_t*>(
- raw + 2 * sizeof(address) + sizeof(source_file_id)));
+ void CopyFrom(const char* raw) {
+ DESERIALIZE(raw, address);
+ DESERIALIZE(raw, size);
+ DESERIALIZE(raw, source_file_id);
+ DESERIALIZE(raw, line);
}
};
struct FastSourceLineResolver::Function :
public SourceLineResolverBase::Function {
- void CopyFrom(const Function *func_ptr) {
- const char *raw = reinterpret_cast<const char*>(func_ptr);
+ void CopyFrom(const Function* func_ptr) {
+ const char* raw = reinterpret_cast<const char*>(func_ptr);
CopyFrom(raw);
}
// De-serialize the memory data of a Function.
- void CopyFrom(const char *raw) {
+ void CopyFrom(const char* raw) {
size_t name_size = strlen(raw) + 1;
name = raw;
- address = *(reinterpret_cast<const MemAddr*>(raw + name_size));
- size = *(reinterpret_cast<const MemAddr*>(
- raw + name_size + sizeof(MemAddr)));
- parameter_size = *(reinterpret_cast<const int32_t*>(
- raw + name_size + 2 * sizeof(MemAddr)));
- lines = StaticRangeMap<MemAddr, Line>(
- raw + name_size + 2 * sizeof(MemAddr) + sizeof(int32_t));
+ raw += name_size;
+ DESERIALIZE(raw, address);
+ DESERIALIZE(raw, size);
+ DESERIALIZE(raw, parameter_size);
+ raw = SimpleSerializer<bool>::Read(raw, &is_multiple);
+ int32_t inline_size;
+ DESERIALIZE(raw, inline_size);
+ inlines = StaticContainedRangeMap<MemAddr, char>(raw);
+ lines = StaticRangeMap<MemAddr, Line>(raw + inline_size);
}
+ StaticContainedRangeMap<MemAddr, char> inlines;
StaticRangeMap<MemAddr, Line> lines;
};
+struct FastSourceLineResolver::Inline : public SourceLineResolverBase::Inline {
+ void CopyFrom(const Inline* inline_ptr) {
+ const char* raw = reinterpret_cast<const char*>(inline_ptr);
+ CopyFrom(raw);
+ }
+
+ // De-serialize the memory data of a Inline.
+ void CopyFrom(const char* raw) {
+ DESERIALIZE(raw, has_call_site_file_id);
+ DESERIALIZE(raw, inline_nest_level);
+ DESERIALIZE(raw, call_site_line);
+ DESERIALIZE(raw, call_site_file_id);
+ DESERIALIZE(raw, origin_id);
+ uint32_t inline_range_size;
+ DESERIALIZE(raw, inline_range_size);
+ for (size_t i = 0; i < inline_range_size; i += 2) {
+ std::pair<MemAddr, MemAddr> range;
+ DESERIALIZE(raw, range.first);
+ DESERIALIZE(raw, range.second);
+ inline_ranges.push_back(range);
+ }
+ }
+};
+
+struct FastSourceLineResolver::InlineOrigin
+ : public SourceLineResolverBase::InlineOrigin {
+ void CopyFrom(const InlineOrigin* origin_ptr) {
+ const char* raw = reinterpret_cast<const char*>(origin_ptr);
+ CopyFrom(raw);
+ }
+
+ // De-serialize the memory data of a Line.
+ void CopyFrom(const char* raw) {
+ DESERIALIZE(raw, has_file_id);
+ DESERIALIZE(raw, source_file_id);
+ name = raw;
+ }
+};
+
struct FastSourceLineResolver::PublicSymbol :
public SourceLineResolverBase::PublicSymbol {
- void CopyFrom(const PublicSymbol *public_symbol_ptr) {
- const char *raw = reinterpret_cast<const char*>(public_symbol_ptr);
+ void CopyFrom(const PublicSymbol* public_symbol_ptr) {
+ const char* raw = reinterpret_cast<const char*>(public_symbol_ptr);
CopyFrom(raw);
}
// De-serialize the memory data of a PublicSymbol.
- void CopyFrom(const char *raw) {
+ void CopyFrom(const char* raw) {
size_t name_size = strlen(raw) + 1;
name = raw;
- address = *(reinterpret_cast<const MemAddr*>(raw + name_size));
- parameter_size = *(reinterpret_cast<const int32_t*>(
- raw + name_size + sizeof(MemAddr)));
+ raw += name_size;
+ DESERIALIZE(raw, address);
+ DESERIALIZE(raw, parameter_size);
+ raw = SimpleSerializer<bool>::Read(raw, &is_multiple);
}
};
+#undef DESERIALIZE
+
class FastSourceLineResolver::Module: public SourceLineResolverBase::Module {
public:
- explicit Module(const string &name) : name_(name), is_corrupt_(false) { }
+ explicit Module(const string& name) : name_(name), is_corrupt_(false) { }
virtual ~Module() { }
// Looks up the given relative address, and fills the StackFrame struct
// with the result.
- virtual void LookupAddress(StackFrame *frame) const;
+ virtual void LookupAddress(
+ StackFrame* frame,
+ std::deque<std::unique_ptr<StackFrame>>* inlined_frames) const;
+
+ // Construct inlined frames for |frame| and store them in |inline_frames|.
+ // |frame|'s source line and source file name may be updated if an inlined
+ // frame is found inside |frame|. As a result, the innermost inlined frame
+ // will be the first one in |inline_frames|.
+ virtual void ConstructInlineFrames(
+ StackFrame* frame,
+ MemAddr address,
+ const StaticContainedRangeMap<MemAddr, char>& inline_map,
+ std::deque<std::unique_ptr<StackFrame>>* inlined_frames) const;
// Loads a map from the given buffer in char* type.
- virtual bool LoadMapFromMemory(char *memory_buffer,
+ virtual bool LoadMapFromMemory(char* memory_buffer,
size_t memory_buffer_size);
// Tells whether the loaded symbol data is corrupt. Return value is
@@ -132,16 +192,16 @@ class FastSourceLineResolver::Module: public SourceLineResolverBase::Module {
// is not available, returns NULL. A NULL return value does not indicate
// an error. The caller takes ownership of any returned WindowsFrameInfo
// object.
- virtual WindowsFrameInfo *FindWindowsFrameInfo(const StackFrame *frame) const;
+ virtual WindowsFrameInfo* FindWindowsFrameInfo(const StackFrame* frame) const;
// If CFI stack walking information is available covering ADDRESS,
// return a CFIFrameInfo structure describing it. If the information
// is not available, return NULL. The caller takes ownership of any
// returned CFIFrameInfo object.
- virtual CFIFrameInfo *FindCFIFrameInfo(const StackFrame *frame) const;
+ virtual CFIFrameInfo* FindCFIFrameInfo(const StackFrame* frame) const;
// Number of serialized map components of Module.
- static const int kNumberMaps_ = 5 + WindowsFrameInfo::STACK_INFO_LAST;
+ static const int kNumberMaps_ = 6 + WindowsFrameInfo::STACK_INFO_LAST;
private:
friend class FastSourceLineResolver;
@@ -178,6 +238,10 @@ class FastSourceLineResolver::Module: public SourceLineResolverBase::Module {
// this map, or the end of the range as given by the cfi_initial_rules_
// entry (which FindCFIFrameInfo looks up first).
StaticMap<MemAddr, char> cfi_delta_rules_;
+
+ // INLINE_ORIGIN records: used as a function name string pool for INLINE
+ // records.
+ StaticMap<int, char> inline_origins_;
};
} // namespace google_breakpad
diff --git a/src/processor/fast_source_line_resolver_unittest.cc b/src/processor/fast_source_line_resolver_unittest.cc
index 87b13c52..1bb35019 100644
--- a/src/processor/fast_source_line_resolver_unittest.cc
+++ b/src/processor/fast_source_line_resolver_unittest.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2010 Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -64,7 +63,6 @@ using google_breakpad::CodeModule;
using google_breakpad::MemoryRegion;
using google_breakpad::StackFrame;
using google_breakpad::WindowsFrameInfo;
-using google_breakpad::linked_ptr;
using google_breakpad::scoped_ptr;
class TestCodeModule : public CodeModule {
@@ -94,15 +92,15 @@ class TestCodeModule : public CodeModule {
class MockMemoryRegion: public MemoryRegion {
uint64_t GetBase() const { return 0x10000; }
uint32_t GetSize() const { return 0x01000; }
- bool GetMemoryAtAddress(uint64_t address, uint8_t *value) const {
+ bool GetMemoryAtAddress(uint64_t address, uint8_t* value) const {
*value = address & 0xff;
return true;
}
- bool GetMemoryAtAddress(uint64_t address, uint16_t *value) const {
+ bool GetMemoryAtAddress(uint64_t address, uint16_t* value) const {
*value = address & 0xffff;
return true;
}
- bool GetMemoryAtAddress(uint64_t address, uint32_t *value) const {
+ bool GetMemoryAtAddress(uint64_t address, uint32_t* value) const {
switch (address) {
case 0x10008: *value = 0x98ecadc3; break; // saved %ebx
case 0x1000c: *value = 0x878f7524; break; // saved %esi
@@ -113,7 +111,7 @@ class MockMemoryRegion: public MemoryRegion {
}
return true;
}
- bool GetMemoryAtAddress(uint64_t address, uint64_t *value) const {
+ bool GetMemoryAtAddress(uint64_t address, uint64_t* value) const {
*value = address;
return true;
}
@@ -127,9 +125,9 @@ class MockMemoryRegion: public MemoryRegion {
// EXPECTED's.) Also verify that ACTUAL has associations for ".ra" and
// ".cfa".
static bool VerifyRegisters(
- const char *file, int line,
- const CFIFrameInfo::RegisterValueMap<uint32_t> &expected,
- const CFIFrameInfo::RegisterValueMap<uint32_t> &actual) {
+ const char* file, int line,
+ const CFIFrameInfo::RegisterValueMap<uint32_t>& expected,
+ const CFIFrameInfo::RegisterValueMap<uint32_t>& actual) {
CFIFrameInfo::RegisterValueMap<uint32_t>::const_iterator a;
a = actual.find(".cfa");
if (a == actual.end())
@@ -158,7 +156,7 @@ static bool VerifyRegisters(
return true;
}
-static bool VerifyEmpty(const StackFrame &frame) {
+static bool VerifyEmpty(const StackFrame& frame) {
if (frame.function_name.empty() &&
frame.source_file_name.empty() &&
frame.source_line == 0)
@@ -166,7 +164,7 @@ static bool VerifyEmpty(const StackFrame &frame) {
return false;
}
-static void ClearSourceLineInfo(StackFrame *frame) {
+static void ClearSourceLineInfo(StackFrame* frame) {
frame->function_name.clear();
frame->module = NULL;
frame->source_file_name.clear();
@@ -217,16 +215,17 @@ TEST_F(TestFastSourceLineResolver, TestLoadAndResolve) {
scoped_ptr<CFIFrameInfo> cfi_frame_info;
frame.instruction = 0x1000;
frame.module = NULL;
- fast_resolver.FillSourceLineInfo(&frame);
+ fast_resolver.FillSourceLineInfo(&frame, nullptr);
ASSERT_FALSE(frame.module);
ASSERT_TRUE(frame.function_name.empty());
ASSERT_EQ(frame.function_base, 0U);
ASSERT_TRUE(frame.source_file_name.empty());
ASSERT_EQ(frame.source_line, 0);
ASSERT_EQ(frame.source_line_base, 0U);
+ ASSERT_EQ(frame.is_multiple, false);
frame.module = &module1;
- fast_resolver.FillSourceLineInfo(&frame);
+ fast_resolver.FillSourceLineInfo(&frame, nullptr);
ASSERT_EQ(frame.function_name, "Function1_1");
ASSERT_TRUE(frame.module);
ASSERT_EQ(frame.module->code_file(), "module1");
@@ -234,6 +233,7 @@ TEST_F(TestFastSourceLineResolver, TestLoadAndResolve) {
ASSERT_EQ(frame.source_file_name, "file1_1.cc");
ASSERT_EQ(frame.source_line, 44);
ASSERT_EQ(frame.source_line_base, 0x1000U);
+ ASSERT_EQ(frame.is_multiple, true);
windows_frame_info.reset(fast_resolver.FindWindowsFrameInfo(&frame));
ASSERT_TRUE(windows_frame_info.get());
ASSERT_FALSE(windows_frame_info->allocates_base_pointer);
@@ -243,13 +243,13 @@ TEST_F(TestFastSourceLineResolver, TestLoadAndResolve) {
ClearSourceLineInfo(&frame);
frame.instruction = 0x800;
frame.module = &module1;
- fast_resolver.FillSourceLineInfo(&frame);
+ fast_resolver.FillSourceLineInfo(&frame, nullptr);
ASSERT_TRUE(VerifyEmpty(frame));
windows_frame_info.reset(fast_resolver.FindWindowsFrameInfo(&frame));
ASSERT_FALSE(windows_frame_info.get());
frame.instruction = 0x1280;
- fast_resolver.FillSourceLineInfo(&frame);
+ fast_resolver.FillSourceLineInfo(&frame, nullptr);
ASSERT_EQ(frame.function_name, "Function1_3");
ASSERT_TRUE(frame.source_file_name.empty());
ASSERT_EQ(frame.source_line, 0);
@@ -260,7 +260,7 @@ TEST_F(TestFastSourceLineResolver, TestLoadAndResolve) {
ASSERT_TRUE(windows_frame_info->program_string.empty());
frame.instruction = 0x1380;
- fast_resolver.FillSourceLineInfo(&frame);
+ fast_resolver.FillSourceLineInfo(&frame, nullptr);
ASSERT_EQ(frame.function_name, "Function1_4");
ASSERT_TRUE(frame.source_file_name.empty());
ASSERT_EQ(frame.source_line, 0);
@@ -369,17 +369,18 @@ TEST_F(TestFastSourceLineResolver, TestLoadAndResolve) {
frame.instruction = 0x2900;
frame.module = &module1;
- fast_resolver.FillSourceLineInfo(&frame);
+ fast_resolver.FillSourceLineInfo(&frame, nullptr);
ASSERT_EQ(frame.function_name, string("PublicSymbol"));
+ EXPECT_EQ(frame.is_multiple, true);
frame.instruction = 0x4000;
frame.module = &module1;
- fast_resolver.FillSourceLineInfo(&frame);
+ fast_resolver.FillSourceLineInfo(&frame, nullptr);
ASSERT_EQ(frame.function_name, string("LargeFunction"));
frame.instruction = 0x2181;
frame.module = &module2;
- fast_resolver.FillSourceLineInfo(&frame);
+ fast_resolver.FillSourceLineInfo(&frame, nullptr);
ASSERT_EQ(frame.function_name, "Function2_2");
ASSERT_EQ(frame.function_base, 0x2170U);
ASSERT_TRUE(frame.module);
@@ -387,27 +388,133 @@ TEST_F(TestFastSourceLineResolver, TestLoadAndResolve) {
ASSERT_EQ(frame.source_file_name, "file2_2.cc");
ASSERT_EQ(frame.source_line, 21);
ASSERT_EQ(frame.source_line_base, 0x2180U);
+ ASSERT_EQ(frame.is_multiple, false);
windows_frame_info.reset(fast_resolver.FindWindowsFrameInfo(&frame));
ASSERT_TRUE(windows_frame_info.get());
ASSERT_EQ(windows_frame_info->type_, WindowsFrameInfo::STACK_INFO_FRAME_DATA);
ASSERT_EQ(windows_frame_info->prolog_size, 1U);
frame.instruction = 0x216f;
- fast_resolver.FillSourceLineInfo(&frame);
+ fast_resolver.FillSourceLineInfo(&frame, nullptr);
ASSERT_EQ(frame.function_name, "Public2_1");
+ EXPECT_EQ(frame.is_multiple, false);
ClearSourceLineInfo(&frame);
frame.instruction = 0x219f;
frame.module = &module2;
- fast_resolver.FillSourceLineInfo(&frame);
+ fast_resolver.FillSourceLineInfo(&frame, nullptr);
ASSERT_TRUE(frame.function_name.empty());
frame.instruction = 0x21a0;
frame.module = &module2;
- fast_resolver.FillSourceLineInfo(&frame);
+ fast_resolver.FillSourceLineInfo(&frame, nullptr);
ASSERT_EQ(frame.function_name, "Public2_2");
}
+// Test adapted from basic_source_line_resolver_unittest.
+TEST_F(TestFastSourceLineResolver, TestLoadAndResolveOldInlines) {
+ TestCodeModule module("linux_inline");
+ ASSERT_TRUE(basic_resolver.LoadModule(
+ &module, testdata_dir +
+ "/symbols/linux_inline/BBA6FA10B8AAB33D00000000000000000/"
+ "linux_inline.old.sym"));
+ ASSERT_TRUE(basic_resolver.HasModule(&module));
+ // Convert module1 to fast_module:
+ ASSERT_TRUE(serializer.ConvertOneModule(module.code_file(), &basic_resolver,
+ &fast_resolver));
+ ASSERT_TRUE(fast_resolver.HasModule(&module));
+
+ StackFrame frame;
+ std::deque<std::unique_ptr<StackFrame>> inlined_frames;
+ frame.instruction = 0x161b6;
+ frame.module = &module;
+ fast_resolver.FillSourceLineInfo(&frame, &inlined_frames);
+
+ // main frame.
+ ASSERT_EQ(frame.function_name, "main");
+ ASSERT_EQ(frame.function_base, 0x15b30U);
+ ASSERT_EQ(frame.source_file_name, "linux_inline.cpp");
+ ASSERT_EQ(frame.source_line, 42);
+ ASSERT_EQ(frame.source_line_base, 0x161b6U);
+ ASSERT_EQ(frame.is_multiple, false);
+
+ ASSERT_EQ(inlined_frames.size(), 3UL);
+
+ // Inlined frames inside main frame.
+ ASSERT_EQ(inlined_frames[2]->function_name, "foo()");
+ ASSERT_EQ(inlined_frames[2]->function_base, 0x15b45U);
+ ASSERT_EQ(inlined_frames[2]->source_file_name, "linux_inline.cpp");
+ ASSERT_EQ(inlined_frames[2]->source_line, 39);
+ ASSERT_EQ(inlined_frames[2]->source_line_base, 0x161b6U);
+ ASSERT_EQ(inlined_frames[2]->trust, StackFrame::FRAME_TRUST_INLINE);
+
+ ASSERT_EQ(inlined_frames[1]->function_name, "bar()");
+ ASSERT_EQ(inlined_frames[1]->function_base, 0x15b72U);
+ ASSERT_EQ(inlined_frames[1]->source_file_name, "linux_inline.cpp");
+ ASSERT_EQ(inlined_frames[1]->source_line, 32);
+ ASSERT_EQ(inlined_frames[1]->source_line_base, 0x161b6U);
+ ASSERT_EQ(inlined_frames[1]->trust, StackFrame::FRAME_TRUST_INLINE);
+
+ ASSERT_EQ(inlined_frames[0]->function_name, "func()");
+ ASSERT_EQ(inlined_frames[0]->function_base, 0x15b83U);
+ ASSERT_EQ(inlined_frames[0]->source_file_name, "linux_inline.cpp");
+ ASSERT_EQ(inlined_frames[0]->source_line, 27);
+ ASSERT_EQ(inlined_frames[0]->source_line_base, 0x161b6U);
+ ASSERT_EQ(inlined_frames[0]->trust, StackFrame::FRAME_TRUST_INLINE);
+}
+
+// Test adapted from basic_source_line_resolver_unittest.
+TEST_F(TestFastSourceLineResolver, TestLoadAndResolveNewInlines) {
+ TestCodeModule module("linux_inline");
+ ASSERT_TRUE(basic_resolver.LoadModule(
+ &module, testdata_dir +
+ "/symbols/linux_inline/BBA6FA10B8AAB33D00000000000000000/"
+ "linux_inline.new.sym"));
+ ASSERT_TRUE(basic_resolver.HasModule(&module));
+ // Convert module1 to fast_module:
+ ASSERT_TRUE(serializer.ConvertOneModule(module.code_file(), &basic_resolver,
+ &fast_resolver));
+ ASSERT_TRUE(fast_resolver.HasModule(&module));
+
+ StackFrame frame;
+ std::deque<std::unique_ptr<StackFrame>> inlined_frames;
+ frame.instruction = 0x161b6;
+ frame.module = &module;
+ fast_resolver.FillSourceLineInfo(&frame, &inlined_frames);
+
+ // main frame.
+ ASSERT_EQ(frame.function_name, "main");
+ ASSERT_EQ(frame.function_base, 0x15b30U);
+ ASSERT_EQ(frame.source_file_name, "a.cpp");
+ ASSERT_EQ(frame.source_line, 42);
+ ASSERT_EQ(frame.source_line_base, 0x161b6U);
+ ASSERT_EQ(frame.is_multiple, false);
+
+ ASSERT_EQ(inlined_frames.size(), 3UL);
+
+ // Inlined frames inside main frame.
+ ASSERT_EQ(inlined_frames[2]->function_name, "foo()");
+ ASSERT_EQ(inlined_frames[2]->function_base, 0x15b45U);
+ ASSERT_EQ(inlined_frames[2]->source_file_name, "b.cpp");
+ ASSERT_EQ(inlined_frames[2]->source_line, 39);
+ ASSERT_EQ(inlined_frames[2]->source_line_base, 0x161b6U);
+ ASSERT_EQ(inlined_frames[2]->trust, StackFrame::FRAME_TRUST_INLINE);
+
+ ASSERT_EQ(inlined_frames[1]->function_name, "bar()");
+ ASSERT_EQ(inlined_frames[1]->function_base, 0x15b72U);
+ ASSERT_EQ(inlined_frames[1]->source_file_name, "c.cpp");
+ ASSERT_EQ(inlined_frames[1]->source_line, 32);
+ ASSERT_EQ(inlined_frames[1]->source_line_base, 0x161b6U);
+ ASSERT_EQ(inlined_frames[1]->trust, StackFrame::FRAME_TRUST_INLINE);
+
+ ASSERT_EQ(inlined_frames[0]->function_name, "func()");
+ ASSERT_EQ(inlined_frames[0]->function_base, 0x15b83U);
+ ASSERT_EQ(inlined_frames[0]->source_file_name, "linux_inline.cpp");
+ ASSERT_EQ(inlined_frames[0]->source_line, 27);
+ ASSERT_EQ(inlined_frames[0]->source_line_base, 0x161b6U);
+ ASSERT_EQ(inlined_frames[0]->trust, StackFrame::FRAME_TRUST_INLINE);
+}
+
TEST_F(TestFastSourceLineResolver, TestInvalidLoads) {
TestCodeModule module3("module3");
ASSERT_TRUE(basic_resolver.LoadModule(&module3,
@@ -467,7 +574,7 @@ TEST_F(TestFastSourceLineResolver, TestUnload) {
}
TEST_F(TestFastSourceLineResolver, CompareModule) {
- char *symbol_data;
+ char* symbol_data;
size_t symbol_data_size;
string symbol_data_string;
string filename;
@@ -486,7 +593,7 @@ TEST_F(TestFastSourceLineResolver, CompareModule) {
} // namespace
-int main(int argc, char *argv[]) {
+int main(int argc, char* argv[]) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
diff --git a/src/processor/linked_ptr.h b/src/processor/linked_ptr.h
index 72fbba84..5de49ee9 100644
--- a/src/processor/linked_ptr.h
+++ b/src/processor/linked_ptr.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2006, Google Inc.
-// All rights reserved.
+// Copyright 2006 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/processor/logging.cc b/src/processor/logging.cc
index d59175a7..136f4f8f 100644
--- a/src/processor/logging.cc
+++ b/src/processor/logging.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2007, Google Inc.
-// All rights reserved.
+// Copyright 2007 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -47,8 +46,8 @@
namespace google_breakpad {
-LogStream::LogStream(std::ostream &stream, Severity severity,
- const char *file, int line)
+LogStream::LogStream(std::ostream& stream, Severity severity,
+ const char* file, int line)
: stream_(stream) {
time_t clock;
time(&clock);
@@ -61,7 +60,7 @@ LogStream::LogStream(std::ostream &stream, Severity severity,
char time_string[20];
strftime(time_string, sizeof(time_string), "%Y-%m-%d %H:%M:%S", &tm_struct);
- const char *severity_string = "UNKNOWN_SEVERITY";
+ const char* severity_string = "UNKNOWN_SEVERITY";
switch (severity) {
case SEVERITY_INFO:
severity_string = "INFO";
@@ -100,7 +99,7 @@ string HexString(int number) {
return string(buffer);
}
-int ErrnoString(string *error_string) {
+int ErrnoString(string* error_string) {
assert(error_string);
// strerror isn't necessarily thread-safe. strerror_r would be preferrable,
diff --git a/src/processor/logging.h b/src/processor/logging.h
index a9f30920..8c040837 100644
--- a/src/processor/logging.h
+++ b/src/processor/logging.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2007, Google Inc.
-// All rights reserved.
+// Copyright 2007 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -67,18 +66,6 @@
#include BP_LOGGING_INCLUDE
#endif // BP_LOGGING_INCLUDE
-#ifndef THIRD_PARTY_BREAKPAD_GOOGLE_GLUE_LOGGING_H_
-namespace base_logging {
-
-// The open-source copy of logging.h has diverged from Google's internal copy
-// (temporarily, at least). To support the transition to structured logging
-// a definition for base_logging::LogMessage is needed, which is a ostream-
-// like object for streaming arguments to construct a log message.
-typedef std::ostream LogMessage;
-
-} // namespace base_logging
-#endif // THIRD_PARTY_BREAKPAD_GOOGLE_GLUE_LOGGING_H_
-
namespace google_breakpad {
// These are defined in Microsoft headers.
@@ -101,22 +88,22 @@ class LogStream {
// Begin logging a message to the stream identified by |stream|, at the
// indicated severity. The file and line parameters should be set so as to
// identify the line of source code that is producing a message.
- LogStream(std::ostream &stream, Severity severity,
- const char *file, int line);
+ LogStream(std::ostream& stream, Severity severity,
+ const char* file, int line);
// Finish logging by printing a newline and flushing the output stream.
~LogStream();
- template<typename T> std::ostream& operator<<(const T &t) {
+ template<typename T> std::ostream& operator<<(const T& t) {
return stream_ << t;
}
private:
- std::ostream &stream_;
+ std::ostream& stream_;
// Disallow copy constructor and assignment operator
- explicit LogStream(const LogStream &that);
- void operator=(const LogStream &that);
+ explicit LogStream(const LogStream& that);
+ void operator=(const LogStream& that);
};
// This class is used to explicitly ignore values in the conditional logging
@@ -128,7 +115,7 @@ class LogMessageVoidify {
// This has to be an operator with a precedence lower than << but higher
// than ?:
- void operator&(base_logging::LogMessage &) {}
+ void operator&(std::ostream&) {}
};
// Returns number formatted as a hexadecimal string, such as "0x7b".
@@ -139,7 +126,7 @@ string HexString(int number);
// Returns the error code as set in the global errno variable, and sets
// error_string, a required argument, to a string describing that error
// code.
-int ErrnoString(string *error_string);
+int ErrnoString(string* error_string);
} // namespace google_breakpad
diff --git a/src/processor/map_serializers-inl.h b/src/processor/map_serializers-inl.h
index 61c7bbd7..577b95f7 100644
--- a/src/processor/map_serializers-inl.h
+++ b/src/processor/map_serializers-inl.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2010, Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -53,7 +52,7 @@ namespace google_breakpad {
template<typename Key, typename Value>
size_t StdMapSerializer<Key, Value>::SizeOf(
- const std::map<Key, Value> &m) const {
+ const std::map<Key, Value>& m) const {
size_t size = 0;
size_t header_size = (1 + m.size()) * sizeof(uint32_t);
size += header_size;
@@ -67,22 +66,22 @@ size_t StdMapSerializer<Key, Value>::SizeOf(
}
template<typename Key, typename Value>
-char *StdMapSerializer<Key, Value>::Write(const std::map<Key, Value> &m,
- char *dest) const {
+char* StdMapSerializer<Key, Value>::Write(const std::map<Key, Value>& m,
+ char* dest) const {
if (!dest) {
BPLOG(ERROR) << "StdMapSerializer failed: write to NULL address.";
return NULL;
}
- char *start_address = dest;
+ char* start_address = dest;
// Write header:
// Number of nodes.
dest = SimpleSerializer<uint32_t>::Write(m.size(), dest);
// Nodes offsets.
- uint32_t *offsets = reinterpret_cast<uint32_t*>(dest);
+ uint32_t* offsets = reinterpret_cast<uint32_t*>(dest);
dest += sizeof(uint32_t) * m.size();
- char *key_address = dest;
+ char* key_address = dest;
dest += sizeof(Key) * m.size();
// Traverse map.
@@ -97,12 +96,12 @@ char *StdMapSerializer<Key, Value>::Write(const std::map<Key, Value> &m,
}
template<typename Key, typename Value>
-char *StdMapSerializer<Key, Value>::Serialize(
- const std::map<Key, Value> &m, unsigned int *size) const {
+char* StdMapSerializer<Key, Value>::Serialize(
+ const std::map<Key, Value>& m, unsigned int* size) const {
// Compute size of memory to be allocated.
unsigned int size_to_alloc = SizeOf(m);
// Allocate memory.
- char *serialized_data = new char[size_to_alloc];
+ char* serialized_data = new char[size_to_alloc];
if (!serialized_data) {
BPLOG(INFO) << "StdMapSerializer memory allocation failed.";
if (size) *size = 0;
@@ -117,7 +116,7 @@ char *StdMapSerializer<Key, Value>::Serialize(
template<typename Address, typename Entry>
size_t RangeMapSerializer<Address, Entry>::SizeOf(
- const RangeMap<Address, Entry> &m) const {
+ const RangeMap<Address, Entry>& m) const {
size_t size = 0;
size_t header_size = (1 + m.map_.size()) * sizeof(uint32_t);
size += header_size;
@@ -135,22 +134,22 @@ size_t RangeMapSerializer<Address, Entry>::SizeOf(
}
template<typename Address, typename Entry>
-char *RangeMapSerializer<Address, Entry>::Write(
- const RangeMap<Address, Entry> &m, char *dest) const {
+char* RangeMapSerializer<Address, Entry>::Write(
+ const RangeMap<Address, Entry>& m, char* dest) const {
if (!dest) {
BPLOG(ERROR) << "RangeMapSerializer failed: write to NULL address.";
return NULL;
}
- char *start_address = dest;
+ char* start_address = dest;
// Write header:
// Number of nodes.
dest = SimpleSerializer<uint32_t>::Write(m.map_.size(), dest);
// Nodes offsets.
- uint32_t *offsets = reinterpret_cast<uint32_t*>(dest);
+ uint32_t* offsets = reinterpret_cast<uint32_t*>(dest);
dest += sizeof(uint32_t) * m.map_.size();
- char *key_address = dest;
+ char* key_address = dest;
dest += sizeof(Address) * m.map_.size();
// Traverse map.
@@ -166,12 +165,12 @@ char *RangeMapSerializer<Address, Entry>::Write(
}
template<typename Address, typename Entry>
-char *RangeMapSerializer<Address, Entry>::Serialize(
- const RangeMap<Address, Entry> &m, unsigned int *size) const {
+char* RangeMapSerializer<Address, Entry>::Serialize(
+ const RangeMap<Address, Entry>& m, unsigned int* size) const {
// Compute size of memory to be allocated.
unsigned int size_to_alloc = SizeOf(m);
// Allocate memory.
- char *serialized_data = new char[size_to_alloc];
+ char* serialized_data = new char[size_to_alloc];
if (!serialized_data) {
BPLOG(INFO) << "RangeMapSerializer memory allocation failed.";
if (size) *size = 0;
@@ -188,7 +187,7 @@ char *RangeMapSerializer<Address, Entry>::Serialize(
template<class AddrType, class EntryType>
size_t ContainedRangeMapSerializer<AddrType, EntryType>::SizeOf(
- const ContainedRangeMap<AddrType, EntryType> *m) const {
+ const ContainedRangeMap<AddrType, EntryType>* m) const {
size_t size = 0;
size_t header_size = addr_serializer_.SizeOf(m->base_)
+ entry_serializer_.SizeOf(m->entry_)
@@ -209,8 +208,8 @@ size_t ContainedRangeMapSerializer<AddrType, EntryType>::SizeOf(
}
template<class AddrType, class EntryType>
-char *ContainedRangeMapSerializer<AddrType, EntryType>::Write(
- const ContainedRangeMap<AddrType, EntryType> *m, char *dest) const {
+char* ContainedRangeMapSerializer<AddrType, EntryType>::Write(
+ const ContainedRangeMap<AddrType, EntryType>* m, char* dest) const {
if (!dest) {
BPLOG(ERROR) << "StdMapSerializer failed: write to NULL address.";
return NULL;
@@ -221,15 +220,15 @@ char *ContainedRangeMapSerializer<AddrType, EntryType>::Write(
dest = entry_serializer_.Write(m->entry_, dest);
// Write map<<AddrType, ContainedRangeMap*>:
- char *map_address = dest;
+ char* map_address = dest;
if (m->map_ == NULL) {
dest = SimpleSerializer<uint32_t>::Write(0, dest);
} else {
dest = SimpleSerializer<uint32_t>::Write(m->map_->size(), dest);
- uint32_t *offsets = reinterpret_cast<uint32_t*>(dest);
+ uint32_t* offsets = reinterpret_cast<uint32_t*>(dest);
dest += sizeof(uint32_t) * m->map_->size();
- char *key_address = dest;
+ char* key_address = dest;
dest += sizeof(AddrType) * m->map_->size();
// Traverse map.
@@ -246,11 +245,11 @@ char *ContainedRangeMapSerializer<AddrType, EntryType>::Write(
}
template<class AddrType, class EntryType>
-char *ContainedRangeMapSerializer<AddrType, EntryType>::Serialize(
- const ContainedRangeMap<AddrType, EntryType> *m, unsigned int *size) const {
+char* ContainedRangeMapSerializer<AddrType, EntryType>::Serialize(
+ const ContainedRangeMap<AddrType, EntryType>* m, unsigned int* size) const {
unsigned int size_to_alloc = SizeOf(m);
// Allocating memory.
- char *serialized_data = new char[size_to_alloc];
+ char* serialized_data = new char[size_to_alloc];
if (!serialized_data) {
BPLOG(INFO) << "ContainedRangeMapSerializer memory allocation failed.";
if (size) *size = 0;
diff --git a/src/processor/map_serializers.h b/src/processor/map_serializers.h
index a0b9d3fd..54153f8a 100644
--- a/src/processor/map_serializers.h
+++ b/src/processor/map_serializers.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2010, Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -53,20 +52,20 @@ template<typename Key, typename Value>
class StdMapSerializer {
public:
// Calculate the memory size of serialized data.
- size_t SizeOf(const std::map<Key, Value> &m) const;
+ size_t SizeOf(const std::map<Key, Value>& m) const;
// Writes the serialized data to memory with start address = dest,
// and returns the "end" of data, i.e., return the address follow the final
// byte of data.
// NOTE: caller has to allocate enough memory before invoke Write() method.
- char* Write(const std::map<Key, Value> &m, char* dest) const;
+ char* Write(const std::map<Key, Value>& m, char* dest) const;
// Serializes a std::map object into a chunk of memory data with format
// described in "StaticMap.h" comment.
// Returns a pointer to the serialized data. If size != NULL, *size is set
// to the size of serialized data, i.e., SizeOf(m).
// Caller has the ownership of memory allocated as "new char[]".
- char* Serialize(const std::map<Key, Value> &m, unsigned int *size) const;
+ char* Serialize(const std::map<Key, Value>& m, unsigned int* size) const;
private:
SimpleSerializer<Key> key_serializer_;
@@ -79,14 +78,14 @@ template<typename Addr, typename Entry>
class AddressMapSerializer {
public:
// Calculate the memory size of serialized data.
- size_t SizeOf(const AddressMap<Addr, Entry> &m) const {
+ size_t SizeOf(const AddressMap<Addr, Entry>& m) const {
return std_map_serializer_.SizeOf(m.map_);
}
// Write the serialized data to specified memory location. Return the "end"
// of data, i.e., return the address after the final byte of data.
// NOTE: caller has to allocate enough memory before invoke Write() method.
- char* Write(const AddressMap<Addr, Entry> &m, char *dest) const {
+ char* Write(const AddressMap<Addr, Entry>& m, char* dest) const {
return std_map_serializer_.Write(m.map_, dest);
}
@@ -94,7 +93,7 @@ class AddressMapSerializer {
// Returns a pointer to the serialized data. If size != NULL, *size is set
// to the size of serialized data, i.e., SizeOf(m).
// Caller has the ownership of memory allocated as "new char[]".
- char* Serialize(const AddressMap<Addr, Entry> &m, unsigned int *size) const {
+ char* Serialize(const AddressMap<Addr, Entry>& m, unsigned int* size) const {
return std_map_serializer_.Serialize(m.map_, size);
}
@@ -110,18 +109,18 @@ template<typename Address, typename Entry>
class RangeMapSerializer {
public:
// Calculate the memory size of serialized data.
- size_t SizeOf(const RangeMap<Address, Entry> &m) const;
+ size_t SizeOf(const RangeMap<Address, Entry>& m) const;
// Write the serialized data to specified memory location. Return the "end"
// of data, i.e., return the address after the final byte of data.
// NOTE: caller has to allocate enough memory before invoke Write() method.
- char* Write(const RangeMap<Address, Entry> &m, char* dest) const;
+ char* Write(const RangeMap<Address, Entry>& m, char* dest) const;
// Serializes a RangeMap object into a chunk of memory data.
// Returns a pointer to the serialized data. If size != NULL, *size is set
// to the size of serialized data, i.e., SizeOf(m).
// Caller has the ownership of memory allocated as "new char[]".
- char* Serialize(const RangeMap<Address, Entry> &m, unsigned int *size) const;
+ char* Serialize(const RangeMap<Address, Entry>& m, unsigned int* size) const;
private:
// Convenient type name for Range.
@@ -139,20 +138,20 @@ template<class AddrType, class EntryType>
class ContainedRangeMapSerializer {
public:
// Calculate the memory size of serialized data.
- size_t SizeOf(const ContainedRangeMap<AddrType, EntryType> *m) const;
+ size_t SizeOf(const ContainedRangeMap<AddrType, EntryType>* m) const;
// Write the serialized data to specified memory location. Return the "end"
// of data, i.e., return the address after the final byte of data.
// NOTE: caller has to allocate enough memory before invoke Write() method.
- char* Write(const ContainedRangeMap<AddrType, EntryType> *m,
+ char* Write(const ContainedRangeMap<AddrType, EntryType>* m,
char* dest) const;
// Serializes a ContainedRangeMap object into a chunk of memory data.
// Returns a pointer to the serialized data. If size != NULL, *size is set
// to the size of serialized data, i.e., SizeOf(m).
// Caller has the ownership of memory allocated as "new char[]".
- char* Serialize(const ContainedRangeMap<AddrType, EntryType> *m,
- unsigned int *size) const;
+ char* Serialize(const ContainedRangeMap<AddrType, EntryType>* m,
+ unsigned int* size) const;
private:
// Convenient type name for the underlying map type.
diff --git a/src/processor/map_serializers_unittest.cc b/src/processor/map_serializers_unittest.cc
index 0d872ec2..74ebd5e5 100644
--- a/src/processor/map_serializers_unittest.cc
+++ b/src/processor/map_serializers_unittest.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2010, Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -63,7 +62,7 @@ class TestStdMapSerializer : public ::testing::Test {
std::map<AddrType, EntryType> std_map_;
google_breakpad::StdMapSerializer<AddrType, EntryType> serializer_;
uint32_t serialized_size_;
- char *serialized_data_;
+ char* serialized_data_;
};
TEST_F(TestStdMapSerializer, EmptyMapTestCase) {
@@ -135,7 +134,7 @@ class TestAddressMapSerializer : public ::testing::Test {
google_breakpad::AddressMap<AddrType, EntryType> address_map_;
google_breakpad::AddressMapSerializer<AddrType, EntryType> serializer_;
uint32_t serialized_size_;
- char *serialized_data_;
+ char* serialized_data_;
};
TEST_F(TestAddressMapSerializer, EmptyMapTestCase) {
@@ -210,7 +209,7 @@ class TestRangeMapSerializer : public ::testing::Test {
google_breakpad::RangeMap<AddrType, EntryType> range_map_;
google_breakpad::RangeMapSerializer<AddrType, EntryType> serializer_;
uint32_t serialized_size_;
- char *serialized_data_;
+ char* serialized_data_;
};
TEST_F(TestRangeMapSerializer, EmptyMapTestCase) {
@@ -283,7 +282,7 @@ class TestContainedRangeMapSerializer : public ::testing::Test {
google_breakpad::ContainedRangeMap<AddrType, EntryType> crm_map_;
google_breakpad::ContainedRangeMapSerializer<AddrType, EntryType> serializer_;
uint32_t serialized_size_;
- char *serialized_data_;
+ char* serialized_data_;
};
TEST_F(TestContainedRangeMapSerializer, EmptyMapTestCase) {
@@ -379,7 +378,7 @@ TEST_F(TestContainedRangeMapSerializer, MapWithTwoLevelsTestCase) {
}
-int main(int argc, char *argv[]) {
+int main(int argc, char* argv[]) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
diff --git a/src/processor/microdump.cc b/src/processor/microdump.cc
index d8141a2a..83fb098c 100644
--- a/src/processor/microdump.cc
+++ b/src/processor/microdump.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2014 Google Inc.
-// All rights reserved.
+// Copyright 2014 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/processor/microdump_processor.cc b/src/processor/microdump_processor.cc
index 2d3a9558..be6150cd 100644
--- a/src/processor/microdump_processor.cc
+++ b/src/processor/microdump_processor.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2014, Google Inc.
-// All rights reserved.
+// Copyright 2014 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/processor/microdump_processor_unittest.cc b/src/processor/microdump_processor_unittest.cc
index 83bdef95..3362431b 100644
--- a/src/processor/microdump_processor_unittest.cc
+++ b/src/processor/microdump_processor_unittest.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2014, Google Inc.
-// All rights reserved.
+// Copyright 2014 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/processor/microdump_stackwalk.cc b/src/processor/microdump_stackwalk.cc
index 220396ed..593b07d6 100644
--- a/src/processor/microdump_stackwalk.cc
+++ b/src/processor/microdump_stackwalk.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2014 Google Inc.
-// All rights reserved.
+// Copyright 2014 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -110,7 +109,10 @@ int PrintMicrodumpProcess(const Options& options) {
if (options.machine_readable) {
PrintProcessStateMachineReadable(process_state);
} else {
- PrintProcessState(process_state, options.output_stack_contents, &resolver);
+ // Microdump has only one thread, |output_requesting_thread_only|'s value
+ // has no effect.
+ PrintProcessState(process_state, options.output_stack_contents,
+ /*output_requesting_thread_only=*/false, &resolver);
}
return 0;
}
@@ -140,7 +142,7 @@ static void SetupOptions(int argc, const char *argv[], Options* options) {
options->machine_readable = false;
options->output_stack_contents = false;
- while ((ch = getopt(argc, (char * const *)argv, "hms")) != -1) {
+ while ((ch = getopt(argc, (char * const*)argv, "hms")) != -1) {
switch (ch) {
case 'h':
Usage(argc, argv, false);
diff --git a/src/processor/microdump_stackwalk_machine_readable_test b/src/processor/microdump_stackwalk_machine_readable_test
index f5614e20..a0898466 100755
--- a/src/processor/microdump_stackwalk_machine_readable_test
+++ b/src/processor/microdump_stackwalk_machine_readable_test
@@ -1,7 +1,6 @@
#!/bin/sh
-# Copyright (c) 2014, Google Inc.
-# All rights reserved.
+# Copyright 2014 Google LLC
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
@@ -13,7 +12,7 @@
# copyright notice, this list of conditions and the following disclaimer
# in the documentation and/or other materials provided with the
# distribution.
-# * Neither the name of Google Inc. nor the names of its
+# * Neither the name of Google LLC nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
diff --git a/src/processor/microdump_stackwalk_test b/src/processor/microdump_stackwalk_test
index e1897656..cb895082 100755
--- a/src/processor/microdump_stackwalk_test
+++ b/src/processor/microdump_stackwalk_test
@@ -1,7 +1,6 @@
#!/bin/sh
-# Copyright (c) 2014, Google Inc.
-# All rights reserved.
+# Copyright 2014 Google LLC
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
@@ -13,7 +12,7 @@
# copyright notice, this list of conditions and the following disclaimer
# in the documentation and/or other materials provided with the
# distribution.
-# * Neither the name of Google Inc. nor the names of its
+# * Neither the name of Google LLC nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
diff --git a/src/processor/minidump.cc b/src/processor/minidump.cc
index 4c0b26ab..135770d5 100644
--- a/src/processor/minidump.cc
+++ b/src/processor/minidump.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2010 Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -37,6 +36,7 @@
#include <assert.h>
#include <fcntl.h>
+#include <inttypes.h>
#include <stddef.h>
#include <string.h>
#include <time.h>
@@ -96,6 +96,10 @@ bool IsContextSizeUnique(uint32_t context_size) {
num_matching_contexts++;
if (context_size == sizeof(MDRawContextMIPS))
num_matching_contexts++;
+ if (context_size == sizeof(MDRawContextRISCV))
+ num_matching_contexts++;
+ if (context_size == sizeof(MDRawContextRISCV64))
+ num_matching_contexts++;
return num_matching_contexts == 1;
}
@@ -212,6 +216,12 @@ inline void Swap(MDRawSimpleStringDictionaryEntry* entry) {
Swap(&entry->value);
}
+inline void Swap(MDRawCrashpadAnnotation* annotation) {
+ Swap(&annotation->name);
+ Swap(&annotation->type);
+ Swap(&annotation->value);
+}
+
inline void Swap(uint16_t* data, size_t size_in_bytes) {
size_t data_length = size_in_bytes / sizeof(data[0]);
for (size_t i = 0; i < data_length; i++) {
@@ -470,7 +480,16 @@ bool MinidumpContext::Read(uint32_t expected_size) {
// First, figure out what type of CPU this context structure is for.
// For some reason, the AMD64 Context doesn't have context_flags
// at the beginning of the structure, so special case it here.
- if (expected_size == sizeof(MDRawContextAMD64)) {
+
+ uint32_t sysinfo_cpu_type = 0;
+ if (!minidump_->GetContextCPUFlagsFromSystemInfo(&sysinfo_cpu_type)) {
+ BPLOG(ERROR) << "Failed to preserve the current stream position";
+ return false;
+ }
+
+ if (expected_size == sizeof(MDRawContextAMD64) ||
+ (sysinfo_cpu_type == MD_CONTEXT_AMD64 &&
+ expected_size >= sizeof(MDRawContextAMD64))) {
BPLOG(INFO) << "MinidumpContext: looks like AMD64 context";
scoped_ptr<MDRawContextAMD64> context_amd64(new MDRawContextAMD64());
@@ -480,17 +499,24 @@ bool MinidumpContext::Read(uint32_t expected_size) {
return false;
}
+ // Context may include xsave registers and so be larger than
+ // sizeof(MDRawContextAMD64). For now we skip this extended data.
+ if (expected_size > sizeof(MDRawContextAMD64)) {
+ size_t bytes_left = expected_size - sizeof(MDRawContextAMD64);
+ std::vector<uint8_t> xstate(bytes_left);
+ if (!minidump_->ReadBytes(xstate.data(),
+ bytes_left)) {
+ BPLOG(ERROR) << "MinidumpContext could not skip amd64 xstate";
+ return false;
+ }
+ }
+
if (minidump_->swap())
Swap(&context_amd64->context_flags);
uint32_t cpu_type = context_amd64->context_flags & MD_CONTEXT_CPU_MASK;
if (cpu_type == 0) {
- if (minidump_->GetContextCPUFlagsFromSystemInfo(&cpu_type)) {
- context_amd64->context_flags |= cpu_type;
- } else {
- BPLOG(ERROR) << "Failed to preserve the current stream position";
- return false;
- }
+ context_amd64->context_flags |= sysinfo_cpu_type;
}
if (cpu_type != MD_CONTEXT_AMD64) {
@@ -765,13 +791,10 @@ bool MinidumpContext::Read(uint32_t expected_size) {
}
}
+ // Fixup if we were not provided a cpu type.
if (cpu_type == 0) {
- if (minidump_->GetContextCPUFlagsFromSystemInfo(&cpu_type)) {
- context_flags |= cpu_type;
- } else {
- BPLOG(ERROR) << "Failed to preserve the current stream position";
- return false;
- }
+ cpu_type = sysinfo_cpu_type;
+ context_flags |= cpu_type;
}
// Allocate the context structure for the correct CPU and fill it. The
@@ -1157,13 +1180,169 @@ bool MinidumpContext::Read(uint32_t expected_size) {
break;
}
+ case MD_CONTEXT_RISCV: {
+ if (expected_size != sizeof(MDRawContextRISCV)) {
+ BPLOG(ERROR) << "MinidumpContext RISCV size mismatch, "
+ << expected_size
+ << " != "
+ << sizeof(MDRawContextRISCV);
+ return false;
+ }
+
+ scoped_ptr<MDRawContextRISCV> context_riscv(new MDRawContextRISCV());
+
+ // Set the context_flags member, which has already been read, and
+ // read the rest of the structure beginning with the first member
+ // after context_flags.
+ context_riscv->context_flags = context_flags;
+
+ size_t flags_size = sizeof(context_riscv->context_flags);
+ uint8_t* context_after_flags =
+ reinterpret_cast<uint8_t*>(context_riscv.get()) + flags_size;
+ if (!minidump_->ReadBytes(context_after_flags,
+ sizeof(MDRawContextRISCV) - flags_size)) {
+ BPLOG(ERROR) << "MinidumpContext could not read RISCV context";
+ return false;
+ }
+
+ // Do this after reading the entire MDRawContext structure because
+ // GetSystemInfo may seek minidump to a new position.
+ if (!CheckAgainstSystemInfo(cpu_type)) {
+ BPLOG(ERROR) << "MinidumpContext RISCV does not match system info";
+ return false;
+ }
+
+ if (minidump_->swap()) {
+ Swap(&context_riscv->pc);
+ Swap(&context_riscv->ra);
+ Swap(&context_riscv->sp);
+ Swap(&context_riscv->gp);
+ Swap(&context_riscv->tp);
+ Swap(&context_riscv->t0);
+ Swap(&context_riscv->t1);
+ Swap(&context_riscv->t2);
+ Swap(&context_riscv->s0);
+ Swap(&context_riscv->s1);
+ Swap(&context_riscv->a0);
+ Swap(&context_riscv->a1);
+ Swap(&context_riscv->a2);
+ Swap(&context_riscv->a3);
+ Swap(&context_riscv->a4);
+ Swap(&context_riscv->a5);
+ Swap(&context_riscv->a6);
+ Swap(&context_riscv->a7);
+ Swap(&context_riscv->s2);
+ Swap(&context_riscv->s3);
+ Swap(&context_riscv->s4);
+ Swap(&context_riscv->s5);
+ Swap(&context_riscv->s6);
+ Swap(&context_riscv->s7);
+ Swap(&context_riscv->s8);
+ Swap(&context_riscv->s9);
+ Swap(&context_riscv->s10);
+ Swap(&context_riscv->s11);
+ Swap(&context_riscv->t3);
+ Swap(&context_riscv->t4);
+ Swap(&context_riscv->t5);
+ Swap(&context_riscv->t6);
+
+ for (int fpr_index = 0;
+ fpr_index < MD_FLOATINGSAVEAREA_RISCV_FPR_COUNT;
+ ++fpr_index) {
+ Swap(&context_riscv->float_save.regs[fpr_index]);
+ }
+ Swap(&context_riscv->float_save.fpcsr);
+ }
+ SetContextRISCV(context_riscv.release());
+
+ break;
+ }
+
+ case MD_CONTEXT_RISCV64: {
+ if (expected_size != sizeof(MDRawContextRISCV64)) {
+ BPLOG(ERROR) << "MinidumpContext RISCV64 size mismatch, "
+ << expected_size
+ << " != "
+ << sizeof(MDRawContextRISCV64);
+ return false;
+ }
+
+ scoped_ptr<MDRawContextRISCV64> context_riscv64(
+ new MDRawContextRISCV64());
+
+ // Set the context_flags member, which has already been read, and
+ // read the rest of the structure beginning with the first member
+ // after context_flags.
+ context_riscv64->context_flags = context_flags;
+
+ size_t flags_size = sizeof(context_riscv64->context_flags);
+ uint8_t* context_after_flags =
+ reinterpret_cast<uint8_t*>(context_riscv64.get()) + flags_size;
+ if (!minidump_->ReadBytes(context_after_flags,
+ sizeof(MDRawContextRISCV64) - flags_size)) {
+ BPLOG(ERROR) << "MinidumpContext could not read RISCV context";
+ return false;
+ }
+
+ // Do this after reading the entire MDRawContext structure because
+ // GetSystemInfo may seek minidump to a new position.
+ if (!CheckAgainstSystemInfo(cpu_type)) {
+ BPLOG(ERROR) << "MinidumpContext RISCV does not match system info";
+ return false;
+ }
+
+ if (minidump_->swap()) {
+ Swap(&context_riscv64->pc);
+ Swap(&context_riscv64->ra);
+ Swap(&context_riscv64->sp);
+ Swap(&context_riscv64->gp);
+ Swap(&context_riscv64->tp);
+ Swap(&context_riscv64->t0);
+ Swap(&context_riscv64->t1);
+ Swap(&context_riscv64->t2);
+ Swap(&context_riscv64->s0);
+ Swap(&context_riscv64->s1);
+ Swap(&context_riscv64->a0);
+ Swap(&context_riscv64->a1);
+ Swap(&context_riscv64->a2);
+ Swap(&context_riscv64->a3);
+ Swap(&context_riscv64->a4);
+ Swap(&context_riscv64->a5);
+ Swap(&context_riscv64->a6);
+ Swap(&context_riscv64->a7);
+ Swap(&context_riscv64->s2);
+ Swap(&context_riscv64->s3);
+ Swap(&context_riscv64->s4);
+ Swap(&context_riscv64->s5);
+ Swap(&context_riscv64->s6);
+ Swap(&context_riscv64->s7);
+ Swap(&context_riscv64->s8);
+ Swap(&context_riscv64->s9);
+ Swap(&context_riscv64->s10);
+ Swap(&context_riscv64->s11);
+ Swap(&context_riscv64->t3);
+ Swap(&context_riscv64->t4);
+ Swap(&context_riscv64->t5);
+ Swap(&context_riscv64->t6);
+
+ for (int fpr_index = 0;
+ fpr_index < MD_FLOATINGSAVEAREA_RISCV_FPR_COUNT;
+ ++fpr_index) {
+ Swap(&context_riscv64->float_save.regs[fpr_index]);
+ }
+ Swap(&context_riscv64->float_save.fpcsr);
+ }
+ SetContextRISCV64(context_riscv64.release());
+
+ break;
+ }
+
default: {
// Unknown context type - Don't log as an error yet. Let the
// caller work that out.
BPLOG(INFO) << "MinidumpContext unknown context type " <<
HexString(cpu_type);
return false;
- break;
}
}
SetContextFlags(context_flags);
@@ -1250,6 +1429,16 @@ bool MinidumpContext::CheckAgainstSystemInfo(uint32_t context_cpu_type) {
if (system_info_cpu_type == MD_CPU_ARCHITECTURE_MIPS64)
return_value = true;
break;
+
+ case MD_CONTEXT_RISCV:
+ if (system_info_cpu_type == MD_CPU_ARCHITECTURE_RISCV)
+ return_value = true;
+ break;
+
+ case MD_CONTEXT_RISCV64:
+ if (system_info_cpu_type == MD_CPU_ARCHITECTURE_RISCV64)
+ return_value = true;
+ break;
}
BPLOG_IF(ERROR, !return_value) << "MinidumpContext CPU " <<
@@ -1611,7 +1800,7 @@ MinidumpContext* MinidumpThread::GetContext() {
}
-bool MinidumpThread::GetThreadID(uint32_t *thread_id) const {
+bool MinidumpThread::GetThreadID(uint32_t* thread_id) const {
BPLOG_IF(ERROR, !thread_id) << "MinidumpThread::GetThreadID requires "
"|thread_id|";
assert(thread_id);
@@ -1831,6 +2020,229 @@ void MinidumpThreadList::Print() {
}
}
+//
+// MinidumpThreadName
+//
+
+MinidumpThreadName::MinidumpThreadName(Minidump* minidump)
+ : MinidumpObject(minidump),
+ thread_name_valid_(false),
+ thread_name_(),
+ name_(NULL) {}
+
+MinidumpThreadName::~MinidumpThreadName() {
+ delete name_;
+}
+
+bool MinidumpThreadName::Read() {
+ // Invalidate cached data.
+ delete name_;
+ name_ = NULL;
+
+ valid_ = false;
+
+ if (!minidump_->ReadBytes(&thread_name_, sizeof(thread_name_))) {
+ BPLOG(ERROR) << "MinidumpThreadName cannot read thread name";
+ return false;
+ }
+
+ if (minidump_->swap()) {
+ Swap(&thread_name_.thread_id);
+ Swap(&thread_name_.thread_name_rva);
+ }
+
+ thread_name_valid_ = true;
+ return true;
+}
+
+bool MinidumpThreadName::ReadAuxiliaryData() {
+ if (!thread_name_valid_) {
+ BPLOG(ERROR) << "Invalid MinidumpThreadName for ReadAuxiliaryData";
+ return false;
+ }
+
+ // On 32-bit systems, check that the RVA64 is within range (off_t is 32 bits).
+ if (thread_name_.thread_name_rva > numeric_limits<off_t>::max()) {
+ BPLOG(ERROR) << "MinidumpThreadName RVA64 out of range";
+ return false;
+ }
+
+ // Read the thread name.
+ const off_t thread_name_rva_offset =
+ static_cast<off_t>(thread_name_.thread_name_rva);
+ name_ = minidump_->ReadString(thread_name_rva_offset);
+ if (!name_) {
+ BPLOG(ERROR) << "MinidumpThreadName could not read name";
+ return false;
+ }
+
+ // At this point, we have enough info for the thread name to be valid.
+ valid_ = true;
+ return true;
+}
+
+bool MinidumpThreadName::GetThreadID(uint32_t* thread_id) const {
+ BPLOG_IF(ERROR, !thread_id) << "MinidumpThreadName::GetThreadID requires "
+ "|thread_id|";
+ assert(thread_id);
+ *thread_id = 0;
+
+ if (!valid_) {
+ BPLOG(ERROR) << "Invalid MinidumpThreadName for GetThreadID";
+ return false;
+ }
+
+ *thread_id = thread_name_.thread_id;
+ return true;
+}
+
+string MinidumpThreadName::GetThreadName() const {
+ if (!valid_) {
+ BPLOG(ERROR) << "Invalid MinidumpThreadName for GetThreadName";
+ return "";
+ }
+
+ return *name_;
+}
+
+void MinidumpThreadName::Print() {
+ if (!valid_) {
+ BPLOG(ERROR) << "MinidumpThreadName cannot print invalid data";
+ return;
+ }
+
+ printf("MDRawThreadName\n");
+ printf(" thread_id = 0x%x\n", thread_name_.thread_id);
+ printf(" thread_name_rva = 0x%" PRIx64 "\n",
+ thread_name_.thread_name_rva);
+ printf(" thread_name = \"%s\"\n", GetThreadName().c_str());
+ printf("\n");
+}
+
+//
+// MinidumpThreadNameList
+//
+
+MinidumpThreadNameList::MinidumpThreadNameList(Minidump* minidump)
+ : MinidumpStream(minidump), thread_names_(NULL), thread_name_count_(0) {}
+
+MinidumpThreadNameList::~MinidumpThreadNameList() {
+ delete thread_names_;
+}
+
+bool MinidumpThreadNameList::Read(uint32_t expected_size) {
+ // Invalidate cached data.
+ delete thread_names_;
+ thread_names_ = NULL;
+ thread_name_count_ = 0;
+
+ valid_ = false;
+
+ uint32_t thread_name_count;
+ if (expected_size < sizeof(thread_name_count)) {
+ BPLOG(ERROR) << "MinidumpThreadNameList count size mismatch, "
+ << expected_size << " < " << sizeof(thread_name_count);
+ return false;
+ }
+ if (!minidump_->ReadBytes(&thread_name_count, sizeof(thread_name_count))) {
+ BPLOG(ERROR) << "MinidumpThreadNameList cannot read thread name count";
+ return false;
+ }
+
+ if (minidump_->swap())
+ Swap(&thread_name_count);
+
+ if (thread_name_count >
+ numeric_limits<uint32_t>::max() / sizeof(MDRawThreadName)) {
+ BPLOG(ERROR) << "MinidumpThreadNameList thread name count "
+ << thread_name_count << " would cause multiplication overflow";
+ return false;
+ }
+
+ if (expected_size !=
+ sizeof(thread_name_count) + thread_name_count * sizeof(MDRawThreadName)) {
+ BPLOG(ERROR) << "MinidumpThreadNameList size mismatch, " << expected_size
+ << " != "
+ << sizeof(thread_name_count) +
+ thread_name_count * sizeof(MDRawThreadName);
+ return false;
+ }
+
+ if (thread_name_count > MinidumpThreadList::max_threads()) {
+ BPLOG(ERROR) << "MinidumpThreadNameList count " << thread_name_count
+ << " exceeds maximum " << MinidumpThreadList::max_threads();
+ return false;
+ }
+
+ if (thread_name_count != 0) {
+ scoped_ptr<MinidumpThreadNames> thread_names(new MinidumpThreadNames(
+ thread_name_count, MinidumpThreadName(minidump_)));
+
+ for (unsigned int thread_name_index = 0;
+ thread_name_index < thread_name_count; ++thread_name_index) {
+ MinidumpThreadName* thread_name = &(*thread_names)[thread_name_index];
+
+ // Assume that the file offset is correct after the last read.
+ if (!thread_name->Read()) {
+ BPLOG(ERROR) << "MinidumpThreadNameList cannot read thread name "
+ << thread_name_index << "/" << thread_name_count;
+ return false;
+ }
+ }
+
+ for (unsigned int thread_name_index = 0;
+ thread_name_index < thread_name_count; ++thread_name_index) {
+ MinidumpThreadName* thread_name = &(*thread_names)[thread_name_index];
+
+ if (!thread_name->ReadAuxiliaryData() && !thread_name->valid()) {
+ BPLOG(ERROR) << "MinidumpThreadNameList cannot read thread name "
+ << thread_name_index << "/" << thread_name_count;
+ return false;
+ }
+ }
+
+ thread_names_ = thread_names.release();
+ }
+
+ thread_name_count_ = thread_name_count;
+
+ valid_ = true;
+ return true;
+}
+
+MinidumpThreadName* MinidumpThreadNameList::GetThreadNameAtIndex(
+ unsigned int index) const {
+ if (!valid_) {
+ BPLOG(ERROR) << "Invalid MinidumpThreadNameList for GetThreadNameAtIndex";
+ return NULL;
+ }
+
+ if (index >= thread_name_count_) {
+ BPLOG(ERROR) << "MinidumpThreadNameList index out of range: " << index
+ << "/" << thread_name_count_;
+ return NULL;
+ }
+
+ return &(*thread_names_)[index];
+}
+
+void MinidumpThreadNameList::Print() {
+ if (!valid_) {
+ BPLOG(ERROR) << "MinidumpThreadNameList cannot print invalid data";
+ return;
+ }
+
+ printf("MinidumpThreadNameList\n");
+ printf(" thread_name_count = %d\n", thread_name_count_);
+ printf("\n");
+
+ for (unsigned int thread_name_index = 0;
+ thread_name_index < thread_name_count_; ++thread_name_index) {
+ printf("thread_name[%d]\n", thread_name_index);
+
+ (*thread_names_)[thread_name_index].Print();
+ }
+}
//
// MinidumpModule
@@ -1973,14 +2385,14 @@ string MinidumpModule::code_identifier() const {
if (!has_debug_info_)
return "";
- MinidumpSystemInfo *minidump_system_info = minidump_->GetSystemInfo();
+ MinidumpSystemInfo* minidump_system_info = minidump_->GetSystemInfo();
if (!minidump_system_info) {
BPLOG(ERROR) << "MinidumpModule code_identifier requires "
"MinidumpSystemInfo";
return "";
}
- const MDRawSystemInfo *raw_system_info = minidump_system_info->system_info();
+ const MDRawSystemInfo* raw_system_info = minidump_system_info->system_info();
if (!raw_system_info) {
BPLOG(ERROR) << "MinidumpModule code_identifier requires MDRawSystemInfo";
return "";
@@ -2093,7 +2505,7 @@ string MinidumpModule::debug_file() const {
// No usable CodeView record. Try the miscellaneous debug record.
if (misc_record_) {
const MDImageDebugMisc* misc_record =
- reinterpret_cast<const MDImageDebugMisc *>(&(*misc_record_)[0]);
+ reinterpret_cast<const MDImageDebugMisc*>(&(*misc_record_)[0]);
if (!misc_record->unicode) {
// If it's not Unicode, just stuff it into the string. It's unclear
// if misc_record->data is 0-terminated, so use an explicit size.
@@ -2202,7 +2614,7 @@ string MinidumpModule::debug_identifier() const {
// with age = 0. Historically Breakpad would do this during dump
// writing to fit the build id data into a MDCVInfoPDB70 struct.
// The full build id is available by calling code_identifier.
- MDGUID guid = {};
+ MDGUID guid = {0};
memcpy(&guid, &cv_record_elf->build_id,
std::min(cv_record_->size() - MDCVInfoELF_minsize,
sizeof(MDGUID)));
@@ -2549,7 +2961,7 @@ void MinidumpModule::Print() {
code_identifier().c_str());
uint32_t cv_record_size;
- const uint8_t *cv_record = GetCVRecord(&cv_record_size);
+ const uint8_t* cv_record = GetCVRecord(&cv_record_size);
if (cv_record) {
if (cv_record_signature_ == MD_CVINFOPDB70_SIGNATURE) {
const MDCVInfoPDB70* cv_record_70 =
@@ -3215,7 +3627,7 @@ bool MinidumpException::Read(uint32_t expected_size) {
}
-bool MinidumpException::GetThreadID(uint32_t *thread_id) const {
+bool MinidumpException::GetThreadID(uint32_t* thread_id) const {
BPLOG_IF(ERROR, !thread_id) << "MinidumpException::GetThreadID requires "
"|thread_id|";
assert(thread_id);
@@ -3538,6 +3950,14 @@ string MinidumpSystemInfo::GetCPU() {
cpu = "arm64";
break;
+ case MD_CPU_ARCHITECTURE_RISCV:
+ cpu = "riscv";
+ break;
+
+ case MD_CPU_ARCHITECTURE_RISCV64:
+ cpu = "riscv64";
+ break;
+
default:
BPLOG(ERROR) << "MinidumpSystemInfo unknown CPU for architecture " <<
HexString(system_info_.processor_architecture);
@@ -3603,8 +4023,8 @@ void MinidumpSystemInfo::Print() {
}
printf("MDRawSystemInfo\n");
- printf(" processor_architecture = 0x%x\n",
- system_info_.processor_architecture);
+ printf(" processor_architecture = 0x%x (%s)\n",
+ system_info_.processor_architecture, GetCPU().c_str());
printf(" processor_level = %d\n",
system_info_.processor_level);
printf(" processor_revision = 0x%x\n",
@@ -3619,8 +4039,8 @@ void MinidumpSystemInfo::Print() {
system_info_.minor_version);
printf(" build_number = %d\n",
system_info_.build_number);
- printf(" platform_id = 0x%x\n",
- system_info_.platform_id);
+ printf(" platform_id = 0x%x (%s)\n",
+ system_info_.platform_id, GetOS().c_str());
printf(" csd_version_rva = 0x%x\n",
system_info_.csd_version_rva);
printf(" suite_mask = 0x%x\n",
@@ -3699,14 +4119,14 @@ string MinidumpUnloadedModule::code_identifier() const {
return "";
}
- MinidumpSystemInfo *minidump_system_info = minidump_->GetSystemInfo();
+ MinidumpSystemInfo* minidump_system_info = minidump_->GetSystemInfo();
if (!minidump_system_info) {
BPLOG(ERROR) << "MinidumpUnloadedModule code_identifier requires "
"MinidumpSystemInfo";
return "";
}
- const MDRawSystemInfo *raw_system_info = minidump_system_info->system_info();
+ const MDRawSystemInfo* raw_system_info = minidump_system_info->system_info();
if (!raw_system_info) {
BPLOG(ERROR) << "MinidumpUnloadedModule code_identifier requires "
<< "MDRawSystemInfo";
@@ -4356,7 +4776,7 @@ bool MinidumpBreakpadInfo::Read(uint32_t expected_size) {
}
-bool MinidumpBreakpadInfo::GetDumpThreadID(uint32_t *thread_id) const {
+bool MinidumpBreakpadInfo::GetDumpThreadID(uint32_t* thread_id) const {
BPLOG_IF(ERROR, !thread_id) << "MinidumpBreakpadInfo::GetDumpThreadID "
"requires |thread_id|";
assert(thread_id);
@@ -4377,7 +4797,7 @@ bool MinidumpBreakpadInfo::GetDumpThreadID(uint32_t *thread_id) const {
}
-bool MinidumpBreakpadInfo::GetRequestingThreadID(uint32_t *thread_id)
+bool MinidumpBreakpadInfo::GetRequestingThreadID(uint32_t* thread_id)
const {
BPLOG_IF(ERROR, !thread_id) << "MinidumpBreakpadInfo::GetRequestingThreadID "
"requires |thread_id|";
@@ -4695,7 +5115,7 @@ void MinidumpMemoryInfoList::Print() {
// MinidumpLinuxMaps
//
-MinidumpLinuxMaps::MinidumpLinuxMaps(Minidump *minidump)
+MinidumpLinuxMaps::MinidumpLinuxMaps(Minidump* minidump)
: MinidumpObject(minidump) {
}
@@ -4711,7 +5131,7 @@ void MinidumpLinuxMaps::Print() const {
// MinidumpLinuxMapsList
//
-MinidumpLinuxMapsList::MinidumpLinuxMapsList(Minidump *minidump)
+MinidumpLinuxMapsList::MinidumpLinuxMapsList(Minidump* minidump)
: MinidumpStream(minidump),
maps_(NULL),
maps_count_(0) {
@@ -4726,7 +5146,7 @@ MinidumpLinuxMapsList::~MinidumpLinuxMapsList() {
}
}
-const MinidumpLinuxMaps *MinidumpLinuxMapsList::GetLinuxMapsForAddress(
+const MinidumpLinuxMaps* MinidumpLinuxMapsList::GetLinuxMapsForAddress(
uint64_t address) const {
if (!valid_ || (maps_ == NULL)) {
BPLOG(ERROR) << "Invalid MinidumpLinuxMapsList for GetLinuxMapsForAddress";
@@ -4748,7 +5168,7 @@ const MinidumpLinuxMaps *MinidumpLinuxMapsList::GetLinuxMapsForAddress(
return NULL;
}
-const MinidumpLinuxMaps *MinidumpLinuxMapsList::GetLinuxMapsAtIndex(
+const MinidumpLinuxMaps* MinidumpLinuxMapsList::GetLinuxMapsAtIndex(
unsigned int index) const {
if (!valid_ || (maps_ == NULL)) {
BPLOG(ERROR) << "Invalid MinidumpLinuxMapsList for GetLinuxMapsAtIndex";
@@ -4847,6 +5267,7 @@ MinidumpCrashpadInfo::MinidumpCrashpadInfo(Minidump* minidump)
module_crashpad_info_(),
module_crashpad_info_list_annotations_(),
module_crashpad_info_simple_annotations_(),
+ module_crashpad_info_annotation_objects_(),
simple_annotations_() {
}
@@ -4854,16 +5275,52 @@ MinidumpCrashpadInfo::MinidumpCrashpadInfo(Minidump* minidump)
bool MinidumpCrashpadInfo::Read(uint32_t expected_size) {
valid_ = false;
- if (expected_size != sizeof(crashpad_info_)) {
- BPLOG(ERROR) << "MinidumpCrashpadInfo size mismatch, " << expected_size <<
- " != " << sizeof(crashpad_info_);
+ // Support old minidumps that do not implement newer crashpad_info_
+ // fields, currently limited to the address mask.
+ static_assert(sizeof(crashpad_info_) == 64,
+ "Updated ::Read for new crashpad_info field.");
+
+ constexpr size_t crashpad_info_min_size =
+ offsetof(decltype(crashpad_info_), reserved);
+ if (expected_size < crashpad_info_min_size) {
+ BPLOG(ERROR) << "MinidumpCrashpadInfo size mismatch, " << expected_size
+ << " < " << crashpad_info_min_size;
return false;
}
- if (!minidump_->ReadBytes(&crashpad_info_, sizeof(crashpad_info_))) {
+ if (!minidump_->ReadBytes(&crashpad_info_, crashpad_info_min_size)) {
BPLOG(ERROR) << "MinidumpCrashpadInfo cannot read Crashpad info";
return false;
}
+ expected_size -= crashpad_info_min_size;
+
+ // Read `reserved` if available.
+ size_t crashpad_reserved_size = sizeof(crashpad_info_.reserved);
+ if (expected_size >= crashpad_reserved_size) {
+ if (!minidump_->ReadBytes(
+ &crashpad_info_.reserved,
+ crashpad_reserved_size)) {
+ BPLOG(ERROR) << "MinidumpCrashpadInfo cannot read reserved";
+ return false;
+ }
+ expected_size -= crashpad_reserved_size;
+ } else {
+ crashpad_info_.reserved = 0;
+ }
+
+ // Read `address_mask` if available.
+ size_t crashpad_address_mask_size = sizeof(crashpad_info_.address_mask);
+ if (expected_size >= crashpad_address_mask_size) {
+ if (!minidump_->ReadBytes(
+ &crashpad_info_.address_mask,
+ crashpad_address_mask_size)) {
+ BPLOG(ERROR) << "MinidumpCrashpadInfo cannot read address mask";
+ return false;
+ }
+ expected_size -= crashpad_address_mask_size;
+ } else {
+ crashpad_info_.address_mask = 0;
+ }
if (minidump_->swap()) {
Swap(&crashpad_info_.version);
@@ -4871,6 +5328,8 @@ bool MinidumpCrashpadInfo::Read(uint32_t expected_size) {
Swap(&crashpad_info_.client_id);
Swap(&crashpad_info_.simple_annotations);
Swap(&crashpad_info_.module_list);
+ Swap(&crashpad_info_.reserved);
+ Swap(&crashpad_info_.address_mask);
}
if (crashpad_info_.simple_annotations.data_size) {
@@ -4934,6 +5393,7 @@ bool MinidumpCrashpadInfo::Read(uint32_t expected_size) {
Swap(&module_crashpad_info.version);
Swap(&module_crashpad_info.list_annotations);
Swap(&module_crashpad_info.simple_annotations);
+ Swap(&module_crashpad_info.annotation_objects);
}
std::vector<std::string> list_annotations;
@@ -4958,11 +5418,23 @@ bool MinidumpCrashpadInfo::Read(uint32_t expected_size) {
}
}
+ std::vector<MinidumpCrashpadInfo::AnnotationObject> annotation_objects;
+ if (module_crashpad_info.annotation_objects.data_size) {
+ if (!minidump_->ReadCrashpadAnnotationsList(
+ module_crashpad_info.annotation_objects.rva,
+ &annotation_objects)) {
+ BPLOG(ERROR)
+ << "MinidumpCrashpadInfo cannot read Crashpad annotations list";
+ return false;
+ }
+ }
+
module_crashpad_info_links_.push_back(
module_crashpad_info_links[index].minidump_module_list_index);
module_crashpad_info_.push_back(module_crashpad_info);
module_crashpad_info_list_annotations_.push_back(list_annotations);
module_crashpad_info_simple_annotations_.push_back(simple_annotations);
+ module_crashpad_info_annotation_objects_.push_back(annotation_objects);
}
}
@@ -4983,12 +5455,9 @@ void MinidumpCrashpadInfo::Print() {
MDGUIDToString(crashpad_info_.report_id).c_str());
printf(" client_id = %s\n",
MDGUIDToString(crashpad_info_.client_id).c_str());
- for (std::map<std::string, std::string>::const_iterator iterator =
- simple_annotations_.begin();
- iterator != simple_annotations_.end();
- ++iterator) {
- printf(" simple_annotations[\"%s\"] = %s\n",
- iterator->first.c_str(), iterator->second.c_str());
+ for (const auto& annot : simple_annotations_) {
+ printf(" simple_annotations[\"%s\"] = %s\n", annot.first.c_str(),
+ annot.second.c_str());
}
for (uint32_t module_index = 0;
module_index < module_crashpad_info_links_.size();
@@ -4997,24 +5466,20 @@ void MinidumpCrashpadInfo::Print() {
module_index, module_crashpad_info_links_[module_index]);
printf(" module_list[%d].version = %d\n",
module_index, module_crashpad_info_[module_index].version);
- for (uint32_t annotation_index = 0;
- annotation_index <
- module_crashpad_info_list_annotations_[module_index].size();
+ const auto& list_annots =
+ module_crashpad_info_list_annotations_[module_index];
+ for (uint32_t annotation_index = 0; annotation_index < list_annots.size();
++annotation_index) {
- printf(" module_list[%d].list_annotations[%d] = %s\n",
- module_index,
- annotation_index,
- module_crashpad_info_list_annotations_
- [module_index][annotation_index].c_str());
+ printf(" module_list[%d].list_annotations[%d] = %s\n", module_index,
+ annotation_index, list_annots[annotation_index].c_str());
}
- for (std::map<std::string, std::string>::const_iterator iterator =
- module_crashpad_info_simple_annotations_[module_index].begin();
- iterator !=
- module_crashpad_info_simple_annotations_[module_index].end();
- ++iterator) {
+ const auto& simple_annots =
+ module_crashpad_info_simple_annotations_[module_index];
+ for (const auto& annot : simple_annots) {
printf(" module_list[%d].simple_annotations[\"%s\"] = %s\n",
- module_index, iterator->first.c_str(), iterator->second.c_str());
+ module_index, annot.first.c_str(), annot.second.c_str());
}
+ printf(" address_mask = %" PRIu64 "\n", crashpad_info_.address_mask);
}
printf("\n");
@@ -5090,7 +5555,7 @@ bool Minidump::Open() {
return true;
}
-bool Minidump::GetContextCPUFlagsFromSystemInfo(uint32_t *context_cpu_flags) {
+bool Minidump::GetContextCPUFlagsFromSystemInfo(uint32_t* context_cpu_flags) {
// Initialize output parameters
*context_cpu_flags = 0;
@@ -5155,6 +5620,12 @@ bool Minidump::GetContextCPUFlagsFromSystemInfo(uint32_t *context_cpu_flags) {
case MD_CPU_ARCHITECTURE_SPARC:
*context_cpu_flags = MD_CONTEXT_SPARC;
break;
+ case MD_CPU_ARCHITECTURE_RISCV:
+ *context_cpu_flags = MD_CONTEXT_RISCV;
+ break;
+ case MD_CPU_ARCHITECTURE_RISCV64:
+ *context_cpu_flags = MD_CONTEXT_RISCV64;
+ break;
case MD_CPU_ARCHITECTURE_UNKNOWN:
*context_cpu_flags = 0;
break;
@@ -5276,6 +5747,7 @@ bool Minidump::Read() {
unsigned int stream_type = directory_entry->stream_type;
switch (stream_type) {
case MD_THREAD_LIST_STREAM:
+ case MD_THREAD_NAME_LIST_STREAM:
case MD_MODULE_LIST_STREAM:
case MD_MEMORY_LIST_STREAM:
case MD_EXCEPTION_STREAM:
@@ -5314,6 +5786,10 @@ MinidumpThreadList* Minidump::GetThreadList() {
return GetStream(&thread_list);
}
+MinidumpThreadNameList* Minidump::GetThreadNameList() {
+ MinidumpThreadNameList* thread_name_list;
+ return GetStream(&thread_name_list);
+}
MinidumpModuleList* Minidump::GetModuleList() {
MinidumpModuleList* module_list;
@@ -5366,8 +5842,8 @@ MinidumpMemoryInfoList* Minidump::GetMemoryInfoList() {
return GetStream(&memory_info_list);
}
-MinidumpLinuxMapsList *Minidump::GetLinuxMapsList() {
- MinidumpLinuxMapsList *linux_maps_list;
+MinidumpLinuxMapsList* Minidump::GetLinuxMapsList() {
+ MinidumpLinuxMapsList* linux_maps_list;
return GetStream(&linux_maps_list);
}
@@ -5413,6 +5889,8 @@ static const char* get_stream_name(uint32_t stream_type) {
return "MD_RESERVED_STREAM_1";
case MD_THREAD_LIST_STREAM:
return "MD_THREAD_LIST_STREAM";
+ case MD_THREAD_NAME_LIST_STREAM:
+ return "MD_THREAD_NAME_LIST_STREAM";
case MD_MODULE_LIST_STREAM:
return "MD_MODULE_LIST_STREAM";
case MD_MEMORY_LIST_STREAM:
@@ -5807,6 +6285,73 @@ bool Minidump::ReadSimpleStringDictionary(
return true;
}
+bool Minidump::ReadCrashpadAnnotationsList(
+ off_t offset,
+ std::vector<MinidumpCrashpadInfo::AnnotationObject>* annotations_list) {
+ annotations_list->clear();
+
+ if (!SeekSet(offset)) {
+ BPLOG(ERROR) << "Minidump cannot seek to annotations_list";
+ return false;
+ }
+
+ uint32_t count;
+ if (!ReadBytes(&count, sizeof(count))) {
+ BPLOG(ERROR) << "Minidump cannot read annotations_list count";
+ return false;
+ }
+
+ if (swap_) {
+ Swap(&count);
+ }
+
+ scoped_array<MDRawCrashpadAnnotation> objects(
+ new MDRawCrashpadAnnotation[count]);
+
+ // Read the entire array in one fell swoop, instead of reading one entry
+ // at a time in the loop.
+ if (!ReadBytes(&objects[0], sizeof(MDRawCrashpadAnnotation) * count)) {
+ BPLOG(ERROR) << "Minidump could not read annotations_list";
+ return false;
+ }
+
+ for (uint32_t index = 0; index < count; ++index) {
+ MDRawCrashpadAnnotation annotation = objects[index];
+
+ if (swap_) {
+ Swap(&annotation);
+ }
+
+ string name;
+ if (!ReadUTF8String(annotation.name, &name)) {
+ BPLOG(ERROR) << "Minidump could not read annotation name";
+ return false;
+ }
+
+ if (!SeekSet(annotation.value)) {
+ BPLOG(ERROR) << "Minidump cannot seek to annotations value";
+ return false;
+ }
+
+ uint32_t value_length;
+ if (!ReadBytes(&value_length, sizeof(value_length))) {
+ BPLOG(ERROR) << "Minidump could not read annotation value length";
+ return false;
+ }
+
+ std::vector<uint8_t> value_data(value_length);
+ if (!ReadBytes(value_data.data(), value_length)) {
+ BPLOG(ERROR) << "Minidump could not read annotation value";
+ return false;
+ }
+
+ MinidumpCrashpadInfo::AnnotationObject object = {annotation.type, name,
+ value_data};
+ annotations_list->push_back(object);
+ }
+
+ return true;
+}
bool Minidump::SeekToStreamType(uint32_t stream_type,
uint32_t* stream_length) {
diff --git a/src/processor/minidump_dump.cc b/src/processor/minidump_dump.cc
index 4716aa08..83afd1da 100644
--- a/src/processor/minidump_dump.cc
+++ b/src/processor/minidump_dump.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2006, Google Inc.
-// All rights reserved.
+// Copyright 2006 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -36,6 +35,7 @@
#include <string.h>
#include <unistd.h>
+#include "common/path_helper.h"
#include "common/scoped_ptr.h"
#include "google_breakpad/processor/minidump.h"
#include "processor/logging.h"
@@ -44,6 +44,7 @@ namespace {
using google_breakpad::Minidump;
using google_breakpad::MinidumpThreadList;
+using google_breakpad::MinidumpThreadNameList;
using google_breakpad::MinidumpModuleList;
using google_breakpad::MinidumpMemoryInfoList;
using google_breakpad::MinidumpMemoryList;
@@ -91,7 +92,7 @@ static void DumpRawStream(Minidump *minidump,
// in compatibility warnings.
uint32_t int_remaining = remaining;
printf("%.*s", int_remaining, &contents[current_offset]);
- char *next_null = reinterpret_cast<char *>(
+ char *next_null = reinterpret_cast<char*>(
memchr(&contents[current_offset], 0, remaining));
if (next_null == NULL)
break;
@@ -121,6 +122,11 @@ static bool PrintMinidumpDump(const Options& options) {
thread_list->Print();
}
+ MinidumpThreadNameList *thread_name_list = minidump.GetThreadNameList();
+ if (thread_name_list) {
+ thread_name_list->Print();
+ }
+
// It's useful to be able to see the full list of modules here even if it
// would cause minidump_stackwalk to fail.
MinidumpModuleList::set_max_modules(UINT32_MAX);
@@ -233,7 +239,7 @@ Usage(int argc, char *argv[], bool error) {
" <minidump> should be a minidump.\n"
" -x:\t Display memory in a hexdump like format\n"
" -h:\t Usage\n",
- argv[0]);
+ google_breakpad::BaseName(argv[0]).c_str());
}
//=============================================================================
@@ -241,7 +247,7 @@ static void
SetupOptions(int argc, char *argv[], Options *options) {
int ch;
- while ((ch = getopt(argc, (char * const *)argv, "xh")) != -1) {
+ while ((ch = getopt(argc, (char * const*)argv, "xh")) != -1) {
switch (ch) {
case 'x':
options->hexdump = true;
diff --git a/src/processor/minidump_dump_test b/src/processor/minidump_dump_test
index fb62ace7..32ae38c5 100755
--- a/src/processor/minidump_dump_test
+++ b/src/processor/minidump_dump_test
@@ -1,7 +1,6 @@
#!/bin/sh
-# Copyright (c) 2006, Google Inc.
-# All rights reserved.
+# Copyright 2006 Google LLC
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
@@ -13,7 +12,7 @@
# copyright notice, this list of conditions and the following disclaimer
# in the documentation and/or other materials provided with the
# distribution.
-# * Neither the name of Google Inc. nor the names of its
+# * Neither the name of Google LLC nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
diff --git a/src/processor/minidump_processor.cc b/src/processor/minidump_processor.cc
index 4ea4cb70..fb330e26 100644
--- a/src/processor/minidump_processor.cc
+++ b/src/processor/minidump_processor.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2006, Google Inc.
-// All rights reserved.
+// Copyright 2006 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -31,7 +30,11 @@
#include <assert.h>
+#include <algorithm>
+#include <limits>
+#include <map>
#include <string>
+#include <utility>
#include "common/scoped_ptr.h"
#include "common/stdio_wrapper.h"
@@ -41,22 +44,23 @@
#include "google_breakpad/processor/process_state.h"
#include "google_breakpad/processor/exploitability.h"
#include "google_breakpad/processor/stack_frame_symbolizer.h"
+#include "processor/disassembler_objdump.h"
#include "processor/logging.h"
#include "processor/stackwalker_x86.h"
#include "processor/symbolic_constants_win.h"
namespace google_breakpad {
-MinidumpProcessor::MinidumpProcessor(SymbolSupplier *supplier,
- SourceLineResolverInterface *resolver)
+MinidumpProcessor::MinidumpProcessor(SymbolSupplier* supplier,
+ SourceLineResolverInterface* resolver)
: frame_symbolizer_(new StackFrameSymbolizer(supplier, resolver)),
own_frame_symbolizer_(true),
enable_exploitability_(false),
enable_objdump_(false) {
}
-MinidumpProcessor::MinidumpProcessor(SymbolSupplier *supplier,
- SourceLineResolverInterface *resolver,
+MinidumpProcessor::MinidumpProcessor(SymbolSupplier* supplier,
+ SourceLineResolverInterface* resolver,
bool enable_exploitability)
: frame_symbolizer_(new StackFrameSymbolizer(supplier, resolver)),
own_frame_symbolizer_(true),
@@ -64,7 +68,7 @@ MinidumpProcessor::MinidumpProcessor(SymbolSupplier *supplier,
enable_objdump_(false) {
}
-MinidumpProcessor::MinidumpProcessor(StackFrameSymbolizer *frame_symbolizer,
+MinidumpProcessor::MinidumpProcessor(StackFrameSymbolizer* frame_symbolizer,
bool enable_exploitability)
: frame_symbolizer_(frame_symbolizer),
own_frame_symbolizer_(false),
@@ -78,13 +82,13 @@ MinidumpProcessor::~MinidumpProcessor() {
}
ProcessResult MinidumpProcessor::Process(
- Minidump *dump, ProcessState *process_state) {
+ Minidump* dump, ProcessState* process_state) {
assert(dump);
assert(process_state);
process_state->Clear();
- const MDRawHeader *header = dump->header();
+ const MDRawHeader* header = dump->header();
if (!header) {
BPLOG(ERROR) << "Minidump " << dump->path() << " has no header";
return PROCESS_ERROR_NO_MINIDUMP_HEADER;
@@ -102,20 +106,20 @@ ProcessResult MinidumpProcessor::Process(
uint32_t requesting_thread_id = 0;
bool has_requesting_thread = false;
- MinidumpBreakpadInfo *breakpad_info = dump->GetBreakpadInfo();
+ MinidumpBreakpadInfo* breakpad_info = dump->GetBreakpadInfo();
if (breakpad_info) {
has_dump_thread = breakpad_info->GetDumpThreadID(&dump_thread_id);
has_requesting_thread =
breakpad_info->GetRequestingThreadID(&requesting_thread_id);
}
- MinidumpException *exception = dump->GetException();
+ MinidumpException* exception = dump->GetException();
if (exception) {
process_state->crashed_ = true;
has_requesting_thread = exception->GetThreadID(&requesting_thread_id);
process_state->crash_reason_ = GetCrashReason(
- dump, &process_state->crash_address_);
+ dump, &process_state->crash_address_, enable_objdump_);
process_state->exception_record_.set_code(
exception->exception()->exception_record.exception_code,
@@ -128,8 +132,10 @@ ProcessResult MinidumpProcessor::Process(
process_state->exception_record_.set_nested_exception_record_address(
exception->exception()->exception_record.exception_record);
process_state->exception_record_.set_address(process_state->crash_address_);
- for (uint32_t i = 0;
- i < exception->exception()->exception_record.number_parameters; i++) {
+ const uint32_t num_parameters =
+ std::min(exception->exception()->exception_record.number_parameters,
+ MD_EXCEPTION_MAXIMUM_PARAMETERS);
+ for (uint32_t i = 0; i < num_parameters; ++i) {
process_state->exception_record_.add_parameter(
exception->exception()->exception_record.exception_information[i],
// TODO(ivanpe): Populate description.
@@ -140,7 +146,7 @@ ProcessResult MinidumpProcessor::Process(
// This will just return an empty string if it doesn't exist.
process_state->assertion_ = GetAssertion(dump);
- MinidumpModuleList *module_list = dump->GetModuleList();
+ MinidumpModuleList* module_list = dump->GetModuleList();
// Put a copy of the module list into ProcessState object. This is not
// necessarily a MinidumpModuleList, but it adheres to the CodeModules
@@ -160,19 +166,19 @@ ProcessResult MinidumpProcessor::Process(
}
}
- MinidumpUnloadedModuleList *unloaded_module_list =
+ MinidumpUnloadedModuleList* unloaded_module_list =
dump->GetUnloadedModuleList();
if (unloaded_module_list) {
process_state->unloaded_modules_ = unloaded_module_list->Copy();
}
- MinidumpMemoryList *memory_list = dump->GetMemoryList();
+ MinidumpMemoryList* memory_list = dump->GetMemoryList();
if (memory_list) {
BPLOG(INFO) << "Found " << memory_list->region_count()
<< " memory regions.";
}
- MinidumpThreadList *threads = dump->GetThreadList();
+ MinidumpThreadList* threads = dump->GetThreadList();
if (!threads) {
BPLOG(ERROR) << "Minidump " << dump->path() << " has no thread list";
return PROCESS_ERROR_NO_THREAD_LIST;
@@ -196,6 +202,28 @@ ProcessResult MinidumpProcessor::Process(
// Reset frame_symbolizer_ at the beginning of stackwalk for each minidump.
frame_symbolizer_->Reset();
+
+ MinidumpThreadNameList* thread_names = dump->GetThreadNameList();
+ std::map<uint32_t, string> thread_id_to_name;
+ if (thread_names) {
+ const unsigned int thread_name_count = thread_names->thread_name_count();
+ for (unsigned int thread_name_index = 0;
+ thread_name_index < thread_name_count;
+ ++thread_name_index) {
+ MinidumpThreadName* thread_name = thread_names->GetThreadNameAtIndex(thread_name_index);
+ if (!thread_name) {
+ BPLOG(ERROR) << "Could not get thread name for thread at index " << thread_name_index;
+ return PROCESS_ERROR_GETTING_THREAD_NAME;
+ }
+ uint32_t thread_id;
+ if (!thread_name->GetThreadID(&thread_id)) {
+ BPLOG(ERROR) << "Could not get thread ID for thread at index " << thread_name_index;
+ return PROCESS_ERROR_GETTING_THREAD_NAME;
+ }
+ thread_id_to_name.insert(std::make_pair(thread_id, thread_name->GetThreadName()));
+ }
+ }
+
for (unsigned int thread_index = 0;
thread_index < thread_count;
++thread_index) {
@@ -204,7 +232,7 @@ ProcessResult MinidumpProcessor::Process(
thread_index, thread_count);
string thread_string = dump->path() + ":" + thread_string_buffer;
- MinidumpThread *thread = threads->GetThreadAtIndex(thread_index);
+ MinidumpThread* thread = threads->GetThreadAtIndex(thread_index);
if (!thread) {
BPLOG(ERROR) << "Could not get thread for " << thread_string;
return PROCESS_ERROR_GETTING_THREAD;
@@ -217,6 +245,14 @@ ProcessResult MinidumpProcessor::Process(
}
thread_string += " id " + HexString(thread_id);
+ auto thread_name_iter = thread_id_to_name.find(thread_id);
+ string thread_name;
+ if (thread_name_iter != thread_id_to_name.end()) {
+ thread_name = thread_name_iter->second;
+ }
+ if (!thread_name.empty()) {
+ thread_string += " name [" + thread_name + "]";
+ }
BPLOG(INFO) << "Looking at thread " << thread_string;
// If this thread is the thread that produced the minidump, don't process
@@ -227,7 +263,7 @@ ProcessResult MinidumpProcessor::Process(
continue;
}
- MinidumpContext *context = thread->GetContext();
+ MinidumpContext* context = thread->GetContext();
if (has_requesting_thread && thread_id == requesting_thread_id) {
if (found_requesting_thread) {
@@ -254,7 +290,7 @@ ProcessResult MinidumpProcessor::Process(
// would not result in the expected stack trace from the time of the
// crash. If the exception context is invalid, however, we fall back
// on the thread context.
- MinidumpContext *ctx = exception->GetContext();
+ MinidumpContext* ctx = exception->GetContext();
context = ctx ? ctx : thread->GetContext();
}
}
@@ -262,7 +298,7 @@ ProcessResult MinidumpProcessor::Process(
// If the memory region for the stack cannot be read using the RVA stored
// in the memory descriptor inside MINIDUMP_THREAD, try to locate and use
// a memory region (containing the stack) from the minidump memory list.
- MinidumpMemoryRegion *thread_memory = thread->GetMemory();
+ MinidumpMemoryRegion* thread_memory = thread->GetMemory();
if (!thread_memory && memory_list) {
uint64_t start_stack_memory_range = thread->GetStartOfStackMemoryRange();
if (start_stack_memory_range) {
@@ -308,6 +344,7 @@ ProcessResult MinidumpProcessor::Process(
stack->set_tid(thread_id);
process_state->threads_.push_back(stack.release());
process_state->thread_memory_regions_.push_back(thread_memory);
+ process_state->thread_names_.push_back(thread_name);
}
if (interrupted) {
@@ -347,7 +384,7 @@ ProcessResult MinidumpProcessor::Process(
}
ProcessResult MinidumpProcessor::Process(
- const string &minidump_file, ProcessState *process_state) {
+ const string& minidump_file, ProcessState* process_state) {
BPLOG(INFO) << "Processing minidump in file " << minidump_file;
Minidump dump(minidump_file);
@@ -362,9 +399,9 @@ ProcessResult MinidumpProcessor::Process(
// Returns the MDRawSystemInfo from a minidump, or NULL if system info is
// not available from the minidump. If system_info is non-NULL, it is used
// to pass back the MinidumpSystemInfo object.
-static const MDRawSystemInfo* GetSystemInfo(Minidump *dump,
- MinidumpSystemInfo **system_info) {
- MinidumpSystemInfo *minidump_system_info = dump->GetSystemInfo();
+static const MDRawSystemInfo* GetSystemInfo(Minidump* dump,
+ MinidumpSystemInfo** system_info) {
+ MinidumpSystemInfo* minidump_system_info = dump->GetSystemInfo();
if (!minidump_system_info)
return NULL;
@@ -517,15 +554,15 @@ static void GetARMCpuInfo(const MDRawSystemInfo* raw_info,
}
// static
-bool MinidumpProcessor::GetCPUInfo(Minidump *dump, SystemInfo *info) {
+bool MinidumpProcessor::GetCPUInfo(Minidump* dump, SystemInfo* info) {
assert(dump);
assert(info);
info->cpu.clear();
info->cpu_info.clear();
- MinidumpSystemInfo *system_info;
- const MDRawSystemInfo *raw_system_info = GetSystemInfo(dump, &system_info);
+ MinidumpSystemInfo* system_info;
+ const MDRawSystemInfo* raw_system_info = GetSystemInfo(dump, &system_info);
if (!raw_system_info)
return false;
@@ -538,7 +575,7 @@ bool MinidumpProcessor::GetCPUInfo(Minidump *dump, SystemInfo *info) {
else
info->cpu = "amd64";
- const string *cpu_vendor = system_info->GetCPUVendor();
+ const string* cpu_vendor = system_info->GetCPUVendor();
if (cpu_vendor) {
info->cpu_info = *cpu_vendor;
info->cpu_info.append(" ");
@@ -605,7 +642,7 @@ bool MinidumpProcessor::GetCPUInfo(Minidump *dump, SystemInfo *info) {
}
// static
-bool MinidumpProcessor::GetOSInfo(Minidump *dump, SystemInfo *info) {
+bool MinidumpProcessor::GetOSInfo(Minidump* dump, SystemInfo* info) {
assert(dump);
assert(info);
@@ -613,8 +650,8 @@ bool MinidumpProcessor::GetOSInfo(Minidump *dump, SystemInfo *info) {
info->os_short.clear();
info->os_version.clear();
- MinidumpSystemInfo *system_info;
- const MDRawSystemInfo *raw_system_info = GetSystemInfo(dump, &system_info);
+ MinidumpSystemInfo* system_info;
+ const MDRawSystemInfo* raw_system_info = GetSystemInfo(dump, &system_info);
if (!raw_system_info)
return false;
@@ -688,7 +725,7 @@ bool MinidumpProcessor::GetOSInfo(Minidump *dump, SystemInfo *info) {
raw_system_info->build_number);
info->os_version = os_version_string;
- const string *csd_version = system_info->GetCSDVersion();
+ const string* csd_version = system_info->GetCSDVersion();
if (csd_version) {
info->os_version.append(" ");
info->os_version.append(*csd_version);
@@ -723,13 +760,87 @@ bool MinidumpProcessor::GetProcessCreateTime(Minidump* dump,
return true;
}
+static bool IsCanonicalAddress(uint64_t address) {
+ uint64_t sign_bit = (address >> 63) & 1;
+ for (int shift = 48; shift < 63; ++shift) {
+ if (sign_bit != ((address >> shift) & 1)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+static void CalculateFaultAddressFromInstruction(Minidump* dump,
+ uint64_t* address) {
+ MinidumpException* exception = dump->GetException();
+ if (exception == NULL) {
+ BPLOG(INFO) << "Failed to get exception.";
+ return;
+ }
+
+ MinidumpContext* context = exception->GetContext();
+ if (context == NULL) {
+ BPLOG(INFO) << "Failed to get exception context.";
+ return;
+ }
+
+ uint64_t instruction_ptr = 0;
+ if (!context->GetInstructionPointer(&instruction_ptr)) {
+ BPLOG(INFO) << "Failed to get instruction pointer.";
+ return;
+ }
+
+ // Get memory region containing instruction pointer.
+ MinidumpMemoryList* memory_list = dump->GetMemoryList();
+ MinidumpMemoryRegion* memory_region =
+ memory_list ?
+ memory_list->GetMemoryRegionForAddress(instruction_ptr) : NULL;
+ if (!memory_region) {
+ BPLOG(INFO) << "No memory region around instruction pointer.";
+ return;
+ }
+
+ DisassemblerObjdump disassembler(context->GetContextCPU(), memory_region,
+ instruction_ptr);
+ fprintf(stderr, "%s %s %s\n", disassembler.operation().c_str(),
+ disassembler.src().c_str(), disassembler.dest().c_str());
+ if (!disassembler.IsValid()) {
+ BPLOG(INFO) << "Disassembling fault instruction failed.";
+ return;
+ }
+
+ // It's possible that we reach here when the faulting address is already
+ // correct, so we only update it if we find that at least one of the src/dest
+ // addresses is non-canonical. If both are non-canonical, we arbitrarily set
+ // it to the larger of the two, as this is more likely to be a known poison
+ // value.
+
+ bool valid_read, valid_write;
+ uint64_t read_address, write_address;
+
+ valid_read = disassembler.CalculateSrcAddress(*context, read_address);
+ valid_read &= !IsCanonicalAddress(read_address);
+
+ valid_write = disassembler.CalculateDestAddress(*context, write_address);
+ valid_write &= !IsCanonicalAddress(write_address);
+
+ if (valid_read && valid_write) {
+ *address = read_address > write_address ? read_address : write_address;
+ } else if (valid_read) {
+ *address = read_address;
+ } else if (valid_write) {
+ *address = write_address;
+ }
+}
+
// static
-string MinidumpProcessor::GetCrashReason(Minidump *dump, uint64_t *address) {
- MinidumpException *exception = dump->GetException();
+string MinidumpProcessor::GetCrashReason(Minidump* dump, uint64_t* address,
+ bool enable_objdump) {
+ MinidumpException* exception = dump->GetException();
if (!exception)
return "";
- const MDRawExceptionStream *raw_exception = exception->exception();
+ const MDRawExceptionStream* raw_exception = exception->exception();
if (!raw_exception)
return "";
@@ -749,7 +860,7 @@ string MinidumpProcessor::GetCrashReason(Minidump *dump, uint64_t *address) {
flags_string);
string reason = reason_string;
- const MDRawSystemInfo *raw_system_info = GetSystemInfo(dump, NULL);
+ const MDRawSystemInfo* raw_system_info = GetSystemInfo(dump, NULL);
if (!raw_system_info)
return reason;
@@ -1132,9 +1243,20 @@ string MinidumpProcessor::GetCrashReason(Minidump *dump, uint64_t *address) {
reason = "EXC_RPC_ALERT / ";
reason.append(flags_string);
break;
+ case MD_EXCEPTION_MAC_RESOURCE:
+ reason = "EXC_RESOURCE / ";
+ reason.append(flags_string);
+ break;
+ case MD_EXCEPTION_MAC_GUARD:
+ reason = "EXC_GUARD / ";
+ reason.append(flags_string);
+ break;
case MD_EXCEPTION_MAC_SIMULATED:
reason = "Simulated Exception";
break;
+ case MD_NS_EXCEPTION_SIMULATED:
+ reason = "Uncaught NSException";
+ break;
}
break;
}
@@ -1291,7 +1413,220 @@ string MinidumpProcessor::GetCrashReason(Minidump *dump, uint64_t *address) {
reason = "EXCEPTION_POSSIBLE_DEADLOCK";
break;
case MD_EXCEPTION_CODE_WIN_STACK_BUFFER_OVERRUN:
- reason = "EXCEPTION_STACK_BUFFER_OVERRUN";
+ if (raw_exception->exception_record.number_parameters >= 1) {
+ MDFastFailSubcodeTypeWin subcode =
+ static_cast<MDFastFailSubcodeTypeWin>(
+ raw_exception->exception_record.exception_information[0]);
+ switch (subcode) {
+ // Note - we skip the '0'/GS case as it exists for legacy reasons.
+ case MD_FAST_FAIL_VTGUARD_CHECK_FAILURE:
+ reason = "FAST_FAIL_VTGUARD_CHECK_FAILURE";
+ break;
+ case MD_FAST_FAIL_STACK_COOKIE_CHECK_FAILURE:
+ reason = "FAST_FAIL_STACK_COOKIE_CHECK_FAILURE";
+ break;
+ case MD_FAST_FAIL_CORRUPT_LIST_ENTRY:
+ reason = "FAST_FAIL_CORRUPT_LIST_ENTRY";
+ break;
+ case MD_FAST_FAIL_INCORRECT_STACK:
+ reason = "FAST_FAIL_INCORRECT_STACK";
+ break;
+ case MD_FAST_FAIL_INVALID_ARG:
+ reason = "FAST_FAIL_INVALID_ARG";
+ break;
+ case MD_FAST_FAIL_GS_COOKIE_INIT:
+ reason = "FAST_FAIL_GS_COOKIE_INIT";
+ break;
+ case MD_FAST_FAIL_FATAL_APP_EXIT:
+ reason = "FAST_FAIL_FATAL_APP_EXIT";
+ break;
+ case MD_FAST_FAIL_RANGE_CHECK_FAILURE:
+ reason = "FAST_FAIL_RANGE_CHECK_FAILURE";
+ break;
+ case MD_FAST_FAIL_UNSAFE_REGISTRY_ACCESS:
+ reason = "FAST_FAIL_UNSAFE_REGISTRY_ACCESS";
+ break;
+ case MD_FAST_FAIL_GUARD_ICALL_CHECK_FAILURE:
+ reason = "FAST_FAIL_GUARD_ICALL_CHECK_FAILURE";
+ break;
+ case MD_FAST_FAIL_GUARD_WRITE_CHECK_FAILURE:
+ reason = "FAST_FAIL_GUARD_WRITE_CHECK_FAILURE";
+ break;
+ case MD_FAST_FAIL_INVALID_FIBER_SWITCH:
+ reason = "FAST_FAIL_INVALID_FIBER_SWITCH";
+ break;
+ case MD_FAST_FAIL_INVALID_SET_OF_CONTEXT:
+ reason = "FAST_FAIL_INVALID_SET_OF_CONTEXT";
+ break;
+ case MD_FAST_FAIL_INVALID_REFERENCE_COUNT:
+ reason = "FAST_FAIL_INVALID_REFERENCE_COUNT";
+ break;
+ case MD_FAST_FAIL_INVALID_JUMP_BUFFER:
+ reason = "FAST_FAIL_INVALID_JUMP_BUFFER";
+ break;
+ case MD_FAST_FAIL_MRDATA_MODIFIED:
+ reason = "FAST_FAIL_MRDATA_MODIFIED";
+ break;
+ case MD_FAST_FAIL_CERTIFICATION_FAILURE:
+ reason = "FAST_FAIL_CERTIFICATION_FAILURE";
+ break;
+ case MD_FAST_FAIL_INVALID_EXCEPTION_CHAIN:
+ reason = "FAST_FAIL_INVALID_EXCEPTION_CHAIN";
+ break;
+ case MD_FAST_FAIL_CRYPTO_LIBRARY:
+ reason = "FAST_FAIL_CRYPTO_LIBRARY";
+ break;
+ case MD_FAST_FAIL_INVALID_CALL_IN_DLL_CALLOUT:
+ reason = "FAST_FAIL_INVALID_CALL_IN_DLL_CALLOUT";
+ break;
+ case MD_FAST_FAIL_INVALID_IMAGE_BASE:
+ reason = "FAST_FAIL_INVALID_IMAGE_BASE";
+ break;
+ case MD_FAST_FAIL_DLOAD_PROTECTION_FAILURE:
+ reason = "FAST_FAIL_DLOAD_PROTECTION_FAILURE";
+ break;
+ case MD_FAST_FAIL_UNSAFE_EXTENSION_CALL:
+ reason = "FAST_FAIL_UNSAFE_EXTENSION_CALL";
+ break;
+ case MD_FAST_FAIL_DEPRECATED_SERVICE_INVOKED:
+ reason = "FAST_FAIL_DEPRECATED_SERVICE_INVOKED";
+ break;
+ case MD_FAST_FAIL_INVALID_BUFFER_ACCESS:
+ reason = "FAST_FAIL_INVALID_BUFFER_ACCESS";
+ break;
+ case MD_FAST_FAIL_INVALID_BALANCED_TREE:
+ reason = "FAST_FAIL_INVALID_BALANCED_TREE";
+ break;
+ case MD_FAST_FAIL_INVALID_NEXT_THREAD:
+ reason = "FAST_FAIL_INVALID_NEXT_THREAD";
+ break;
+ case MD_FAST_FAIL_GUARD_ICALL_CHECK_SUPPRESSED:
+ reason = "FAST_FAIL_GUARD_ICALL_CHECK_SUPPRESSED";
+ break;
+ case MD_FAST_FAIL_APCS_DISABLED:
+ reason = "FAST_FAIL_APCS_DISABLED";
+ break;
+ case MD_FAST_FAIL_INVALID_IDLE_STATE:
+ reason = "FAST_FAIL_INVALID_IDLE_STATE";
+ break;
+ case MD_FAST_FAIL_MRDATA_PROTECTION_FAILURE:
+ reason = "FAST_FAIL_MRDATA_PROTECTION_FAILURE";
+ break;
+ case MD_FAST_FAIL_UNEXPECTED_HEAP_EXCEPTION:
+ reason = "FAST_FAIL_UNEXPECTED_HEAP_EXCEPTION";
+ break;
+ case MD_FAST_FAIL_INVALID_LOCK_STATE:
+ reason = "FAST_FAIL_INVALID_LOCK_STATE";
+ break;
+ case MD_FAST_FAIL_GUARD_JUMPTABLE:
+ reason = "FAST_FAIL_GUARD_JUMPTABLE";
+ break;
+ case MD_FAST_FAIL_INVALID_LONGJUMP_TARGET:
+ reason = "FAST_FAIL_INVALID_LONGJUMP_TARGET";
+ break;
+ case MD_FAST_FAIL_INVALID_DISPATCH_CONTEXT:
+ reason = "FAST_FAIL_INVALID_DISPATCH_CONTEXT";
+ break;
+ case MD_FAST_FAIL_INVALID_THREAD:
+ reason = "FAST_FAIL_INVALID_THREAD";
+ break;
+ case MD_FAST_FAIL_INVALID_SYSCALL_NUMBER:
+ reason = "FAST_FAIL_INVALID_SYSCALL_NUMBER";
+ break;
+ case MD_FAST_FAIL_INVALID_FILE_OPERATION:
+ reason = "FAST_FAIL_INVALID_FILE_OPERATION";
+ break;
+ case MD_FAST_FAIL_LPAC_ACCESS_DENIED:
+ reason = "FAST_FAIL_LPAC_ACCESS_DENIED";
+ break;
+ case MD_FAST_FAIL_GUARD_SS_FAILURE:
+ reason = "FAST_FAIL_GUARD_SS_FAILURE";
+ break;
+ case MD_FAST_FAIL_LOADER_CONTINUITY_FAILURE:
+ reason = "FAST_FAIL_LOADER_CONTINUITY_FAILURE";
+ break;
+ case MD_FAST_FAIL_GUARD_EXPORT_SUPPRESSION_FAILURE:
+ reason = "FAST_FAIL_GUARD_EXPORT_SUPPRESSION_FAILURE";
+ break;
+ case MD_FAST_FAIL_INVALID_CONTROL_STACK:
+ reason = "FAST_FAIL_INVALID_CONTROL_STACK";
+ break;
+ case MD_FAST_FAIL_SET_CONTEXT_DENIED:
+ reason = "FAST_FAIL_SET_CONTEXT_DENIED";
+ break;
+ case MD_FAST_FAIL_INVALID_IAT:
+ reason = "FAST_FAIL_INVALID_IAT";
+ break;
+ case MD_FAST_FAIL_HEAP_METADATA_CORRUPTION:
+ reason = "FAST_FAIL_HEAP_METADATA_CORRUPTION";
+ break;
+ case MD_FAST_FAIL_PAYLOAD_RESTRICTION_VIOLATION:
+ reason = "FAST_FAIL_PAYLOAD_RESTRICTION_VIOLATION";
+ break;
+ case MD_FAST_FAIL_LOW_LABEL_ACCESS_DENIED:
+ reason = "FAST_FAIL_LOW_LABEL_ACCESS_DENIED";
+ break;
+ case MD_FAST_FAIL_ENCLAVE_CALL_FAILURE:
+ reason = "FAST_FAIL_ENCLAVE_CALL_FAILURE";
+ break;
+ case MD_FAST_FAIL_UNHANDLED_LSS_EXCEPTON:
+ reason = "FAST_FAIL_UNHANDLED_LSS_EXCEPTON";
+ break;
+ case MD_FAST_FAIL_ADMINLESS_ACCESS_DENIED:
+ reason = "FAST_FAIL_ADMINLESS_ACCESS_DENIED";
+ break;
+ case MD_FAST_FAIL_UNEXPECTED_CALL:
+ reason = "FAST_FAIL_UNEXPECTED_CALL";
+ break;
+ case MD_FAST_FAIL_CONTROL_INVALID_RETURN_ADDRESS:
+ reason = "FAST_FAIL_CONTROL_INVALID_RETURN_ADDRESS";
+ break;
+ case MD_FAST_FAIL_UNEXPECTED_HOST_BEHAVIOR:
+ reason = "FAST_FAIL_UNEXPECTED_HOST_BEHAVIOR";
+ break;
+ case MD_FAST_FAIL_FLAGS_CORRUPTION:
+ reason = "FAST_FAIL_FLAGS_CORRUPTION";
+ break;
+ case MD_FAST_FAIL_VEH_CORRUPTION:
+ reason = "FAST_FAIL_VEH_CORRUPTION";
+ break;
+ case MD_FAST_FAIL_ETW_CORRUPTION:
+ reason = "FAST_FAIL_ETW_CORRUPTION";
+ break;
+ case MD_FAST_FAIL_RIO_ABORT:
+ reason = "FAST_FAIL_RIO_ABORT";
+ break;
+ case MD_FAST_FAIL_INVALID_PFN:
+ reason = "FAST_FAIL_INVALID_PFN";
+ break;
+ case MD_FAST_FAIL_GUARD_ICALL_CHECK_FAILURE_XFG:
+ reason = "FAST_FAIL_GUARD_ICALL_CHECK_FAILURE_XFG";
+ break;
+ case MD_FAST_FAIL_CAST_GUARD:
+ reason = "FAST_FAIL_CAST_GUARD";
+ break;
+ case MD_FAST_FAIL_HOST_VISIBILITY_CHANGE:
+ reason = "FAST_FAIL_HOST_VISIBILITY_CHANGE";
+ break;
+ case MD_FAST_FAIL_KERNEL_CET_SHADOW_STACK_ASSIST:
+ reason = "FAST_FAIL_KERNEL_CET_SHADOW_STACK_ASSIST";
+ break;
+ case MD_FAST_FAIL_PATCH_CALLBACK_FAILED:
+ reason = "FAST_FAIL_PATCH_CALLBACK_FAILED";
+ break;
+ case MD_FAST_FAIL_NTDLL_PATCH_FAILED:
+ reason = "FAST_FAIL_NTDLL_PATCH_FAILED";
+ break;
+ case MD_FAST_FAIL_INVALID_FLS_DATA:
+ reason = "FAST_FAIL_INVALID_FLS_DATA";
+ break;
+ default:
+ reason = "EXCEPTION_STACK_BUFFER_OVERRUN";
+ break;
+ }
+ } else {
+ reason = "EXCEPTION_STACK_BUFFER_OVERRUN";
+ }
break;
case MD_EXCEPTION_CODE_WIN_HEAP_CORRUPTION:
reason = "EXCEPTION_HEAP_CORRUPTION";
@@ -1734,18 +2069,27 @@ string MinidumpProcessor::GetCrashReason(Minidump *dump, uint64_t *address) {
*address = GetAddressForArchitecture(
static_cast<MDCPUArchitecture>(raw_system_info->processor_architecture),
*address);
+
+ // For invalid accesses to non-canonical addresses, amd64 cpus don't provide
+ // the fault address, so recover it from the disassembly and register state
+ // if possible.
+ if (enable_objdump
+ && raw_system_info->processor_architecture == MD_CPU_ARCHITECTURE_AMD64
+ && std::numeric_limits<uint64_t>::max() == *address) {
+ CalculateFaultAddressFromInstruction(dump, address);
+ }
}
return reason;
}
// static
-string MinidumpProcessor::GetAssertion(Minidump *dump) {
- MinidumpAssertion *assertion = dump->GetAssertion();
+string MinidumpProcessor::GetAssertion(Minidump* dump) {
+ MinidumpAssertion* assertion = dump->GetAssertion();
if (!assertion)
return "";
- const MDRawAssertionInfo *raw_assertion = assertion->assertion();
+ const MDRawAssertionInfo* raw_assertion = assertion->assertion();
if (!raw_assertion)
return "";
diff --git a/src/processor/minidump_processor_unittest.cc b/src/processor/minidump_processor_unittest.cc
index a4ac3685..1ca8c9fb 100644
--- a/src/processor/minidump_processor_unittest.cc
+++ b/src/processor/minidump_processor_unittest.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2006, Google Inc.
-// All rights reserved.
+// Copyright 2006 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -127,16 +126,16 @@ class MockMinidumpMemoryRegion : public MinidumpMemoryRegion {
uint64_t GetBase() const { return region_.GetBase(); }
uint32_t GetSize() const { return region_.GetSize(); }
- bool GetMemoryAtAddress(uint64_t address, uint8_t *value) const {
+ bool GetMemoryAtAddress(uint64_t address, uint8_t* value) const {
return region_.GetMemoryAtAddress(address, value);
}
- bool GetMemoryAtAddress(uint64_t address, uint16_t *value) const {
+ bool GetMemoryAtAddress(uint64_t address, uint16_t* value) const {
return region_.GetMemoryAtAddress(address, value);
}
- bool GetMemoryAtAddress(uint64_t address, uint32_t *value) const {
+ bool GetMemoryAtAddress(uint64_t address, uint32_t* value) const {
return region_.GetMemoryAtAddress(address, value);
}
- bool GetMemoryAtAddress(uint64_t address, uint64_t *value) const {
+ bool GetMemoryAtAddress(uint64_t address, uint64_t* value) const {
return region_.GetMemoryAtAddress(address, value);
}
@@ -188,11 +187,11 @@ using ::testing::Property;
using ::testing::Return;
using ::testing::SetArgumentPointee;
-static const char *kSystemInfoOS = "Windows NT";
-static const char *kSystemInfoOSShort = "windows";
-static const char *kSystemInfoOSVersion = "5.1.2600 Service Pack 2";
-static const char *kSystemInfoCPU = "x86";
-static const char *kSystemInfoCPUInfo =
+static const char* kSystemInfoOS = "Windows NT";
+static const char* kSystemInfoOSShort = "windows";
+static const char* kSystemInfoOSVersion = "5.1.2600 Service Pack 2";
+static const char* kSystemInfoCPU = "x86";
+static const char* kSystemInfoCPUInfo =
"GenuineIntel family 6 model 13 stepping 8";
#define ASSERT_TRUE_ABORT(cond) \
@@ -204,7 +203,7 @@ static const char *kSystemInfoCPUInfo =
#define ASSERT_EQ_ABORT(e1, e2) ASSERT_TRUE_ABORT((e1) == (e2))
static string GetTestDataPath() {
- char *srcdir = getenv("srcdir");
+ char* srcdir = getenv("srcdir");
return string(srcdir ? srcdir : ".") + "/src/processor/testdata/";
}
@@ -213,35 +212,35 @@ class TestSymbolSupplier : public SymbolSupplier {
public:
TestSymbolSupplier() : interrupt_(false) {}
- virtual SymbolResult GetSymbolFile(const CodeModule *module,
- const SystemInfo *system_info,
- string *symbol_file);
+ virtual SymbolResult GetSymbolFile(const CodeModule* module,
+ const SystemInfo* system_info,
+ string* symbol_file);
- virtual SymbolResult GetSymbolFile(const CodeModule *module,
- const SystemInfo *system_info,
- string *symbol_file,
- string *symbol_data);
+ virtual SymbolResult GetSymbolFile(const CodeModule* module,
+ const SystemInfo* system_info,
+ string* symbol_file,
+ string* symbol_data);
- virtual SymbolResult GetCStringSymbolData(const CodeModule *module,
- const SystemInfo *system_info,
- string *symbol_file,
- char **symbol_data,
- size_t *symbol_data_size);
+ virtual SymbolResult GetCStringSymbolData(const CodeModule* module,
+ const SystemInfo* system_info,
+ string* symbol_file,
+ char** symbol_data,
+ size_t* symbol_data_size);
- virtual void FreeSymbolData(const CodeModule *module);
+ virtual void FreeSymbolData(const CodeModule* module);
// When set to true, causes the SymbolSupplier to return INTERRUPT
void set_interrupt(bool interrupt) { interrupt_ = interrupt; }
private:
bool interrupt_;
- map<string, char *> memory_buffers_;
+ map<string, char*> memory_buffers_;
};
SymbolSupplier::SymbolResult TestSymbolSupplier::GetSymbolFile(
- const CodeModule *module,
- const SystemInfo *system_info,
- string *symbol_file) {
+ const CodeModule* module,
+ const SystemInfo* system_info,
+ string* symbol_file) {
ASSERT_TRUE_ABORT(module);
ASSERT_TRUE_ABORT(system_info);
ASSERT_EQ_ABORT(system_info->cpu, kSystemInfoCPU);
@@ -264,10 +263,10 @@ SymbolSupplier::SymbolResult TestSymbolSupplier::GetSymbolFile(
}
SymbolSupplier::SymbolResult TestSymbolSupplier::GetSymbolFile(
- const CodeModule *module,
- const SystemInfo *system_info,
- string *symbol_file,
- string *symbol_data) {
+ const CodeModule* module,
+ const SystemInfo* system_info,
+ string* symbol_file,
+ string* symbol_data) {
SymbolSupplier::SymbolResult s = GetSymbolFile(module, system_info,
symbol_file);
if (s == FOUND) {
@@ -281,11 +280,11 @@ SymbolSupplier::SymbolResult TestSymbolSupplier::GetSymbolFile(
}
SymbolSupplier::SymbolResult TestSymbolSupplier::GetCStringSymbolData(
- const CodeModule *module,
- const SystemInfo *system_info,
- string *symbol_file,
- char **symbol_data,
- size_t *symbol_data_size) {
+ const CodeModule* module,
+ const SystemInfo* system_info,
+ string* symbol_file,
+ char** symbol_data,
+ size_t* symbol_data_size) {
string symbol_data_string;
SymbolSupplier::SymbolResult s = GetSymbolFile(module,
system_info,
@@ -307,8 +306,8 @@ SymbolSupplier::SymbolResult TestSymbolSupplier::GetCStringSymbolData(
return s;
}
-void TestSymbolSupplier::FreeSymbolData(const CodeModule *module) {
- map<string, char *>::iterator it = memory_buffers_.find(module->code_file());
+void TestSymbolSupplier::FreeSymbolData(const CodeModule* module) {
+ map<string, char*>::iterator it = memory_buffers_.find(module->code_file());
if (it != memory_buffers_.end()) {
delete [] it->second;
memory_buffers_.erase(it);
@@ -523,7 +522,7 @@ TEST_F(MinidumpProcessorTest, TestBasicProcessing) {
EXPECT_EQ(1171480435U, state.time_date_stamp());
EXPECT_EQ(1171480435U, state.process_create_time());
- CallStack *stack = state.threads()->at(0);
+ CallStack* stack = state.threads()->at(0);
ASSERT_TRUE(stack);
ASSERT_EQ(stack->frames()->size(), 4U);
@@ -761,9 +760,67 @@ TEST_F(MinidumpProcessorTest, Test32BitCrashingAddress) {
ASSERT_EQ(state.crash_address(), 0x45U);
}
+TEST_F(MinidumpProcessorTest, TestXStateAmd64ContextMinidump) {
+ // This tests if we can passively process a minidump with cet registers in its
+ // context. Dump is captured from a toy executable and is readable by windbg.
+ MinidumpProcessor processor(nullptr, nullptr /*&supplier, &resolver*/);
+
+ string minidump_file = GetTestDataPath()
+ + "tiny-exe-with-cet-xsave.dmp";
+
+ ProcessState state;
+ ASSERT_EQ(processor.Process(minidump_file, &state),
+ google_breakpad::PROCESS_OK);
+ ASSERT_EQ(state.system_info()->os, "Windows NT");
+ ASSERT_EQ(state.system_info()->os_version, "10.0.22000 282");
+ ASSERT_EQ(state.system_info()->cpu, "amd64");
+ ASSERT_EQ(state.system_info()->cpu_info,
+ "family 6 model 140 stepping 1");
+ ASSERT_FALSE(state.crashed());
+ ASSERT_EQ(state.threads()->size(), size_t(1));
+
+ // TODO: verify cetumsr and cetussp once these are supported by
+ // breakpad.
+}
+
+TEST_F(MinidumpProcessorTest, TestFastFailException) {
+ // This tests if we can understand fastfail exception subcodes.
+ // Dump is captured from a toy executable and is readable by windbg.
+ MinidumpProcessor processor(nullptr, nullptr /*&supplier, &resolver*/);
+
+ string minidump_file = GetTestDataPath()
+ + "tiny-exe-fastfail.dmp";
+
+ ProcessState state;
+ ASSERT_EQ(processor.Process(minidump_file, &state),
+ google_breakpad::PROCESS_OK);
+ ASSERT_TRUE(state.crashed());
+ ASSERT_EQ(state.threads()->size(), size_t(4));
+ ASSERT_EQ(state.crash_reason(), "FAST_FAIL_FATAL_APP_EXIT");
+}
+
+#ifdef __linux__
+TEST_F(MinidumpProcessorTest, TestNonCanonicalAddress) {
+ // This tests if we can correctly fixup non-canonical address GPF fault
+ // addresses.
+ // Dump is captured from a toy executable and is readable by windbg.
+ MinidumpProcessor processor(nullptr, nullptr /*&supplier, &resolver*/);
+ processor.set_enable_objdump(true);
+
+ string minidump_file = GetTestDataPath()
+ + "write_av_non_canonical.dmp";
+
+ ProcessState state;
+ ASSERT_EQ(processor.Process(minidump_file, &state),
+ google_breakpad::PROCESS_OK);
+ ASSERT_TRUE(state.crashed());
+ ASSERT_EQ(state.crash_address(), 0xfefefefefefefefeU);
+}
+#endif // __linux__
+
} // namespace
-int main(int argc, char *argv[]) {
+int main(int argc, char* argv[]) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
diff --git a/src/processor/minidump_stackwalk.cc b/src/processor/minidump_stackwalk.cc
index acf80972..cee9a734 100644
--- a/src/processor/minidump_stackwalk.cc
+++ b/src/processor/minidump_stackwalk.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2010 Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -57,6 +56,7 @@ namespace {
struct Options {
bool machine_readable;
bool output_stack_contents;
+ bool output_requesting_thread_only;
string minidump_file;
std::vector<string> symbol_paths;
@@ -111,7 +111,8 @@ bool PrintMinidumpProcess(const Options& options) {
if (options.machine_readable) {
PrintProcessStateMachineReadable(process_state);
} else {
- PrintProcessState(process_state, options.output_stack_contents, &resolver);
+ PrintProcessState(process_state, options.output_stack_contents,
+ options.output_requesting_thread_only, &resolver);
}
return true;
@@ -128,7 +129,8 @@ static void Usage(int argc, const char *argv[], bool error) {
"Options:\n"
"\n"
" -m Output in machine-readable format\n"
- " -s Output stack contents\n",
+ " -s Output stack contents\n"
+ " -c Output thread that causes crash or dump only\n",
google_breakpad::BaseName(argv[0]).c_str());
}
@@ -137,14 +139,18 @@ static void SetupOptions(int argc, const char *argv[], Options* options) {
options->machine_readable = false;
options->output_stack_contents = false;
+ options->output_requesting_thread_only = false;
- while ((ch = getopt(argc, (char * const *)argv, "hms")) != -1) {
+ while ((ch = getopt(argc, (char * const*)argv, "chms")) != -1) {
switch (ch) {
case 'h':
Usage(argc, argv, false);
exit(0);
break;
+ case 'c':
+ options->output_requesting_thread_only = true;
+ break;
case 'm':
options->machine_readable = true;
break;
diff --git a/src/processor/minidump_stackwalk_machine_readable_test b/src/processor/minidump_stackwalk_machine_readable_test
index 2aadb241..84672183 100755
--- a/src/processor/minidump_stackwalk_machine_readable_test
+++ b/src/processor/minidump_stackwalk_machine_readable_test
@@ -1,7 +1,6 @@
#!/bin/sh
-# Copyright (c) 2007, Google Inc.
-# All rights reserved.
+# Copyright 2007 Google LLC
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
@@ -13,7 +12,7 @@
# copyright notice, this list of conditions and the following disclaimer
# in the documentation and/or other materials provided with the
# distribution.
-# * Neither the name of Google Inc. nor the names of its
+# * Neither the name of Google LLC nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
diff --git a/src/processor/minidump_stackwalk_test b/src/processor/minidump_stackwalk_test
index f9790279..c7da9c4a 100755
--- a/src/processor/minidump_stackwalk_test
+++ b/src/processor/minidump_stackwalk_test
@@ -1,7 +1,6 @@
#!/bin/sh
-# Copyright (c) 2006, Google Inc.
-# All rights reserved.
+# Copyright 2006 Google LLC
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
@@ -13,7 +12,7 @@
# copyright notice, this list of conditions and the following disclaimer
# in the documentation and/or other materials provided with the
# distribution.
-# * Neither the name of Google Inc. nor the names of its
+# * Neither the name of Google LLC nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
diff --git a/src/processor/minidump_unittest.cc b/src/processor/minidump_unittest.cc
index 036d03f1..53d44ae1 100644
--- a/src/processor/minidump_unittest.cc
+++ b/src/processor/minidump_unittest.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2010, Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -48,6 +47,7 @@ namespace {
using google_breakpad::Minidump;
using google_breakpad::MinidumpContext;
+using google_breakpad::MinidumpCrashpadInfo;
using google_breakpad::MinidumpException;
using google_breakpad::MinidumpMemoryInfo;
using google_breakpad::MinidumpMemoryInfoList;
@@ -95,9 +95,9 @@ TEST_F(MinidumpTest, TestMinidumpFromFile) {
ASSERT_NE(header, (MDRawHeader*)NULL);
ASSERT_EQ(header->signature, uint32_t(MD_HEADER_SIGNATURE));
- MinidumpModuleList *md_module_list = minidump.GetModuleList();
+ MinidumpModuleList* md_module_list = minidump.GetModuleList();
ASSERT_TRUE(md_module_list != NULL);
- const MinidumpModule *md_module = md_module_list->GetModuleAtIndex(0);
+ const MinidumpModule* md_module = md_module_list->GetModuleAtIndex(0);
ASSERT_TRUE(md_module != NULL);
ASSERT_EQ("c:\\test_app.exe", md_module->code_file());
ASSERT_EQ("c:\\test_app.pdb", md_module->debug_file());
@@ -131,6 +131,42 @@ TEST_F(MinidumpTest, TestMinidumpFromStream) {
//TODO: add more checks here
}
+TEST_F(MinidumpTest, TestMinidumpWithCrashpadAnnotations) {
+ string crashpad_minidump_file =
+ string(getenv("srcdir") ? getenv("srcdir") : ".") +
+ "/src/processor/testdata/minidump_crashpad_annotation.dmp";
+
+ Minidump minidump(crashpad_minidump_file);
+ ASSERT_EQ(minidump.path(), crashpad_minidump_file);
+ ASSERT_TRUE(minidump.Read());
+
+ MinidumpCrashpadInfo* crashpad_info = minidump.GetCrashpadInfo();
+ ASSERT_TRUE(crashpad_info != NULL);
+
+ const std::vector<std::vector<MinidumpCrashpadInfo::AnnotationObject>>*
+ annotation_objects_list =
+ crashpad_info->GetModuleCrashpadInfoAnnotationObjects();
+ ASSERT_EQ(2U, annotation_objects_list->size());
+
+ std::vector<MinidumpCrashpadInfo::AnnotationObject> annotation_objects =
+ annotation_objects_list->at(0);
+ ASSERT_EQ(5U, annotation_objects.size());
+
+ std::vector<std::string> annotation_names;
+ for (size_t i = 0; i < annotation_objects.size(); i++) {
+ MinidumpCrashpadInfo::AnnotationObject annotation_object =
+ annotation_objects.at(i);
+ annotation_names.push_back(annotation_object.name);
+ ASSERT_TRUE(annotation_object.type > 0);
+ ASSERT_TRUE(annotation_object.value.size() > 0);
+ }
+
+ std::vector<std::string> expected_strings{
+ "exceptionReason", "exceptionName", "firstexception_bt", "firstexception",
+ "CounterAnnotation"};
+ ASSERT_EQ(annotation_names, expected_strings);
+}
+
TEST(Dump, ReadBackEmpty) {
Dump dump(0);
dump.Finish();
@@ -167,7 +203,7 @@ TEST(Dump, OneStream) {
ASSERT_TRUE(minidump.Read());
ASSERT_EQ(1U, minidump.GetDirectoryEntryCount());
- const MDRawDirectory *dir = minidump.GetDirectoryEntryAtIndex(0);
+ const MDRawDirectory* dir = minidump.GetDirectoryEntryAtIndex(0);
ASSERT_TRUE(dir != NULL);
EXPECT_EQ(0xfbb7fa2bU, dir->stream_type);
@@ -203,18 +239,18 @@ TEST(Dump, OneMemory) {
ASSERT_TRUE(minidump.Read());
ASSERT_EQ(1U, minidump.GetDirectoryEntryCount());
- const MDRawDirectory *dir = minidump.GetDirectoryEntryAtIndex(0);
+ const MDRawDirectory* dir = minidump.GetDirectoryEntryAtIndex(0);
ASSERT_TRUE(dir != NULL);
EXPECT_EQ((uint32_t) MD_MEMORY_LIST_STREAM, dir->stream_type);
- MinidumpMemoryList *memory_list = minidump.GetMemoryList();
+ MinidumpMemoryList* memory_list = minidump.GetMemoryList();
ASSERT_TRUE(memory_list != NULL);
ASSERT_EQ(1U, memory_list->region_count());
- MinidumpMemoryRegion *region1 = memory_list->GetMemoryRegionAtIndex(0);
+ MinidumpMemoryRegion* region1 = memory_list->GetMemoryRegionAtIndex(0);
ASSERT_EQ(0x309d68010bd21b2cULL, region1->GetBase());
ASSERT_EQ(15U, region1->GetSize());
- const uint8_t *region1_bytes = region1->GetMemory();
+ const uint8_t* region1_bytes = region1->GetMemory();
ASSERT_TRUE(memcmp("memory contents", region1_bytes, 15) == 0);
}
@@ -257,33 +293,33 @@ TEST(Dump, OneThread) {
ASSERT_TRUE(minidump.Read());
ASSERT_EQ(2U, minidump.GetDirectoryEntryCount());
- MinidumpMemoryList *md_memory_list = minidump.GetMemoryList();
+ MinidumpMemoryList* md_memory_list = minidump.GetMemoryList();
ASSERT_TRUE(md_memory_list != NULL);
ASSERT_EQ(1U, md_memory_list->region_count());
- MinidumpMemoryRegion *md_region = md_memory_list->GetMemoryRegionAtIndex(0);
+ MinidumpMemoryRegion* md_region = md_memory_list->GetMemoryRegionAtIndex(0);
ASSERT_EQ(0x2326a0faU, md_region->GetBase());
ASSERT_EQ(16U, md_region->GetSize());
- const uint8_t *region_bytes = md_region->GetMemory();
+ const uint8_t* region_bytes = md_region->GetMemory();
ASSERT_TRUE(memcmp("stack for thread", region_bytes, 16) == 0);
- MinidumpThreadList *thread_list = minidump.GetThreadList();
+ MinidumpThreadList* thread_list = minidump.GetThreadList();
ASSERT_TRUE(thread_list != NULL);
ASSERT_EQ(1U, thread_list->thread_count());
- MinidumpThread *md_thread = thread_list->GetThreadAtIndex(0);
+ MinidumpThread* md_thread = thread_list->GetThreadAtIndex(0);
ASSERT_TRUE(md_thread != NULL);
uint32_t thread_id;
ASSERT_TRUE(md_thread->GetThreadID(&thread_id));
ASSERT_EQ(0xa898f11bU, thread_id);
- MinidumpMemoryRegion *md_stack = md_thread->GetMemory();
+ MinidumpMemoryRegion* md_stack = md_thread->GetMemory();
ASSERT_TRUE(md_stack != NULL);
ASSERT_EQ(0x2326a0faU, md_stack->GetBase());
ASSERT_EQ(16U, md_stack->GetSize());
- const uint8_t *md_stack_bytes = md_stack->GetMemory();
+ const uint8_t* md_stack_bytes = md_stack->GetMemory();
ASSERT_TRUE(memcmp("stack for thread", md_stack_bytes, 16) == 0);
- MinidumpContext *md_context = md_thread->GetContext();
+ MinidumpContext* md_context = md_thread->GetContext();
ASSERT_TRUE(md_context != NULL);
ASSERT_EQ((uint32_t) MD_CONTEXT_X86, md_context->GetContextCPU());
@@ -291,7 +327,7 @@ TEST(Dump, OneThread) {
ASSERT_TRUE(md_context->GetInstructionPointer(&eip));
EXPECT_EQ(kExpectedEIP, eip);
- const MDRawContextX86 *md_raw_context = md_context->GetContextX86();
+ const MDRawContextX86* md_raw_context = md_context->GetContextX86();
ASSERT_TRUE(md_raw_context != NULL);
ASSERT_EQ((uint32_t) (MD_CONTEXT_X86_INTEGER | MD_CONTEXT_X86_CONTROL),
(md_raw_context->context_flags
@@ -425,16 +461,16 @@ TEST(Dump, OneUnloadedModule) {
ASSERT_TRUE(minidump.Read());
ASSERT_EQ(2U, minidump.GetDirectoryEntryCount());
- const MDRawDirectory *dir = minidump.GetDirectoryEntryAtIndex(1);
+ const MDRawDirectory* dir = minidump.GetDirectoryEntryAtIndex(1);
ASSERT_TRUE(dir != NULL);
EXPECT_EQ((uint32_t) MD_UNLOADED_MODULE_LIST_STREAM, dir->stream_type);
- MinidumpUnloadedModuleList *md_unloaded_module_list =
+ MinidumpUnloadedModuleList* md_unloaded_module_list =
minidump.GetUnloadedModuleList();
ASSERT_TRUE(md_unloaded_module_list != NULL);
ASSERT_EQ(1U, md_unloaded_module_list->module_count());
- const MinidumpUnloadedModule *md_unloaded_module =
+ const MinidumpUnloadedModule* md_unloaded_module =
md_unloaded_module_list->GetModuleAtIndex(0);
ASSERT_TRUE(md_unloaded_module != NULL);
ASSERT_EQ(0xa90206ca83eb2852ULL, md_unloaded_module->base_address());
@@ -445,7 +481,7 @@ TEST(Dump, OneUnloadedModule) {
ASSERT_EQ("B1054D2Aada542bd", md_unloaded_module->code_identifier());
ASSERT_EQ("", md_unloaded_module->debug_identifier());
- const MDRawUnloadedModule *md_raw_unloaded_module =
+ const MDRawUnloadedModule* md_raw_unloaded_module =
md_unloaded_module->module();
ASSERT_TRUE(md_raw_unloaded_module != NULL);
ASSERT_EQ(0xb1054d2aU, md_raw_unloaded_module->time_date_stamp);
@@ -506,15 +542,15 @@ TEST(Dump, OneModule) {
ASSERT_TRUE(minidump.Read());
ASSERT_EQ(2U, minidump.GetDirectoryEntryCount());
- const MDRawDirectory *dir = minidump.GetDirectoryEntryAtIndex(1);
+ const MDRawDirectory* dir = minidump.GetDirectoryEntryAtIndex(1);
ASSERT_TRUE(dir != NULL);
EXPECT_EQ((uint32_t) MD_MODULE_LIST_STREAM, dir->stream_type);
- MinidumpModuleList *md_module_list = minidump.GetModuleList();
+ MinidumpModuleList* md_module_list = minidump.GetModuleList();
ASSERT_TRUE(md_module_list != NULL);
ASSERT_EQ(1U, md_module_list->module_count());
- const MinidumpModule *md_module = md_module_list->GetModuleAtIndex(0);
+ const MinidumpModule* md_module = md_module_list->GetModuleAtIndex(0);
ASSERT_TRUE(md_module != NULL);
ASSERT_EQ(0xa90206ca83eb2852ULL, md_module->base_address());
ASSERT_EQ(0xada542bd, md_module->size());
@@ -524,7 +560,7 @@ TEST(Dump, OneModule) {
ASSERT_EQ("B1054D2Aada542bd", md_module->code_identifier());
ASSERT_EQ("ABCD1234F00DBEEF01020304050607081", md_module->debug_identifier());
- const MDRawModule *md_raw_module = md_module->module();
+ const MDRawModule* md_raw_module = md_module->module();
ASSERT_TRUE(md_raw_module != NULL);
ASSERT_EQ(0xb1054d2aU, md_raw_module->time_date_stamp);
ASSERT_EQ(0x34571371U, md_raw_module->checksum);
@@ -588,11 +624,11 @@ TEST(Dump, OneModuleCVELF) {
Minidump minidump(minidump_stream);
ASSERT_TRUE(minidump.Read());
- MinidumpModuleList *md_module_list = minidump.GetModuleList();
+ MinidumpModuleList* md_module_list = minidump.GetModuleList();
ASSERT_TRUE(md_module_list != NULL);
ASSERT_EQ(1U, md_module_list->module_count());
- const MinidumpModule *md_module = md_module_list->GetModuleAtIndex(0);
+ const MinidumpModule* md_module = md_module_list->GetModuleAtIndex(0);
ASSERT_TRUE(md_module != NULL);
ASSERT_EQ(0xa90206ca83eb2852ULL, md_module->base_address());
ASSERT_EQ(0xada542bd, md_module->size());
@@ -606,7 +642,7 @@ TEST(Dump, OneModuleCVELF) {
// age appended
ASSERT_EQ("B4CDA95F53101BDF86FAB733B4DF37380", md_module->debug_identifier());
- const MDRawModule *md_raw_module = md_module->module();
+ const MDRawModule* md_raw_module = md_module->module();
ASSERT_TRUE(md_raw_module != NULL);
ASSERT_EQ(0xb1054d2aU, md_raw_module->time_date_stamp);
ASSERT_EQ(0x34571371U, md_raw_module->checksum);
@@ -670,11 +706,11 @@ TEST(Dump, CVELFShort) {
ASSERT_TRUE(minidump.Read());
ASSERT_EQ(2U, minidump.GetDirectoryEntryCount());
- MinidumpModuleList *md_module_list = minidump.GetModuleList();
+ MinidumpModuleList* md_module_list = minidump.GetModuleList();
ASSERT_TRUE(md_module_list != NULL);
ASSERT_EQ(1U, md_module_list->module_count());
- const MinidumpModule *md_module = md_module_list->GetModuleAtIndex(0);
+ const MinidumpModule* md_module = md_module_list->GetModuleAtIndex(0);
ASSERT_TRUE(md_module != NULL);
// just the build_id, directly
ASSERT_EQ("5fa9cdb4", md_module->code_identifier());
@@ -742,11 +778,11 @@ TEST(Dump, CVELFLong) {
ASSERT_TRUE(minidump.Read());
ASSERT_EQ(2U, minidump.GetDirectoryEntryCount());
- MinidumpModuleList *md_module_list = minidump.GetModuleList();
+ MinidumpModuleList* md_module_list = minidump.GetModuleList();
ASSERT_TRUE(md_module_list != NULL);
ASSERT_EQ(1U, md_module_list->module_count());
- const MinidumpModule *md_module = md_module_list->GetModuleAtIndex(0);
+ const MinidumpModule* md_module = md_module_list->GetModuleAtIndex(0);
ASSERT_TRUE(md_module != NULL);
// just the build_id, directly
ASSERT_EQ(
@@ -773,11 +809,11 @@ TEST(Dump, OneSystemInfo) {
ASSERT_TRUE(minidump.Read());
ASSERT_EQ(1U, minidump.GetDirectoryEntryCount());
- const MDRawDirectory *dir = minidump.GetDirectoryEntryAtIndex(0);
+ const MDRawDirectory* dir = minidump.GetDirectoryEntryAtIndex(0);
ASSERT_TRUE(dir != NULL);
EXPECT_EQ((uint32_t) MD_SYSTEM_INFO_STREAM, dir->stream_type);
- MinidumpSystemInfo *md_system_info = minidump.GetSystemInfo();
+ MinidumpSystemInfo* md_system_info = minidump.GetSystemInfo();
ASSERT_TRUE(md_system_info != NULL);
ASSERT_EQ("windows", md_system_info->GetOS());
ASSERT_EQ("x86", md_system_info->GetCPU());
@@ -912,7 +948,7 @@ TEST(Dump, BigDump) {
ASSERT_EQ(5U, minidump.GetDirectoryEntryCount());
// Check the threads.
- MinidumpThreadList *thread_list = minidump.GetThreadList();
+ MinidumpThreadList* thread_list = minidump.GetThreadList();
ASSERT_TRUE(thread_list != NULL);
ASSERT_EQ(5U, thread_list->thread_count());
uint32_t thread_id;
@@ -957,7 +993,7 @@ TEST(Dump, BigDump) {
->eip);
// Check the modules.
- MinidumpModuleList *md_module_list = minidump.GetModuleList();
+ MinidumpModuleList* md_module_list = minidump.GetModuleList();
ASSERT_TRUE(md_module_list != NULL);
ASSERT_EQ(3U, md_module_list->module_count());
EXPECT_EQ(0xeb77da57b5d4cbdaULL,
@@ -968,7 +1004,7 @@ TEST(Dump, BigDump) {
md_module_list->GetModuleAtIndex(2)->base_address());
// Check unloaded modules
- MinidumpUnloadedModuleList *md_unloaded_module_list =
+ MinidumpUnloadedModuleList* md_unloaded_module_list =
minidump.GetUnloadedModuleList();
ASSERT_TRUE(md_unloaded_module_list != NULL);
ASSERT_EQ(3U, md_unloaded_module_list->module_count());
@@ -979,7 +1015,7 @@ TEST(Dump, BigDump) {
EXPECT_EQ(umodule3_base,
md_unloaded_module_list->GetModuleAtIndex(2)->base_address());
- const MinidumpUnloadedModule *umodule =
+ const MinidumpUnloadedModule* umodule =
md_unloaded_module_list->GetModuleForAddress(
umodule1_base + umodule1_size / 2);
EXPECT_EQ(umodule1_base, umodule->base_address());
@@ -1025,22 +1061,22 @@ TEST(Dump, OneMemoryInfo) {
ASSERT_TRUE(minidump.Read());
ASSERT_EQ(1U, minidump.GetDirectoryEntryCount());
- const MDRawDirectory *dir = minidump.GetDirectoryEntryAtIndex(0);
+ const MDRawDirectory* dir = minidump.GetDirectoryEntryAtIndex(0);
ASSERT_TRUE(dir != NULL);
EXPECT_EQ((uint32_t) MD_MEMORY_INFO_LIST_STREAM, dir->stream_type);
- MinidumpMemoryInfoList *info_list = minidump.GetMemoryInfoList();
+ MinidumpMemoryInfoList* info_list = minidump.GetMemoryInfoList();
ASSERT_TRUE(info_list != NULL);
ASSERT_EQ(1U, info_list->info_count());
- const MinidumpMemoryInfo *info1 = info_list->GetMemoryInfoAtIndex(0);
+ const MinidumpMemoryInfo* info1 = info_list->GetMemoryInfoAtIndex(0);
ASSERT_EQ(kBaseAddress, info1->GetBase());
ASSERT_EQ(kRegionSize, info1->GetSize());
ASSERT_TRUE(info1->IsExecutable());
ASSERT_TRUE(info1->IsWritable());
// Should get back the same memory region here.
- const MinidumpMemoryInfo *info2 =
+ const MinidumpMemoryInfo* info2 =
info_list->GetMemoryInfoForAddress(kBaseAddress + kRegionSize / 2);
ASSERT_EQ(kBaseAddress, info2->GetBase());
ASSERT_EQ(kRegionSize, info2->GetSize());
@@ -1083,7 +1119,7 @@ TEST(Dump, OneExceptionX86) {
ASSERT_TRUE(minidump.Read());
ASSERT_EQ(1U, minidump.GetDirectoryEntryCount());
- MinidumpException *md_exception = minidump.GetException();
+ MinidumpException* md_exception = minidump.GetException();
ASSERT_TRUE(md_exception != NULL);
uint32_t thread_id;
@@ -1097,10 +1133,10 @@ TEST(Dump, OneExceptionX86) {
EXPECT_EQ(0x0919a9b9c9d9e9f9ULL,
raw_exception->exception_record.exception_address);
- MinidumpContext *md_context = md_exception->GetContext();
+ MinidumpContext* md_context = md_exception->GetContext();
ASSERT_TRUE(md_context != NULL);
ASSERT_EQ((uint32_t) MD_CONTEXT_X86, md_context->GetContextCPU());
- const MDRawContextX86 *md_raw_context = md_context->GetContextX86();
+ const MDRawContextX86* md_raw_context = md_context->GetContextX86();
ASSERT_TRUE(md_raw_context != NULL);
ASSERT_EQ((uint32_t) (MD_CONTEXT_X86_INTEGER | MD_CONTEXT_X86_CONTROL),
(md_raw_context->context_flags
@@ -1157,7 +1193,7 @@ TEST(Dump, OneExceptionX86XState) {
ASSERT_TRUE(minidump.Read());
ASSERT_EQ(1U, minidump.GetDirectoryEntryCount());
- MinidumpException *md_exception = minidump.GetException();
+ MinidumpException* md_exception = minidump.GetException();
ASSERT_TRUE(md_exception != NULL);
uint32_t thread_id;
@@ -1171,10 +1207,10 @@ TEST(Dump, OneExceptionX86XState) {
EXPECT_EQ(0x0919a9b9c9d9e9f9ULL,
raw_exception->exception_record.exception_address);
- MinidumpContext *md_context = md_exception->GetContext();
+ MinidumpContext* md_context = md_exception->GetContext();
ASSERT_TRUE(md_context != NULL);
ASSERT_EQ((uint32_t) MD_CONTEXT_X86, md_context->GetContextCPU());
- const MDRawContextX86 *md_raw_context = md_context->GetContextX86();
+ const MDRawContextX86* md_raw_context = md_context->GetContextX86();
ASSERT_TRUE(md_raw_context != NULL);
ASSERT_EQ((uint32_t) (MD_CONTEXT_X86_INTEGER | MD_CONTEXT_X86_CONTROL),
(md_raw_context->context_flags
@@ -1242,7 +1278,7 @@ TEST(Dump, OneExceptionX86NoCPUFlags) {
ASSERT_TRUE(minidump.Read());
ASSERT_EQ(2U, minidump.GetDirectoryEntryCount());
- MinidumpException *md_exception = minidump.GetException();
+ MinidumpException* md_exception = minidump.GetException();
ASSERT_TRUE(md_exception != NULL);
uint32_t thread_id;
@@ -1256,11 +1292,11 @@ TEST(Dump, OneExceptionX86NoCPUFlags) {
EXPECT_EQ(0x0919a9b9c9d9e9f9ULL,
raw_exception->exception_record.exception_address);
- MinidumpContext *md_context = md_exception->GetContext();
+ MinidumpContext* md_context = md_exception->GetContext();
ASSERT_TRUE(md_context != NULL);
ASSERT_EQ((uint32_t) MD_CONTEXT_X86, md_context->GetContextCPU());
- const MDRawContextX86 *md_raw_context = md_context->GetContextX86();
+ const MDRawContextX86* md_raw_context = md_context->GetContextX86();
ASSERT_TRUE(md_raw_context != NULL);
// Even though the CPU flags were missing from the context_flags, the
@@ -1324,7 +1360,7 @@ TEST(Dump, OneExceptionX86NoCPUFlagsNoSystemInfo) {
ASSERT_TRUE(minidump.Read());
ASSERT_EQ(1U, minidump.GetDirectoryEntryCount());
- MinidumpException *md_exception = minidump.GetException();
+ MinidumpException* md_exception = minidump.GetException();
ASSERT_TRUE(md_exception != NULL);
uint32_t thread_id;
@@ -1341,7 +1377,7 @@ TEST(Dump, OneExceptionX86NoCPUFlagsNoSystemInfo) {
// The context record of the exception is unusable because the context_flags
// don't have CPU type information and at the same time the minidump lacks
// system info stream so it is impossible to deduce the CPU type.
- MinidumpContext *md_context = md_exception->GetContext();
+ MinidumpContext* md_context = md_exception->GetContext();
ASSERT_EQ(NULL, md_context);
}
@@ -1387,7 +1423,7 @@ TEST(Dump, OneExceptionARM) {
ASSERT_TRUE(minidump.Read());
ASSERT_EQ(1U, minidump.GetDirectoryEntryCount());
- MinidumpException *md_exception = minidump.GetException();
+ MinidumpException* md_exception = minidump.GetException();
ASSERT_TRUE(md_exception != NULL);
uint32_t thread_id;
@@ -1401,10 +1437,10 @@ TEST(Dump, OneExceptionARM) {
EXPECT_EQ(0x0919a9b9c9d9e9f9ULL,
raw_exception->exception_record.exception_address);
- MinidumpContext *md_context = md_exception->GetContext();
+ MinidumpContext* md_context = md_exception->GetContext();
ASSERT_TRUE(md_context != NULL);
ASSERT_EQ((uint32_t) MD_CONTEXT_ARM, md_context->GetContextCPU());
- const MDRawContextARM *md_raw_context = md_context->GetContextARM();
+ const MDRawContextARM* md_raw_context = md_context->GetContextARM();
ASSERT_TRUE(md_raw_context != NULL);
ASSERT_EQ((uint32_t) MD_CONTEXT_ARM_INTEGER,
(md_raw_context->context_flags
@@ -1471,7 +1507,7 @@ TEST(Dump, OneExceptionARMOldFlags) {
ASSERT_TRUE(minidump.Read());
ASSERT_EQ(1U, minidump.GetDirectoryEntryCount());
- MinidumpException *md_exception = minidump.GetException();
+ MinidumpException* md_exception = minidump.GetException();
ASSERT_TRUE(md_exception != NULL);
uint32_t thread_id;
@@ -1485,10 +1521,10 @@ TEST(Dump, OneExceptionARMOldFlags) {
EXPECT_EQ(0x0919a9b9c9d9e9f9ULL,
raw_exception->exception_record.exception_address);
- MinidumpContext *md_context = md_exception->GetContext();
+ MinidumpContext* md_context = md_exception->GetContext();
ASSERT_TRUE(md_context != NULL);
ASSERT_EQ((uint32_t) MD_CONTEXT_ARM, md_context->GetContextCPU());
- const MDRawContextARM *md_raw_context = md_context->GetContextARM();
+ const MDRawContextARM* md_raw_context = md_context->GetContextARM();
ASSERT_TRUE(md_raw_context != NULL);
ASSERT_EQ((uint32_t) MD_CONTEXT_ARM_INTEGER,
(md_raw_context->context_flags
@@ -1570,7 +1606,7 @@ TEST(Dump, OneExceptionMIPS) {
ASSERT_TRUE(minidump.Read());
ASSERT_EQ(1U, minidump.GetDirectoryEntryCount());
- MinidumpException *md_exception = minidump.GetException();
+ MinidumpException* md_exception = minidump.GetException();
ASSERT_TRUE(md_exception != NULL);
uint32_t thread_id;
diff --git a/src/processor/module_comparer.cc b/src/processor/module_comparer.cc
index 025ab883..389712c5 100644
--- a/src/processor/module_comparer.cc
+++ b/src/processor/module_comparer.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2010, Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -52,7 +51,7 @@
namespace google_breakpad {
-bool ModuleComparer::Compare(const string &symbol_data) {
+bool ModuleComparer::Compare(const string& symbol_data) {
scoped_ptr<BasicModule> basic_module(new BasicModule("test_module"));
scoped_ptr<FastModule> fast_module(new FastModule("test_module"));
@@ -284,7 +283,7 @@ bool ModuleComparer::CompareCRM(
while (iter1 != basic_crm->map_->end()
&& iter2 != fast_crm->map_.end()) {
ASSERT_TRUE(iter1->first == iter2.GetKey());
- StaticContainedRangeMap<MemAddr, char> *child =
+ StaticContainedRangeMap<MemAddr, char>* child =
new StaticContainedRangeMap<MemAddr, char>(
reinterpret_cast<const char*>(iter2.GetValuePtr()));
ASSERT_TRUE(CompareCRM(iter1->second, child));
diff --git a/src/processor/module_comparer.h b/src/processor/module_comparer.h
index fcbd5177..6bd3e7b8 100644
--- a/src/processor/module_comparer.h
+++ b/src/processor/module_comparer.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2010, Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -64,7 +63,7 @@ class ModuleComparer {
// FastSourceLineResolver loads its module using the serialized memory chunk,
// Then, traverse both modules together and compare underlying data
// return true if both modules contain exactly same data.
- bool Compare(const string &symbol_data);
+ bool Compare(const string& symbol_data);
private:
typedef BasicSourceLineResolver::Module BasicModule;
diff --git a/src/processor/module_factory.h b/src/processor/module_factory.h
index 7aa7caa5..3df85a60 100644
--- a/src/processor/module_factory.h
+++ b/src/processor/module_factory.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2010 Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -46,14 +45,14 @@ class ModuleFactory {
public:
virtual ~ModuleFactory() { };
virtual SourceLineResolverBase::Module* CreateModule(
- const string &name) const = 0;
+ const string& name) const = 0;
};
class BasicModuleFactory : public ModuleFactory {
public:
virtual ~BasicModuleFactory() { }
virtual BasicSourceLineResolver::Module* CreateModule(
- const string &name) const {
+ const string& name) const {
return new BasicSourceLineResolver::Module(name);
}
};
@@ -62,7 +61,7 @@ class FastModuleFactory : public ModuleFactory {
public:
virtual ~FastModuleFactory() { }
virtual FastSourceLineResolver::Module* CreateModule(
- const string &name) const {
+ const string& name) const {
return new FastSourceLineResolver::Module(name);
}
};
diff --git a/src/processor/module_serializer.cc b/src/processor/module_serializer.cc
index 6ac60c1f..d0445094 100644
--- a/src/processor/module_serializer.cc
+++ b/src/processor/module_serializer.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2010, Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -43,12 +42,17 @@
namespace google_breakpad {
-// Definition of static member variable in SimplerSerializer<Funcion>, which
-// is declared in file "simple_serializer-inl.h"
-RangeMapSerializer< MemAddr, linked_ptr<BasicSourceLineResolver::Line> >
-SimpleSerializer<BasicSourceLineResolver::Function>::range_map_serializer_;
-
-size_t ModuleSerializer::SizeOf(const BasicSourceLineResolver::Module &module) {
+// Definition of static member variables in SimplerSerializer<Funcion> and
+// SimplerSerializer<Inline>, which are declared in file
+// "simple_serializer-inl.h"
+RangeMapSerializer<MemAddr, linked_ptr<BasicSourceLineResolver::Line>>
+ SimpleSerializer<BasicSourceLineResolver::Function>::range_map_serializer_;
+ContainedRangeMapSerializer<MemAddr,
+ linked_ptr<BasicSourceLineResolver::Inline>>
+ SimpleSerializer<
+ BasicSourceLineResolver::Function>::inline_range_map_serializer_;
+
+size_t ModuleSerializer::SizeOf(const BasicSourceLineResolver::Module& module) {
size_t total_size_alloc_ = 0;
// Size of the "is_corrupt" flag.
@@ -66,6 +70,8 @@ size_t ModuleSerializer::SizeOf(const BasicSourceLineResolver::Module &module) {
module.cfi_initial_rules_);
map_sizes_[map_index++] = cfi_delta_rules_serializer_.SizeOf(
module.cfi_delta_rules_);
+ map_sizes_[map_index++] =
+ inline_origin_serializer_.SizeOf(module.inline_origins_);
// Header size.
total_size_alloc_ += kNumberMaps_ * sizeof(uint32_t);
@@ -80,8 +86,8 @@ size_t ModuleSerializer::SizeOf(const BasicSourceLineResolver::Module &module) {
return total_size_alloc_;
}
-char *ModuleSerializer::Write(const BasicSourceLineResolver::Module &module,
- char *dest) {
+char* ModuleSerializer::Write(const BasicSourceLineResolver::Module& module,
+ char* dest) {
// Write the is_corrupt flag.
dest = SimpleSerializer<bool>::Write(module.is_corrupt_, dest);
// Write header.
@@ -95,18 +101,19 @@ char *ModuleSerializer::Write(const BasicSourceLineResolver::Module &module,
dest = wfi_serializer_.Write(&(module.windows_frame_info_[i]), dest);
dest = cfi_init_rules_serializer_.Write(module.cfi_initial_rules_, dest);
dest = cfi_delta_rules_serializer_.Write(module.cfi_delta_rules_, dest);
+ dest = inline_origin_serializer_.Write(module.inline_origins_, dest);
// Write a null terminator.
dest = SimpleSerializer<char>::Write(0, dest);
return dest;
}
char* ModuleSerializer::Serialize(
- const BasicSourceLineResolver::Module &module, unsigned int *size) {
+ const BasicSourceLineResolver::Module& module, unsigned int* size) {
// Compute size of memory to allocate.
unsigned int size_to_alloc = SizeOf(module);
// Allocate memory for serialized data.
- char *serialized_data = new char[size_to_alloc];
+ char* serialized_data = new char[size_to_alloc];
if (!serialized_data) {
BPLOG(ERROR) << "ModuleSerializer: memory allocation failed, "
<< "size to alloc: " << size_to_alloc;
@@ -115,7 +122,7 @@ char* ModuleSerializer::Serialize(
}
// Write serialized data to allocated memory chunk.
- char *end_address = Write(module, serialized_data);
+ char* end_address = Write(module, serialized_data);
// Verify the allocated memory size is equal to the size of data been written.
unsigned int size_written =
static_cast<unsigned int>(end_address - serialized_data);
@@ -131,8 +138,8 @@ char* ModuleSerializer::Serialize(
}
bool ModuleSerializer::SerializeModuleAndLoadIntoFastResolver(
- const BasicSourceLineResolver::ModuleMap::const_iterator &iter,
- FastSourceLineResolver *fast_resolver) {
+ const BasicSourceLineResolver::ModuleMap::const_iterator& iter,
+ FastSourceLineResolver* fast_resolver) {
BPLOG(INFO) << "Converting symbol " << iter->first.c_str();
// Cast SourceLineResolverBase::Module* to BasicSourceLineResolver::Module*.
@@ -161,8 +168,8 @@ bool ModuleSerializer::SerializeModuleAndLoadIntoFastResolver(
}
void ModuleSerializer::ConvertAllModules(
- const BasicSourceLineResolver *basic_resolver,
- FastSourceLineResolver *fast_resolver) {
+ const BasicSourceLineResolver* basic_resolver,
+ FastSourceLineResolver* fast_resolver) {
// Check for NULL pointer.
if (!basic_resolver || !fast_resolver)
return;
@@ -175,9 +182,9 @@ void ModuleSerializer::ConvertAllModules(
}
bool ModuleSerializer::ConvertOneModule(
- const string &moduleid,
- const BasicSourceLineResolver *basic_resolver,
- FastSourceLineResolver *fast_resolver) {
+ const string& moduleid,
+ const BasicSourceLineResolver* basic_resolver,
+ FastSourceLineResolver* fast_resolver) {
// Check for NULL pointer.
if (!basic_resolver || !fast_resolver)
return false;
@@ -191,7 +198,7 @@ bool ModuleSerializer::ConvertOneModule(
}
char* ModuleSerializer::SerializeSymbolFileData(
- const string &symbol_data, unsigned int *size) {
+ const string& symbol_data, unsigned int* size) {
scoped_ptr<BasicSourceLineResolver::Module> module(
new BasicSourceLineResolver::Module("no name"));
scoped_array<char> buffer(new char[symbol_data.size() + 1]);
diff --git a/src/processor/module_serializer.h b/src/processor/module_serializer.h
index effb0091..4e365a41 100644
--- a/src/processor/module_serializer.h
+++ b/src/processor/module_serializer.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2010, Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -61,49 +60,50 @@ class ModuleSerializer {
public:
// Compute the size of memory required to serialize a module. Return the
// total size needed for serialization.
- size_t SizeOf(const BasicSourceLineResolver::Module &module);
+ size_t SizeOf(const BasicSourceLineResolver::Module& module);
// Write a module into an allocated memory chunk with required size.
// Return the "end" of data, i.e., the address after the final byte of data.
- char* Write(const BasicSourceLineResolver::Module &module, char *dest);
+ char* Write(const BasicSourceLineResolver::Module& module, char* dest);
// Serializes a loaded Module object into a chunk of memory data and returns
// the address of memory chunk. If size != NULL, *size is set to the memory
// size allocated for the serialized data.
// Caller takes the ownership of the memory chunk (allocated on heap), and
// owner should call delete [] to free the memory after use.
- char* Serialize(const BasicSourceLineResolver::Module &module,
- unsigned int *size = NULL);
+ char* Serialize(const BasicSourceLineResolver::Module& module,
+ unsigned int* size = NULL);
// Given the string format symbol_data, produces a chunk of serialized data.
// Caller takes ownership of the serialized data (on heap), and owner should
// call delete [] to free the memory after use.
- char* SerializeSymbolFileData(const string &symbol_data,
- unsigned int *size = NULL);
+ char* SerializeSymbolFileData(const string& symbol_data,
+ unsigned int* size = NULL);
// Serializes one loaded module with given moduleid in the basic source line
// resolver, and loads the serialized data into the fast source line resolver.
// Return false if the basic source line doesn't have a module with the given
// moduleid.
- bool ConvertOneModule(const string &moduleid,
- const BasicSourceLineResolver *basic_resolver,
- FastSourceLineResolver *fast_resolver);
+ bool ConvertOneModule(const string& moduleid,
+ const BasicSourceLineResolver* basic_resolver,
+ FastSourceLineResolver* fast_resolver);
// Serializes all the loaded modules in a basic source line resolver, and
// loads the serialized data into a fast source line resolver.
- void ConvertAllModules(const BasicSourceLineResolver *basic_resolver,
- FastSourceLineResolver *fast_resolver);
+ void ConvertAllModules(const BasicSourceLineResolver* basic_resolver,
+ FastSourceLineResolver* fast_resolver);
private:
// Convenient type names.
typedef BasicSourceLineResolver::Line Line;
typedef BasicSourceLineResolver::Function Function;
typedef BasicSourceLineResolver::PublicSymbol PublicSymbol;
+ typedef BasicSourceLineResolver::InlineOrigin InlineOrigin;
// Internal implementation for ConvertOneModule and ConvertAllModules methods.
bool SerializeModuleAndLoadIntoFastResolver(
- const BasicSourceLineResolver::ModuleMap::const_iterator &iter,
- FastSourceLineResolver *fast_resolver);
+ const BasicSourceLineResolver::ModuleMap::const_iterator& iter,
+ FastSourceLineResolver* fast_resolver);
// Number of Maps that Module class contains.
static const int32_t kNumberMaps_ =
@@ -120,6 +120,7 @@ class ModuleSerializer {
linked_ptr<WindowsFrameInfo> > wfi_serializer_;
RangeMapSerializer<MemAddr, string> cfi_init_rules_serializer_;
StdMapSerializer<MemAddr, string> cfi_delta_rules_serializer_;
+ StdMapSerializer<int, linked_ptr<InlineOrigin>> inline_origin_serializer_;
};
} // namespace google_breakpad
diff --git a/src/processor/pathname_stripper.cc b/src/processor/pathname_stripper.cc
index 839287bd..f34b53f7 100644
--- a/src/processor/pathname_stripper.cc
+++ b/src/processor/pathname_stripper.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2006, Google Inc.
-// All rights reserved.
+// Copyright 2006 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -38,7 +37,7 @@
namespace google_breakpad {
// static
-string PathnameStripper::File(const string &path) {
+string PathnameStripper::File(const string& path) {
string::size_type slash = path.rfind('/');
string::size_type backslash = path.rfind('\\');
diff --git a/src/processor/pathname_stripper.h b/src/processor/pathname_stripper.h
index 423ca0d0..62c9bddd 100644
--- a/src/processor/pathname_stripper.h
+++ b/src/processor/pathname_stripper.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2006, Google Inc.
-// All rights reserved.
+// Copyright 2006 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -45,7 +44,7 @@ class PathnameStripper {
// Given path, a pathname with components separated by slashes (/) or
// backslashes (\), returns the trailing component, without any separator.
// If path ends in a separator character, returns an empty string.
- static string File(const string &path);
+ static string File(const string& path);
};
} // namespace google_breakpad
diff --git a/src/processor/pathname_stripper_unittest.cc b/src/processor/pathname_stripper_unittest.cc
index 1bff4cb0..ff474a7b 100644
--- a/src/processor/pathname_stripper_unittest.cc
+++ b/src/processor/pathname_stripper_unittest.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2006, Google Inc.
-// All rights reserved.
+// Copyright 2006 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -80,7 +79,7 @@ static bool RunTests() {
} // namespace
-int main(int argc, char **argv) {
+int main(int argc, char** argv) {
BPLOG_INIT(&argc, &argv);
return RunTests() ? 0 : 1;
diff --git a/src/processor/postfix_evaluator-inl.h b/src/processor/postfix_evaluator-inl.h
index d7dbeac2..abdf259e 100644
--- a/src/processor/postfix_evaluator-inl.h
+++ b/src/processor/postfix_evaluator-inl.h
@@ -1,7 +1,6 @@
// -*- mode: c++ -*-
-// Copyright (c) 2010 Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -13,7 +12,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -58,19 +57,19 @@ using std::ostringstream;
// before returning failure.
class AutoStackClearer {
public:
- explicit AutoStackClearer(vector<string> *stack) : stack_(stack) {}
+ explicit AutoStackClearer(vector<string>* stack) : stack_(stack) {}
~AutoStackClearer() { stack_->clear(); }
private:
- vector<string> *stack_;
+ vector<string>* stack_;
};
template<typename ValueType>
bool PostfixEvaluator<ValueType>::EvaluateToken(
- const string &token,
- const string &expression,
- DictionaryValidityType *assigned) {
+ const string& token,
+ const string& expression,
+ DictionaryValidityType* assigned) {
// There are enough binary operations that do exactly the same thing
// (other than the specific operation, of course) that it makes sense
// to share as much code as possible.
@@ -203,8 +202,8 @@ bool PostfixEvaluator<ValueType>::EvaluateToken(
template<typename ValueType>
bool PostfixEvaluator<ValueType>::EvaluateInternal(
- const string &expression,
- DictionaryValidityType *assigned) {
+ const string& expression,
+ DictionaryValidityType* assigned) {
// Tokenize, splitting on whitespace.
istringstream stream(expression);
string token;
@@ -231,8 +230,8 @@ bool PostfixEvaluator<ValueType>::EvaluateInternal(
}
template<typename ValueType>
-bool PostfixEvaluator<ValueType>::Evaluate(const string &expression,
- DictionaryValidityType *assigned) {
+bool PostfixEvaluator<ValueType>::Evaluate(const string& expression,
+ DictionaryValidityType* assigned) {
// Ensure that the stack is cleared before returning.
AutoStackClearer clearer(&stack_);
@@ -250,8 +249,8 @@ bool PostfixEvaluator<ValueType>::Evaluate(const string &expression,
}
template<typename ValueType>
-bool PostfixEvaluator<ValueType>::EvaluateForValue(const string &expression,
- ValueType *result) {
+bool PostfixEvaluator<ValueType>::EvaluateForValue(const string& expression,
+ ValueType* result) {
// Ensure that the stack is cleared before returning.
AutoStackClearer clearer(&stack_);
@@ -271,7 +270,7 @@ bool PostfixEvaluator<ValueType>::EvaluateForValue(const string &expression,
template<typename ValueType>
typename PostfixEvaluator<ValueType>::PopResult
PostfixEvaluator<ValueType>::PopValueOrIdentifier(
- ValueType *value, string *identifier) {
+ ValueType* value, string* identifier) {
// There needs to be at least one element on the stack to pop.
if (!stack_.size())
return POP_RESULT_FAIL;
@@ -314,7 +313,7 @@ PostfixEvaluator<ValueType>::PopValueOrIdentifier(
template<typename ValueType>
-bool PostfixEvaluator<ValueType>::PopValue(ValueType *value) {
+bool PostfixEvaluator<ValueType>::PopValue(ValueType* value) {
ValueType literal = ValueType();
string token;
PopResult result;
@@ -343,14 +342,14 @@ bool PostfixEvaluator<ValueType>::PopValue(ValueType *value) {
template<typename ValueType>
-bool PostfixEvaluator<ValueType>::PopValues(ValueType *value1,
- ValueType *value2) {
+bool PostfixEvaluator<ValueType>::PopValues(ValueType* value1,
+ ValueType* value2) {
return PopValue(value2) && PopValue(value1);
}
template<typename ValueType>
-void PostfixEvaluator<ValueType>::PushValue(const ValueType &value) {
+void PostfixEvaluator<ValueType>::PushValue(const ValueType& value) {
ostringstream token_stream;
token_stream << value;
stack_.push_back(token_stream.str());
diff --git a/src/processor/postfix_evaluator.h b/src/processor/postfix_evaluator.h
index 94b66190..b6f718ab 100644
--- a/src/processor/postfix_evaluator.h
+++ b/src/processor/postfix_evaluator.h
@@ -1,7 +1,6 @@
// -*- mode: C++ -*-
-// Copyright (c) 2010 Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -13,7 +12,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -95,7 +94,7 @@ class PostfixEvaluator {
// (^) will not be supported. |dictionary| may be NULL, but evaluation
// will fail in that case unless set_dictionary is used before calling
// Evaluate.
- PostfixEvaluator(DictionaryType *dictionary, const MemoryRegion *memory)
+ PostfixEvaluator(DictionaryType* dictionary, const MemoryRegion* memory)
: dictionary_(dictionary), memory_(memory), stack_() {}
// Evaluate the expression, starting with an empty stack. The results of
@@ -105,18 +104,18 @@ class PostfixEvaluator {
// non-NULL, any keys set in the dictionary as a result of evaluation
// will also be set to true in assigned, providing a way to determine if
// an expression modifies any of its input variables.
- bool Evaluate(const string &expression, DictionaryValidityType *assigned);
+ bool Evaluate(const string& expression, DictionaryValidityType* assigned);
// Like Evaluate, but provides the value left on the stack to the
// caller. If evaluation succeeds and leaves exactly one value on
// the stack, pop that value, store it in *result, and return true.
// Otherwise, return false.
- bool EvaluateForValue(const string &expression, ValueType *result);
+ bool EvaluateForValue(const string& expression, ValueType* result);
DictionaryType* dictionary() const { return dictionary_; }
// Reset the dictionary. PostfixEvaluator does not take ownership.
- void set_dictionary(DictionaryType *dictionary) {dictionary_ = dictionary; }
+ void set_dictionary(DictionaryType* dictionary) {dictionary_ = dictionary; }
private:
// Return values for PopValueOrIdentifier
@@ -132,40 +131,40 @@ class PostfixEvaluator {
// if the topmost entry is a constant or variable identifier, and sets
// |identifier| accordingly. Returns POP_RESULT_FAIL on failure, such
// as when the stack is empty.
- PopResult PopValueOrIdentifier(ValueType *value, string *identifier);
+ PopResult PopValueOrIdentifier(ValueType* value, string* identifier);
// Retrieves the topmost value on the stack. If the topmost entry is
// an identifier, the dictionary is queried for the identifier's value.
// Returns false on failure, such as when the stack is empty or when
// a nonexistent identifier is named.
- bool PopValue(ValueType *value);
+ bool PopValue(ValueType* value);
// Retrieves the top two values on the stack, in the style of PopValue.
// value2 is popped before value1, so that value1 corresponds to the
// entry that was pushed prior to value2. Returns false on failure.
- bool PopValues(ValueType *value1, ValueType *value2);
+ bool PopValues(ValueType* value1, ValueType* value2);
// Pushes a new value onto the stack.
- void PushValue(const ValueType &value);
+ void PushValue(const ValueType& value);
// Evaluate expression, updating *assigned if it is non-zero. Return
// true if evaluation completes successfully. Do not clear the stack
// upon successful evaluation.
- bool EvaluateInternal(const string &expression,
- DictionaryValidityType *assigned);
+ bool EvaluateInternal(const string& expression,
+ DictionaryValidityType* assigned);
- bool EvaluateToken(const string &token,
- const string &expression,
- DictionaryValidityType *assigned);
+ bool EvaluateToken(const string& token,
+ const string& expression,
+ DictionaryValidityType* assigned);
// The dictionary mapping constant and variable identifiers (strings) to
// values. Keys beginning with '$' are treated as variable names, and
// PostfixEvaluator is free to create and modify these keys. Weak pointer.
- DictionaryType *dictionary_;
+ DictionaryType* dictionary_;
// If non-NULL, the MemoryRegion used for dereference (^) operations.
// If NULL, dereferencing is unsupported and will fail. Weak pointer.
- const MemoryRegion *memory_;
+ const MemoryRegion* memory_;
// The stack contains state information as execution progresses. Values
// are pushed on to it as the expression string is read and as operations
diff --git a/src/processor/postfix_evaluator_unittest.cc b/src/processor/postfix_evaluator_unittest.cc
index f1189828..76d85751 100644
--- a/src/processor/postfix_evaluator_unittest.cc
+++ b/src/processor/postfix_evaluator_unittest.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2010 Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -60,19 +59,19 @@ class FakeMemoryRegion : public MemoryRegion {
public:
virtual uint64_t GetBase() const { return 0; }
virtual uint32_t GetSize() const { return 0; }
- virtual bool GetMemoryAtAddress(uint64_t address, uint8_t *value) const {
+ virtual bool GetMemoryAtAddress(uint64_t address, uint8_t* value) const {
*value = address + 1;
return true;
}
- virtual bool GetMemoryAtAddress(uint64_t address, uint16_t *value) const {
+ virtual bool GetMemoryAtAddress(uint64_t address, uint16_t* value) const {
*value = address + 1;
return true;
}
- virtual bool GetMemoryAtAddress(uint64_t address, uint32_t *value) const {
+ virtual bool GetMemoryAtAddress(uint64_t address, uint32_t* value) const {
*value = address + 1;
return true;
}
- virtual bool GetMemoryAtAddress(uint64_t address, uint64_t *value) const {
+ virtual bool GetMemoryAtAddress(uint64_t address, uint64_t* value) const {
*value = address + 1;
return true;
}
@@ -94,17 +93,17 @@ struct EvaluateTest {
struct EvaluateTestSet {
// The dictionary used for all tests in the set.
- PostfixEvaluator<unsigned int>::DictionaryType *dictionary;
+ PostfixEvaluator<unsigned int>::DictionaryType* dictionary;
// The list of tests.
- const EvaluateTest *evaluate_tests;
+ const EvaluateTest* evaluate_tests;
// The number of tests.
unsigned int evaluate_test_count;
// Identifiers and their expected values upon completion of the Evaluate
// tests in the set.
- map<string, unsigned int> *validate_data;
+ map<string, unsigned int>* validate_data;
};
@@ -227,9 +226,9 @@ static bool RunTests() {
for (unsigned int evaluate_test_set_index = 0;
evaluate_test_set_index < evaluate_test_set_count;
++evaluate_test_set_index) {
- EvaluateTestSet *evaluate_test_set =
+ EvaluateTestSet* evaluate_test_set =
&evaluate_test_sets[evaluate_test_set_index];
- const EvaluateTest *evaluate_tests = evaluate_test_set->evaluate_tests;
+ const EvaluateTest* evaluate_tests = evaluate_test_set->evaluate_tests;
unsigned int evaluate_test_count = evaluate_test_set->evaluate_test_count;
// The same dictionary will be used for each test in the set. Earlier
@@ -242,7 +241,7 @@ static bool RunTests() {
for (unsigned int evaluate_test_index = 0;
evaluate_test_index < evaluate_test_count;
++evaluate_test_index) {
- const EvaluateTest *evaluate_test = &evaluate_tests[evaluate_test_index];
+ const EvaluateTest* evaluate_test = &evaluate_tests[evaluate_test_index];
// Do the test.
bool result = postfix_evaluator.Evaluate(evaluate_test->expression,
@@ -344,7 +343,7 @@ static bool RunTests() {
postfix_evaluator.set_dictionary(&dictionary_2);
for (int i = 0; i < evaluate_for_value_tests_2_size; i++) {
- const EvaluateForValueTest *test = &evaluate_for_value_tests_2[i];
+ const EvaluateForValueTest* test = &evaluate_for_value_tests_2[i];
unsigned int result;
if (postfix_evaluator.EvaluateForValue(test->expression, &result)
!= test->evaluable) {
@@ -396,7 +395,7 @@ static bool RunTests() {
} // namespace
-int main(int argc, char **argv) {
+int main(int argc, char** argv) {
BPLOG_INIT(&argc, &argv);
return RunTests() ? 0 : 1;
diff --git a/src/processor/proc_maps_linux.cc b/src/processor/proc_maps_linux.cc
index 3c0dea25..05c1145a 100644
--- a/src/processor/proc_maps_linux.cc
+++ b/src/processor/proc_maps_linux.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Copyright 2013 Google LLC
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/src/processor/proc_maps_linux_unittest.cc b/src/processor/proc_maps_linux_unittest.cc
index 466f2345..dc51babb 100644
--- a/src/processor/proc_maps_linux_unittest.cc
+++ b/src/processor/proc_maps_linux_unittest.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Copyright 2013 Google LLC
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/src/processor/process_state.cc b/src/processor/process_state.cc
index 43c4a4b8..95bbd48d 100644
--- a/src/processor/process_state.cc
+++ b/src/processor/process_state.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2006, Google Inc.
-// All rights reserved.
+// Copyright 2006 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -51,13 +50,14 @@ void ProcessState::Clear() {
crash_address_ = 0;
assertion_.clear();
requesting_thread_ = -1;
- for (vector<CallStack *>::const_iterator iterator = threads_.begin();
+ for (vector<CallStack*>::const_iterator iterator = threads_.begin();
iterator != threads_.end();
++iterator) {
delete *iterator;
}
threads_.clear();
system_info_.Clear();
+ thread_names_.clear();
// modules_without_symbols_ and modules_with_corrupt_symbols_ DO NOT own
// the underlying CodeModule pointers. Just clear the vectors.
modules_without_symbols_.clear();
diff --git a/src/processor/processor.gyp b/src/processor/processor.gyp
deleted file mode 100644
index 93896c0e..00000000
--- a/src/processor/processor.gyp
+++ /dev/null
@@ -1,187 +0,0 @@
-# Copyright 2014 Google Inc. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-# * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-# * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-{
- 'includes': [
- '../build/common.gypi',
- 'processor_tools.gypi',
- ],
- 'targets': [
- {
- 'target_name': 'processor',
- 'type': 'static_library',
- 'sources': [
- 'address_map-inl.h',
- 'address_map.h',
- 'basic_code_module.h',
- 'basic_code_modules.cc',
- 'basic_code_modules.h',
- 'basic_source_line_resolver.cc',
- 'basic_source_line_resolver_types.h',
- 'call_stack.cc',
- 'cfi_frame_info-inl.h',
- 'cfi_frame_info.cc',
- 'cfi_frame_info.h',
- 'contained_range_map-inl.h',
- 'contained_range_map.h',
- 'convert_old_arm64_context.cc',
- 'convert_old_arm64_context.h',
- 'disassembler_x86.cc',
- 'disassembler_x86.h',
- 'dump_context.cc',
- 'dump_object.cc',
- 'exploitability.cc',
- 'exploitability_linux.cc',
- 'exploitability_linux.h',
- 'exploitability_win.cc',
- 'exploitability_win.h',
- 'fast_source_line_resolver.cc',
- 'fast_source_line_resolver_types.h',
- 'linked_ptr.h',
- 'logging.cc',
- 'logging.h',
- 'map_serializers-inl.h',
- 'map_serializers.h',
- 'microdump_processor.cc',
- 'minidump.cc',
- 'minidump_processor.cc',
- 'module_comparer.cc',
- 'module_comparer.h',
- 'module_factory.h',
- 'module_serializer.cc',
- 'module_serializer.h',
- 'pathname_stripper.cc',
- 'pathname_stripper.h',
- 'postfix_evaluator-inl.h',
- 'postfix_evaluator.h',
- 'proc_maps_linux.cc',
- 'process_state.cc',
- 'range_map-inl.h',
- 'range_map.h',
- 'simple_serializer-inl.h',
- 'simple_serializer.h',
- 'simple_symbol_supplier.cc',
- 'simple_symbol_supplier.h',
- 'source_line_resolver_base.cc',
- 'source_line_resolver_base_types.h',
- 'stack_frame_cpu.cc',
- 'stack_frame_symbolizer.cc',
- 'stackwalk_common.cc',
- 'stackwalk_common.h',
- 'stackwalker.cc',
- 'stackwalker_address_list.cc',
- 'stackwalker_address_list.h',
- 'stackwalker_amd64.cc',
- 'stackwalker_amd64.h',
- 'stackwalker_arm.cc',
- 'stackwalker_arm.h',
- 'stackwalker_arm64.cc',
- 'stackwalker_arm64.h',
- 'stackwalker_mips.cc',
- 'stackwalker_mips.h',
- 'stackwalker_ppc.cc',
- 'stackwalker_ppc.h',
- 'stackwalker_ppc64.cc',
- 'stackwalker_ppc64.h',
- 'stackwalker_selftest.cc',
- 'stackwalker_sparc.cc',
- 'stackwalker_sparc.h',
- 'stackwalker_x86.cc',
- 'stackwalker_x86.h',
- 'static_address_map-inl.h',
- 'static_address_map.h',
- 'static_contained_range_map-inl.h',
- 'static_contained_range_map.h',
- 'static_map-inl.h',
- 'static_map.h',
- 'static_map_iterator-inl.h',
- 'static_map_iterator.h',
- 'static_range_map-inl.h',
- 'static_range_map.h',
- 'symbolic_constants_win.cc',
- 'symbolic_constants_win.h',
- 'synth_minidump.cc',
- 'synth_minidump.h',
- 'tokenize.cc',
- 'tokenize.h',
- 'windows_frame_info.h',
- ],
- 'include_dirs': [
- '..',
- ],
- 'dependencies': [
- '../common/common.gyp:common',
- '../third_party/libdisasm/libdisasm.gyp:libdisasm',
- ],
- },
- {
- 'target_name': 'processor_unittests',
- 'type': 'executable',
- 'sources': [
- 'address_map_unittest.cc',
- 'basic_source_line_resolver_unittest.cc',
- 'cfi_frame_info_unittest.cc',
- 'contained_range_map_unittest.cc',
- 'disassembler_x86_unittest.cc',
- 'exploitability_unittest.cc',
- 'fast_source_line_resolver_unittest.cc',
- 'map_serializers_unittest.cc',
- 'microdump_processor_unittest.cc',
- 'minidump_processor_unittest.cc',
- 'minidump_unittest.cc',
- 'pathname_stripper_unittest.cc',
- 'postfix_evaluator_unittest.cc',
- 'range_map_truncate_lower_unittest.cc',
- 'range_map_truncate_upper_unittest.cc',
- 'range_map_unittest.cc',
- 'stackwalker_address_list_unittest.cc',
- 'stackwalker_amd64_unittest.cc',
- 'stackwalker_arm64_unittest.cc',
- 'stackwalker_arm_unittest.cc',
- 'stackwalker_mips_unittest.cc',
- 'stackwalker_mips64_unittest.cc',
- 'stackwalker_unittest_utils.h',
- 'stackwalker_x86_unittest.cc',
- 'static_address_map_unittest.cc',
- 'static_contained_range_map_unittest.cc',
- 'static_map_unittest.cc',
- 'static_range_map_unittest.cc',
- 'synth_minidump_unittest.cc',
- 'synth_minidump_unittest_data.h',
- ],
- 'include_dirs': [
- '..',
- ],
- 'dependencies': [
- 'processor',
- '../build/testing.gyp:gmock',
- '../build/testing.gyp:gtest',
- ],
- },
- ],
-}
diff --git a/src/processor/processor_tools.gypi b/src/processor/processor_tools.gypi
deleted file mode 100644
index ecb450d6..00000000
--- a/src/processor/processor_tools.gypi
+++ /dev/null
@@ -1,57 +0,0 @@
-# Copyright 2014 Google Inc. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-# * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-# * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-{
- 'target_defaults': {
- 'include_dirs': [
- '..',
- ],
- },
- 'targets': [
- {
- 'target_name': 'minidump_dump',
- 'type': 'executable',
- 'sources': [
- 'minidump_dump.cc',
- ],
- 'dependencies': [
- 'processor',
- ],
- },
- {
- 'target_name': 'minidump_stackwalk',
- 'type': 'executable',
- 'sources': [
- 'minidump_stackwalk.cc',
- ],
- 'dependencies': [
- 'processor',
- ],
- },
- ],
-}
diff --git a/src/processor/proto/process_state.proto b/src/processor/proto/process_state.proto
index d3e02dc3..f6b5fb4f 100644
--- a/src/processor/proto/process_state.proto
+++ b/src/processor/proto/process_state.proto
@@ -1,5 +1,4 @@
-// Copyright (c) 2010, Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/processor/range_map-inl.h b/src/processor/range_map-inl.h
index 4d3b0eb9..860314f5 100644
--- a/src/processor/range_map-inl.h
+++ b/src/processor/range_map-inl.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2010 Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -39,6 +38,7 @@
#include <assert.h>
+#include "common/safe_math.h"
#include "processor/range_map.h"
#include "processor/linked_ptr.h"
#include "processor/logging.h"
@@ -47,20 +47,25 @@
namespace google_breakpad {
template<typename AddressType, typename EntryType>
-bool RangeMap<AddressType, EntryType>::StoreRange(const AddressType &base,
- const AddressType &size,
- const EntryType &entry) {
+bool RangeMap<AddressType, EntryType>::StoreRange(const AddressType& base,
+ const AddressType& size,
+ const EntryType& entry) {
return StoreRangeInternal(base, 0 /* delta */, size, entry);
}
template<typename AddressType, typename EntryType>
bool RangeMap<AddressType, EntryType>::StoreRangeInternal(
- const AddressType &base, const AddressType &delta,
- const AddressType &size, const EntryType &entry) {
- AddressType high = base + (size - 1);
-
+ const AddressType& base, const AddressType& delta,
+ const AddressType& size, const EntryType& entry) {
+ AddressType high;
+ bool high_ok = false;
+ if (size > 0) {
+ std::pair<AddressType, bool> result = AddWithOverflowCheck(base, size - 1);
+ high = result.first;
+ high_ok = !result.second;
+ }
// Check for undersize or overflow.
- if (size <= 0 || high < base) {
+ if (!high_ok) {
// The processor will hit this case too frequently with common symbol
// files in the size == 0 case, which is more suited to a DEBUG channel.
// Filter those out since there's no DEBUG channel at the moment.
@@ -181,8 +186,8 @@ bool RangeMap<AddressType, EntryType>::StoreRangeInternal(
template<typename AddressType, typename EntryType>
bool RangeMap<AddressType, EntryType>::RetrieveRange(
- const AddressType &address, EntryType *entry, AddressType *entry_base,
- AddressType *entry_delta, AddressType *entry_size) const {
+ const AddressType& address, EntryType* entry, AddressType* entry_base,
+ AddressType* entry_delta, AddressType* entry_size) const {
BPLOG_IF(ERROR, !entry) << "RangeMap::RetrieveRange requires |entry|";
assert(entry);
@@ -212,8 +217,8 @@ bool RangeMap<AddressType, EntryType>::RetrieveRange(
template<typename AddressType, typename EntryType>
bool RangeMap<AddressType, EntryType>::RetrieveNearestRange(
- const AddressType &address, EntryType *entry, AddressType *entry_base,
- AddressType *entry_delta, AddressType *entry_size) const {
+ const AddressType& address, EntryType* entry, AddressType* entry_base,
+ AddressType* entry_delta, AddressType* entry_size) const {
BPLOG_IF(ERROR, !entry) << "RangeMap::RetrieveNearestRange requires |entry|";
assert(entry);
@@ -245,8 +250,8 @@ bool RangeMap<AddressType, EntryType>::RetrieveNearestRange(
template<typename AddressType, typename EntryType>
bool RangeMap<AddressType, EntryType>::RetrieveRangeAtIndex(
- int index, EntryType *entry, AddressType *entry_base,
- AddressType *entry_delta, AddressType *entry_size) const {
+ int index, EntryType* entry, AddressType* entry_base,
+ AddressType* entry_delta, AddressType* entry_size) const {
BPLOG_IF(ERROR, !entry) << "RangeMap::RetrieveRangeAtIndex requires |entry|";
assert(entry);
diff --git a/src/processor/range_map.h b/src/processor/range_map.h
index 33f32973..578bd144 100644
--- a/src/processor/range_map.h
+++ b/src/processor/range_map.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2006, Google Inc.
-// All rights reserved.
+// Copyright 2006 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -78,17 +77,17 @@ class RangeMap {
// stored in the map. If enable_shrink_down is true and there is an overlap
// between the current range and some other range (already in the map),
// shrink down the range which ends at a higher address.
- bool StoreRange(const AddressType &base, const AddressType &size,
- const EntryType &entry);
+ bool StoreRange(const AddressType& base, const AddressType& size,
+ const EntryType& entry);
// Locates the range encompassing the supplied address. If there is no such
// range, returns false. entry_base, entry_delta, and entry_size, if
// non-NULL, are set to the base, delta, and size of the entry's range.
// A positive entry delta (> 0) indicates that there was an overlap and the
// entry was shrunk down (original start address was increased by delta).
- bool RetrieveRange(const AddressType &address, EntryType *entry,
- AddressType *entry_base, AddressType *entry_delta,
- AddressType *entry_size) const;
+ bool RetrieveRange(const AddressType& address, EntryType* entry,
+ AddressType* entry_base, AddressType* entry_delta,
+ AddressType* entry_size) const;
// Locates the range encompassing the supplied address, if one exists.
// If no range encompasses the supplied address, locates the nearest range
@@ -97,9 +96,9 @@ class RangeMap {
// if non-NULL, are set to the base, delta, and size of the entry's range.
// A positive entry delta (> 0) indicates that there was an overlap and the
// entry was shrunk down (original start address was increased by delta).
- bool RetrieveNearestRange(const AddressType &address, EntryType *entry,
- AddressType *entry_base, AddressType *entry_delta,
- AddressType *entry_size) const;
+ bool RetrieveNearestRange(const AddressType& address, EntryType* entry,
+ AddressType* entry_base, AddressType* entry_delta,
+ AddressType* entry_size) const;
// Treating all ranges as a list ordered by the address spaces that they
// occupy, locates the range at the index specified by index. Returns
@@ -110,9 +109,9 @@ class RangeMap {
// entry was shrunk down (original start address was increased by delta).
//
// RetrieveRangeAtIndex is not optimized for speedy operation.
- bool RetrieveRangeAtIndex(int index, EntryType *entry,
- AddressType *entry_base, AddressType *entry_delta,
- AddressType *entry_size) const;
+ bool RetrieveRangeAtIndex(int index, EntryType* entry,
+ AddressType* entry_base, AddressType* entry_delta,
+ AddressType* entry_size) const;
// Returns the number of ranges stored in the RangeMap.
int GetCount() const;
@@ -128,13 +127,13 @@ class RangeMap {
// Same a StoreRange() with the only exception that the |delta| can be
// passed in.
- bool StoreRangeInternal(const AddressType &base, const AddressType &delta,
- const AddressType &size, const EntryType &entry);
+ bool StoreRangeInternal(const AddressType& base, const AddressType& delta,
+ const AddressType& size, const EntryType& entry);
class Range {
public:
- Range(const AddressType &base, const AddressType &delta,
- const EntryType &entry)
+ Range(const AddressType& base, const AddressType& delta,
+ const EntryType& entry)
: base_(base), delta_(delta), entry_(entry) {}
AddressType base() const { return base_; }
diff --git a/src/processor/range_map_truncate_lower_unittest.cc b/src/processor/range_map_truncate_lower_unittest.cc
index a933c956..12dad873 100644
--- a/src/processor/range_map_truncate_lower_unittest.cc
+++ b/src/processor/range_map_truncate_lower_unittest.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2019, Google Inc.
-// All rights reserved.
+// Copyright 2019 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -25,7 +24,7 @@
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <limits.h>
#include <stdio.h>
diff --git a/src/processor/range_map_truncate_upper_unittest.cc b/src/processor/range_map_truncate_upper_unittest.cc
index 7e3034f2..57046e19 100644
--- a/src/processor/range_map_truncate_upper_unittest.cc
+++ b/src/processor/range_map_truncate_upper_unittest.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2016, Google Inc.
-// All rights reserved.
+// Copyright 2016 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -25,7 +24,7 @@
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// range_map_shrink_down_unittest.cc: Unit tests for RangeMap that specifically
// test shrink down when ranges overlap.
diff --git a/src/processor/range_map_unittest.cc b/src/processor/range_map_unittest.cc
index 31b89e5d..2745e809 100644
--- a/src/processor/range_map_unittest.cc
+++ b/src/processor/range_map_unittest.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2010 Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -43,11 +42,10 @@
namespace {
-
+using google_breakpad::AddIgnoringOverflow;
using google_breakpad::linked_ptr;
-using google_breakpad::scoped_ptr;
using google_breakpad::RangeMap;
-
+using google_breakpad::scoped_ptr;
// A CountedObject holds an int. A global (not thread safe!) count of
// allocated CountedObjects is maintained to help test memory management.
@@ -92,7 +90,7 @@ struct RangeTest {
// sequence on the same RangeMap.
struct RangeTestSet {
// An array of RangeTests
- const RangeTest *range_tests;
+ const RangeTest* range_tests;
// The number of tests in the set
unsigned int range_test_count;
@@ -102,7 +100,7 @@ struct RangeTestSet {
// StoreTest uses the data in a RangeTest and calls StoreRange on the
// test RangeMap. It returns true if the expected result occurred, and
// false if something else happened.
-static bool StoreTest(TestMap *range_map, const RangeTest *range_test) {
+static bool StoreTest(TestMap* range_map, const RangeTest* range_test) {
linked_ptr<CountedObject> object(new CountedObject(range_test->id));
bool stored = range_map->StoreRange(range_test->address,
range_test->size,
@@ -126,7 +124,7 @@ static bool StoreTest(TestMap *range_map, const RangeTest *range_test) {
// map entry at the specified range,) it returns true, otherwise, it returns
// false. RetrieveTest will check the values around the base address and
// the high address of a range to guard against off-by-one errors.
-static bool RetrieveTest(TestMap *range_map, const RangeTest *range_test) {
+static bool RetrieveTest(TestMap* range_map, const RangeTest* range_test) {
for (unsigned int side = 0; side <= 1; ++side) {
// When side == 0, check the low side (base address) of each range.
// When side == 1, check the high side (base + size) of each range.
@@ -148,10 +146,10 @@ static bool RetrieveTest(TestMap *range_map, const RangeTest *range_test) {
}
for (AddressType offset = low_offset; offset <= high_offset; ++offset) {
- AddressType address =
- offset +
- (!side ? range_test->address :
- range_test->address + range_test->size - 1);
+ AddressType address = AddIgnoringOverflow(
+ offset, (!side ? range_test->address
+ : AddIgnoringOverflow(range_test->address,
+ range_test->size - 1)));
bool expected_result = false; // This is correct for tests not stored.
if (range_test->expect_storable) {
@@ -270,9 +268,9 @@ static bool RetrieveTest(TestMap *range_map, const RangeTest *range_test) {
// and verifying that each call returns a different object than the previous
// call, and that ranges are returned with increasing base addresses. Returns
// false if the test fails.
-static bool RetrieveIndexTest(TestMap *range_map, int set) {
+static bool RetrieveIndexTest(TestMap* range_map, int set) {
linked_ptr<CountedObject> object;
- CountedObject *last_object = NULL;
+ CountedObject* last_object = NULL;
AddressType last_base = 0;
int object_count = range_map->GetCount();
@@ -469,7 +467,7 @@ static bool RunTests() {
for (unsigned int range_test_set_index = 0;
range_test_set_index < range_test_set_count;
++range_test_set_index) {
- const RangeTest *range_tests =
+ const RangeTest* range_tests =
range_test_sets[range_test_set_index].range_tests;
unsigned int range_test_count =
range_test_sets[range_test_set_index].range_test_count;
@@ -480,7 +478,7 @@ static bool RunTests() {
for (unsigned int range_test_index = 0;
range_test_index < range_test_count;
++range_test_index) {
- const RangeTest *range_test = &range_tests[range_test_index];
+ const RangeTest* range_test = &range_tests[range_test_index];
if (!StoreTest(range_map.get(), range_test))
return false;
@@ -512,7 +510,7 @@ static bool RunTests() {
for (unsigned int range_test_index = 0;
range_test_index < range_test_count;
++range_test_index) {
- const RangeTest *range_test = &range_tests[range_test_index];
+ const RangeTest* range_test = &range_tests[range_test_index];
if (!RetrieveTest(range_map.get(), range_test))
return false;
}
@@ -552,7 +550,7 @@ static bool RunTests() {
} // namespace
-int main(int argc, char **argv) {
+int main(int argc, char** argv) {
BPLOG_INIT(&argc, &argv);
return RunTests() ? 0 : 1;
diff --git a/src/processor/simple_serializer-inl.h b/src/processor/simple_serializer-inl.h
index 606bb3ce..bc2c8def 100644
--- a/src/processor/simple_serializer-inl.h
+++ b/src/processor/simple_serializer-inl.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2010, Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -38,14 +37,15 @@
#ifndef PROCESSOR_SIMPLE_SERIALIZER_INL_H__
#define PROCESSOR_SIMPLE_SERIALIZER_INL_H__
-#include <string>
-
#include "processor/simple_serializer.h"
-#include "map_serializers-inl.h"
+
+#include <cstdint>
+#include <string>
#include "google_breakpad/processor/basic_source_line_resolver.h"
#include "processor/basic_source_line_resolver_types.h"
#include "processor/linked_ptr.h"
+#include "processor/map_serializers-inl.h"
#include "processor/windows_frame_info.h"
namespace google_breakpad {
@@ -56,12 +56,12 @@ class SimpleSerializer<bool> {
public:
static size_t SizeOf(bool boolean) { return 1; }
- static char *Write(bool boolean, char *dest) {
+ static char* Write(bool boolean, char* dest) {
*dest = static_cast<char>(boolean? 255 : 0);
return ++dest;
}
- static const char *Read(const char *source, bool *value) {
+ static const char* Read(const char* source, bool* value) {
*value = ((*source) == 0 ? false : true);
return ++source;
}
@@ -71,9 +71,9 @@ class SimpleSerializer<bool> {
template<>
class SimpleSerializer<string> {
public:
- static size_t SizeOf(const string &str) { return str.size() + 1; }
+ static size_t SizeOf(const string& str) { return str.size() + 1; }
- static char *Write(const string &str, char *dest) {
+ static char* Write(const string& str, char* dest) {
strcpy(dest, str.c_str());
return dest + SizeOf(str);
}
@@ -83,11 +83,11 @@ class SimpleSerializer<string> {
template<>
class SimpleSerializer<const char*> {
public:
- static size_t SizeOf(const char *cstring) {
+ static size_t SizeOf(const char* cstring) {
return strlen(cstring) + 1;
}
- static char *Write(const char *cstring, char *dest) {
+ static char* Write(const char* cstring, char* dest) {
strcpy(dest, cstring);
return dest + SizeOf(cstring);
}
@@ -98,13 +98,13 @@ template<>
class SimpleSerializer<BasicSourceLineResolver::Line> {
typedef BasicSourceLineResolver::Line Line;
public:
- static size_t SizeOf(const Line &line) {
+ static size_t SizeOf(const Line& line) {
return SimpleSerializer<MemAddr>::SizeOf(line.address)
+ SimpleSerializer<MemAddr>::SizeOf(line.size)
+ SimpleSerializer<int32_t>::SizeOf(line.source_file_id)
+ SimpleSerializer<int32_t>::SizeOf(line.line);
}
- static char *Write(const Line &line, char *dest) {
+ static char* Write(const Line& line, char* dest) {
dest = SimpleSerializer<MemAddr>::Write(line.address, dest);
dest = SimpleSerializer<MemAddr>::Write(line.size, dest);
dest = SimpleSerializer<int32_t>::Write(line.source_file_id, dest);
@@ -113,20 +113,41 @@ class SimpleSerializer<BasicSourceLineResolver::Line> {
}
};
+// Specializations of SimpleSerializer: InlineOrigin
+template <>
+class SimpleSerializer<BasicSourceLineResolver::InlineOrigin> {
+ typedef BasicSourceLineResolver::InlineOrigin InlineOrigin;
+
+ public:
+ static size_t SizeOf(const InlineOrigin& origin) {
+ return SimpleSerializer<bool>::SizeOf(origin.has_file_id) +
+ SimpleSerializer<int32_t>::SizeOf(origin.source_file_id) +
+ SimpleSerializer<string>::SizeOf(origin.name);
+ }
+ static char* Write(const InlineOrigin& origin, char* dest) {
+ dest = SimpleSerializer<bool>::Write(origin.has_file_id, dest);
+ dest = SimpleSerializer<int32_t>::Write(origin.source_file_id, dest);
+ dest = SimpleSerializer<string>::Write(origin.name, dest);
+ return dest;
+ }
+};
+
// Specializations of SimpleSerializer: PublicSymbol
template<>
class SimpleSerializer<BasicSourceLineResolver::PublicSymbol> {
typedef BasicSourceLineResolver::PublicSymbol PublicSymbol;
public:
- static size_t SizeOf(const PublicSymbol &pubsymbol) {
+ static size_t SizeOf(const PublicSymbol& pubsymbol) {
return SimpleSerializer<string>::SizeOf(pubsymbol.name)
+ SimpleSerializer<MemAddr>::SizeOf(pubsymbol.address)
- + SimpleSerializer<int32_t>::SizeOf(pubsymbol.parameter_size);
+ + SimpleSerializer<int32_t>::SizeOf(pubsymbol.parameter_size)
+ + SimpleSerializer<bool>::SizeOf(pubsymbol.is_multiple);
}
- static char *Write(const PublicSymbol &pubsymbol, char *dest) {
+ static char* Write(const PublicSymbol& pubsymbol, char* dest) {
dest = SimpleSerializer<string>::Write(pubsymbol.name, dest);
dest = SimpleSerializer<MemAddr>::Write(pubsymbol.address, dest);
dest = SimpleSerializer<int32_t>::Write(pubsymbol.parameter_size, dest);
+ dest = SimpleSerializer<bool>::Write(pubsymbol.is_multiple, dest);
return dest;
}
};
@@ -135,7 +156,7 @@ class SimpleSerializer<BasicSourceLineResolver::PublicSymbol> {
template<>
class SimpleSerializer<WindowsFrameInfo> {
public:
- static size_t SizeOf(const WindowsFrameInfo &wfi) {
+ static size_t SizeOf(const WindowsFrameInfo& wfi) {
unsigned int size = 0;
size += sizeof(int32_t); // wfi.type_
size += SimpleSerializer<int32_t>::SizeOf(wfi.valid);
@@ -149,7 +170,7 @@ class SimpleSerializer<WindowsFrameInfo> {
size += SimpleSerializer<string>::SizeOf(wfi.program_string);
return size;
}
- static char *Write(const WindowsFrameInfo &wfi, char *dest) {
+ static char* Write(const WindowsFrameInfo& wfi, char* dest) {
dest = SimpleSerializer<int32_t>::Write(
static_cast<const int32_t>(wfi.type_), dest);
dest = SimpleSerializer<int32_t>::Write(wfi.valid, dest);
@@ -165,61 +186,151 @@ class SimpleSerializer<WindowsFrameInfo> {
};
// Specializations of SimpleSerializer: Linked_ptr version of
-// Line, Function, PublicSymbol, WindowsFrameInfo.
+// Line, InlineOrigin, Inline, Function, PublicSymbol, WindowsFrameInfo.
template<>
class SimpleSerializer< linked_ptr<BasicSourceLineResolver::Line> > {
typedef BasicSourceLineResolver::Line Line;
public:
- static size_t SizeOf(const linked_ptr<Line> &lineptr) {
+ static size_t SizeOf(const linked_ptr<Line>& lineptr) {
if (lineptr.get() == NULL) return 0;
return SimpleSerializer<Line>::SizeOf(*(lineptr.get()));
}
- static char *Write(const linked_ptr<Line> &lineptr, char *dest) {
+ static char* Write(const linked_ptr<Line>& lineptr, char* dest) {
if (lineptr.get())
dest = SimpleSerializer<Line>::Write(*(lineptr.get()), dest);
return dest;
}
};
+template <>
+class SimpleSerializer<linked_ptr<BasicSourceLineResolver::InlineOrigin>> {
+ typedef BasicSourceLineResolver::InlineOrigin InlineOrigin;
+
+ public:
+ static size_t SizeOf(const linked_ptr<InlineOrigin>& origin_ptr) {
+ if (origin_ptr.get() == NULL)
+ return 0;
+ return SimpleSerializer<InlineOrigin>::SizeOf(*(origin_ptr.get()));
+ }
+ static char* Write(const linked_ptr<InlineOrigin>& origin_ptr, char* dest) {
+ if (origin_ptr.get())
+ dest = SimpleSerializer<InlineOrigin>::Write(*(origin_ptr.get()), dest);
+ return dest;
+ }
+};
+
+// Specializations of SimpleSerializer: Inline
+template <>
+class SimpleSerializer<linked_ptr<BasicSourceLineResolver::Inline>>;
+template <>
+class SimpleSerializer<BasicSourceLineResolver::Inline> {
+ typedef BasicSourceLineResolver::Inline Inline;
+
+ public:
+ inline static size_t SizeOf(const Inline& in);
+ inline static char* Write(const Inline& in, char* dest);
+};
+
+template <>
+class SimpleSerializer<linked_ptr<BasicSourceLineResolver::Inline>> {
+ typedef BasicSourceLineResolver::Inline Inline;
+
+ public:
+ static size_t SizeOf(const linked_ptr<Inline>& inline_ptr) {
+ if (inline_ptr.get() == NULL)
+ return 0;
+ return SimpleSerializer<Inline>::SizeOf(*(inline_ptr.get()));
+ }
+ static char* Write(const linked_ptr<Inline>& inline_ptr, char* dest) {
+ if (inline_ptr.get())
+ dest = SimpleSerializer<Inline>::Write(*(inline_ptr.get()), dest);
+ return dest;
+ }
+};
+
+size_t SimpleSerializer<BasicSourceLineResolver::Inline>::SizeOf(
+ const Inline& in) {
+ return SimpleSerializer<bool>::SizeOf(in.has_call_site_file_id) +
+ SimpleSerializer<int32_t>::SizeOf(in.inline_nest_level) +
+ SimpleSerializer<int32_t>::SizeOf(in.call_site_line) +
+ SimpleSerializer<int32_t>::SizeOf(in.call_site_file_id) +
+ SimpleSerializer<int32_t>::SizeOf(in.origin_id) +
+ sizeof(uint32_t) + // This is to store the size of inline_ranges.
+ (in.inline_ranges.size() * sizeof(MemAddr) * 2);
+}
+
+char* SimpleSerializer<BasicSourceLineResolver::Inline>::Write(const Inline& in,
+ char* dest) {
+ dest = SimpleSerializer<bool>::Write(in.has_call_site_file_id, dest);
+ dest = SimpleSerializer<int32_t>::Write(in.inline_nest_level, dest);
+ dest = SimpleSerializer<int32_t>::Write(in.call_site_line, dest);
+ dest = SimpleSerializer<int32_t>::Write(in.call_site_file_id, dest);
+ dest = SimpleSerializer<int32_t>::Write(in.origin_id, dest);
+ // Write the size of inline_ranges.
+ dest = SimpleSerializer<int32_t>::Write(in.inline_ranges.size(), dest);
+ for (const std::pair<MemAddr, MemAddr>& range : in.inline_ranges) {
+ dest = SimpleSerializer<MemAddr>::Write(range.first, dest);
+ dest = SimpleSerializer<MemAddr>::Write(range.second, dest);
+ }
+ return dest;
+}
+
template<>
class SimpleSerializer<BasicSourceLineResolver::Function> {
// Convenient type names.
typedef BasicSourceLineResolver::Function Function;
typedef BasicSourceLineResolver::Line Line;
+ typedef BasicSourceLineResolver::Inline Inline;
+
public:
- static size_t SizeOf(const Function &func) {
+ static size_t SizeOf(const Function& func) {
unsigned int size = 0;
size += SimpleSerializer<string>::SizeOf(func.name);
size += SimpleSerializer<MemAddr>::SizeOf(func.address);
size += SimpleSerializer<MemAddr>::SizeOf(func.size);
size += SimpleSerializer<int32_t>::SizeOf(func.parameter_size);
+ size += SimpleSerializer<bool>::SizeOf(func.is_multiple);
+ // This extra size is used to store the size of serialized func.inlines, so
+ // we know where to start de-serialize func.lines.
+ size += sizeof(int32_t);
+ size += inline_range_map_serializer_.SizeOf(&func.inlines);
size += range_map_serializer_.SizeOf(func.lines);
return size;
}
- static char *Write(const Function &func, char *dest) {
+ static char* Write(const Function& func, char* dest) {
dest = SimpleSerializer<string>::Write(func.name, dest);
dest = SimpleSerializer<MemAddr>::Write(func.address, dest);
dest = SimpleSerializer<MemAddr>::Write(func.size, dest);
dest = SimpleSerializer<int32_t>::Write(func.parameter_size, dest);
+ dest = SimpleSerializer<bool>::Write(func.is_multiple, dest);
+ char* old_dest = dest;
+ dest += sizeof(int32_t);
+ dest = inline_range_map_serializer_.Write(&func.inlines, dest);
+ // Write the size of serialized func.inlines. The size doesn't include size
+ // field itself.
+ SimpleSerializer<MemAddr>::Write(dest - old_dest - sizeof(int32_t),
+ old_dest);
dest = range_map_serializer_.Write(func.lines, dest);
return dest;
}
private:
// This static member is defined in module_serializer.cc.
- static RangeMapSerializer< MemAddr, linked_ptr<Line> > range_map_serializer_;
+ static RangeMapSerializer<MemAddr, linked_ptr<Line>> range_map_serializer_;
+ static ContainedRangeMapSerializer<MemAddr, linked_ptr<Inline>>
+ inline_range_map_serializer_;
};
template<>
class SimpleSerializer< linked_ptr<BasicSourceLineResolver::Function> > {
typedef BasicSourceLineResolver::Function Function;
public:
- static size_t SizeOf(const linked_ptr<Function> &func) {
+ static size_t SizeOf(const linked_ptr<Function>& func) {
if (!func.get()) return 0;
return SimpleSerializer<Function>::SizeOf(*(func.get()));
}
- static char *Write(const linked_ptr<Function> &func, char *dest) {
+ static char* Write(const linked_ptr<Function>& func, char* dest) {
if (func.get())
dest = SimpleSerializer<Function>::Write(*(func.get()), dest);
return dest;
@@ -230,11 +341,11 @@ template<>
class SimpleSerializer< linked_ptr<BasicSourceLineResolver::PublicSymbol> > {
typedef BasicSourceLineResolver::PublicSymbol PublicSymbol;
public:
- static size_t SizeOf(const linked_ptr<PublicSymbol> &pubsymbol) {
+ static size_t SizeOf(const linked_ptr<PublicSymbol>& pubsymbol) {
if (pubsymbol.get() == NULL) return 0;
return SimpleSerializer<PublicSymbol>::SizeOf(*(pubsymbol.get()));
}
- static char *Write(const linked_ptr<PublicSymbol> &pubsymbol, char *dest) {
+ static char* Write(const linked_ptr<PublicSymbol>& pubsymbol, char* dest) {
if (pubsymbol.get())
dest = SimpleSerializer<PublicSymbol>::Write(*(pubsymbol.get()), dest);
return dest;
@@ -244,11 +355,11 @@ class SimpleSerializer< linked_ptr<BasicSourceLineResolver::PublicSymbol> > {
template<>
class SimpleSerializer< linked_ptr<WindowsFrameInfo> > {
public:
- static size_t SizeOf(const linked_ptr<WindowsFrameInfo> &wfi) {
+ static size_t SizeOf(const linked_ptr<WindowsFrameInfo>& wfi) {
if (wfi.get() == NULL) return 0;
return SimpleSerializer<WindowsFrameInfo>::SizeOf(*(wfi.get()));
}
- static char *Write(const linked_ptr<WindowsFrameInfo> &wfi, char *dest) {
+ static char* Write(const linked_ptr<WindowsFrameInfo>& wfi, char* dest) {
if (wfi.get())
dest = SimpleSerializer<WindowsFrameInfo>::Write(*(wfi.get()), dest);
return dest;
diff --git a/src/processor/simple_serializer.h b/src/processor/simple_serializer.h
index 275f51ce..bd6cc84c 100644
--- a/src/processor/simple_serializer.h
+++ b/src/processor/simple_serializer.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2010, Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -38,6 +37,8 @@
#ifndef PROCESSOR_SIMPLE_SERIALIZER_H__
#define PROCESSOR_SIMPLE_SERIALIZER_H__
+#include <stddef.h>
+
#include "google_breakpad/common/breakpad_types.h"
namespace google_breakpad {
@@ -49,10 +50,10 @@ typedef uint64_t MemAddr;
template<class Type> class SimpleSerializer {
public:
// Calculate and return the size of the 'item'.
- static size_t SizeOf(const Type &item) { return sizeof(item); }
+ static size_t SizeOf(const Type& item) { return sizeof(item); }
// Write 'item' to memory location 'dest', and return to the "end" address of
// data written, i.e., the address after the final byte written.
- static char *Write(const Type &item, char *dest) {
+ static char* Write(const Type& item, char* dest) {
new (dest) Type(item);
return dest + SizeOf(item);
}
diff --git a/src/processor/simple_symbol_supplier.cc b/src/processor/simple_symbol_supplier.cc
index bc5ebb68..5b3f6819 100644
--- a/src/processor/simple_symbol_supplier.cc
+++ b/src/processor/simple_symbol_supplier.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2006, Google Inc.
-// All rights reserved.
+// Copyright 2006 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -52,14 +51,14 @@
namespace google_breakpad {
-static bool file_exists(const string &file_name) {
+static bool file_exists(const string& file_name) {
struct stat sb;
return stat(file_name.c_str(), &sb) == 0;
}
SymbolSupplier::SymbolResult SimpleSymbolSupplier::GetSymbolFile(
- const CodeModule *module, const SystemInfo *system_info,
- string *symbol_file) {
+ const CodeModule* module, const SystemInfo* system_info,
+ string* symbol_file) {
BPLOG_IF(ERROR, !symbol_file) << "SimpleSymbolSupplier::GetSymbolFile "
"requires |symbol_file|";
assert(symbol_file);
@@ -77,10 +76,10 @@ SymbolSupplier::SymbolResult SimpleSymbolSupplier::GetSymbolFile(
}
SymbolSupplier::SymbolResult SimpleSymbolSupplier::GetSymbolFile(
- const CodeModule *module,
- const SystemInfo *system_info,
- string *symbol_file,
- string *symbol_data) {
+ const CodeModule* module,
+ const SystemInfo* system_info,
+ string* symbol_file,
+ string* symbol_data) {
assert(symbol_data);
symbol_data->clear();
@@ -96,11 +95,11 @@ SymbolSupplier::SymbolResult SimpleSymbolSupplier::GetSymbolFile(
}
SymbolSupplier::SymbolResult SimpleSymbolSupplier::GetCStringSymbolData(
- const CodeModule *module,
- const SystemInfo *system_info,
- string *symbol_file,
- char **symbol_data,
- size_t *symbol_data_size) {
+ const CodeModule* module,
+ const SystemInfo* system_info,
+ string* symbol_file,
+ char** symbol_data,
+ size_t* symbol_data_size) {
assert(symbol_data);
assert(symbol_data_size);
@@ -123,13 +122,13 @@ SymbolSupplier::SymbolResult SimpleSymbolSupplier::GetCStringSymbolData(
return s;
}
-void SimpleSymbolSupplier::FreeSymbolData(const CodeModule *module) {
+void SimpleSymbolSupplier::FreeSymbolData(const CodeModule* module) {
if (!module) {
BPLOG(INFO) << "Cannot free symbol data buffer for NULL module";
return;
}
- map<string, char *>::iterator it = memory_buffers_.find(module->code_file());
+ map<string, char*>::iterator it = memory_buffers_.find(module->code_file());
if (it == memory_buffers_.end()) {
BPLOG(INFO) << "Cannot find symbol data buffer for module "
<< module->code_file();
@@ -140,8 +139,8 @@ void SimpleSymbolSupplier::FreeSymbolData(const CodeModule *module) {
}
SymbolSupplier::SymbolResult SimpleSymbolSupplier::GetSymbolFileAtPathFromRoot(
- const CodeModule *module, const SystemInfo *system_info,
- const string &root_path, string *symbol_file) {
+ const CodeModule* module, const SystemInfo* system_info,
+ const string& root_path, string* symbol_file) {
BPLOG_IF(ERROR, !symbol_file) << "SimpleSymbolSupplier::GetSymbolFileAtPath "
"requires |symbol_file|";
assert(symbol_file);
diff --git a/src/processor/simple_symbol_supplier.h b/src/processor/simple_symbol_supplier.h
index 0cde85cd..3302bab6 100644
--- a/src/processor/simple_symbol_supplier.h
+++ b/src/processor/simple_symbol_supplier.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2006, Google Inc.
-// All rights reserved.
+// Copyright 2006 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -94,44 +93,44 @@ class SimpleSymbolSupplier : public SymbolSupplier {
public:
// Creates a new SimpleSymbolSupplier, using path as the root path where
// symbols are stored.
- explicit SimpleSymbolSupplier(const string &path) : paths_(1, path) {}
+ explicit SimpleSymbolSupplier(const string& path) : paths_(1, path) {}
// Creates a new SimpleSymbolSupplier, using paths as a list of root
// paths where symbols may be stored.
- explicit SimpleSymbolSupplier(const vector<string> &paths) : paths_(paths) {}
+ explicit SimpleSymbolSupplier(const vector<string>& paths) : paths_(paths) {}
virtual ~SimpleSymbolSupplier() {}
// Returns the path to the symbol file for the given module. See the
// description above.
- virtual SymbolResult GetSymbolFile(const CodeModule *module,
- const SystemInfo *system_info,
- string *symbol_file);
+ virtual SymbolResult GetSymbolFile(const CodeModule* module,
+ const SystemInfo* system_info,
+ string* symbol_file);
- virtual SymbolResult GetSymbolFile(const CodeModule *module,
- const SystemInfo *system_info,
- string *symbol_file,
- string *symbol_data);
+ virtual SymbolResult GetSymbolFile(const CodeModule* module,
+ const SystemInfo* system_info,
+ string* symbol_file,
+ string* symbol_data);
// Allocates data buffer on heap and writes symbol data into buffer.
// Symbol supplier ALWAYS takes ownership of the data buffer.
- virtual SymbolResult GetCStringSymbolData(const CodeModule *module,
- const SystemInfo *system_info,
- string *symbol_file,
- char **symbol_data,
- size_t *symbol_data_size);
+ virtual SymbolResult GetCStringSymbolData(const CodeModule* module,
+ const SystemInfo* system_info,
+ string* symbol_file,
+ char** symbol_data,
+ size_t* symbol_data_size);
// Free the data buffer allocated in the above GetCStringSymbolData();
- virtual void FreeSymbolData(const CodeModule *module);
+ virtual void FreeSymbolData(const CodeModule* module);
protected:
- SymbolResult GetSymbolFileAtPathFromRoot(const CodeModule *module,
- const SystemInfo *system_info,
- const string &root_path,
- string *symbol_file);
+ SymbolResult GetSymbolFileAtPathFromRoot(const CodeModule* module,
+ const SystemInfo* system_info,
+ const string& root_path,
+ string* symbol_file);
private:
- map<string, char *> memory_buffers_;
+ map<string, char*> memory_buffers_;
vector<string> paths_;
};
diff --git a/src/processor/source_line_resolver_base.cc b/src/processor/source_line_resolver_base.cc
index 6eff1f99..5c0b6cd7 100644
--- a/src/processor/source_line_resolver_base.cc
+++ b/src/processor/source_line_resolver_base.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2010 Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -42,16 +41,16 @@
#include <utility>
#include "google_breakpad/processor/source_line_resolver_base.h"
-#include "processor/source_line_resolver_base_types.h"
+#include "processor/logging.h"
#include "processor/module_factory.h"
+#include "processor/source_line_resolver_base_types.h"
-using std::map;
using std::make_pair;
namespace google_breakpad {
SourceLineResolverBase::SourceLineResolverBase(
- ModuleFactory *module_factory)
+ ModuleFactory* module_factory)
: modules_(new ModuleMap),
corrupt_modules_(new ModuleSet),
memory_buffers_(new MemoryMap),
@@ -85,9 +84,9 @@ SourceLineResolverBase::~SourceLineResolverBase() {
module_factory_ = NULL;
}
-bool SourceLineResolverBase::ReadSymbolFile(const string &map_file,
- char **symbol_data,
- size_t *symbol_data_size) {
+bool SourceLineResolverBase::ReadSymbolFile(const string& map_file,
+ char** symbol_data,
+ size_t* symbol_data_size) {
if (symbol_data == NULL || symbol_data_size == NULL) {
BPLOG(ERROR) << "Could not Read file into Null memory pointer";
return false;
@@ -117,7 +116,7 @@ bool SourceLineResolverBase::ReadSymbolFile(const string &map_file,
BPLOG(INFO) << "Opening " << map_file;
- FILE *f = fopen(map_file.c_str(), "rt");
+ FILE* f = fopen(map_file.c_str(), "rt");
if (!f) {
string error_string;
error_code = ErrnoString(&error_string);
@@ -148,8 +147,8 @@ bool SourceLineResolverBase::ReadSymbolFile(const string &map_file,
return true;
}
-bool SourceLineResolverBase::LoadModule(const CodeModule *module,
- const string &map_file) {
+bool SourceLineResolverBase::LoadModule(const CodeModule* module,
+ const string& map_file) {
if (module == NULL)
return false;
@@ -163,12 +162,14 @@ bool SourceLineResolverBase::LoadModule(const CodeModule *module,
BPLOG(INFO) << "Loading symbols for module " << module->code_file()
<< " from " << map_file;
- char *memory_buffer;
+ char* memory_buffer;
size_t memory_buffer_size;
if (!ReadSymbolFile(map_file, &memory_buffer, &memory_buffer_size))
return false;
- BPLOG(INFO) << "Read symbol file " << map_file << " succeeded";
+ BPLOG(INFO) << "Read symbol file " << map_file << " succeeded. "
+ << "module = " << module->code_file()
+ << ", memory_buffer_size = " << memory_buffer_size;
bool load_result = LoadModuleUsingMemoryBuffer(module, memory_buffer,
memory_buffer_size);
@@ -184,7 +185,10 @@ bool SourceLineResolverBase::LoadModule(const CodeModule *module,
}
bool SourceLineResolverBase::LoadModuleUsingMapBuffer(
- const CodeModule *module, const string &map_buffer) {
+ const CodeModule* module, const string& map_buffer) {
+ BPLOG(INFO) << "SourceLineResolverBase::LoadModuleUsingMapBuffer(module = "
+ << module->code_file()
+ << ", map_buffer.size() = " << map_buffer.size() << ")";
if (module == NULL)
return false;
@@ -196,7 +200,7 @@ bool SourceLineResolverBase::LoadModuleUsingMapBuffer(
}
size_t memory_buffer_size = map_buffer.size() + 1;
- char *memory_buffer = new char[memory_buffer_size];
+ char* memory_buffer = new char[memory_buffer_size];
if (memory_buffer == NULL) {
BPLOG(ERROR) << "Could not allocate memory for " << module->code_file();
return false;
@@ -220,8 +224,8 @@ bool SourceLineResolverBase::LoadModuleUsingMapBuffer(
}
bool SourceLineResolverBase::LoadModuleUsingMemoryBuffer(
- const CodeModule *module,
- char *memory_buffer,
+ const CodeModule* module,
+ char* memory_buffer,
size_t memory_buffer_size) {
if (!module)
return false;
@@ -234,9 +238,9 @@ bool SourceLineResolverBase::LoadModuleUsingMemoryBuffer(
}
BPLOG(INFO) << "Loading symbols for module " << module->code_file()
- << " from memory buffer";
+ << " from memory buffer, size: " << memory_buffer_size;
- Module *basic_module = module_factory_->CreateModule(module->code_file());
+ Module* basic_module = module_factory_->CreateModule(module->code_file());
// Ownership of memory is NOT transfered to Module::LoadMapFromMemory().
if (!basic_module->LoadMapFromMemory(memory_buffer, memory_buffer_size)) {
@@ -259,13 +263,13 @@ bool SourceLineResolverBase::ShouldDeleteMemoryBufferAfterLoadModule() {
return true;
}
-void SourceLineResolverBase::UnloadModule(const CodeModule *code_module) {
+void SourceLineResolverBase::UnloadModule(const CodeModule* code_module) {
if (!code_module)
return;
ModuleMap::iterator mod_iter = modules_->find(code_module->code_file());
if (mod_iter != modules_->end()) {
- Module *symbol_module = mod_iter->second;
+ Module* symbol_module = mod_iter->second;
delete symbol_module;
corrupt_modules_->erase(mod_iter->first);
modules_->erase(mod_iter);
@@ -283,29 +287,31 @@ void SourceLineResolverBase::UnloadModule(const CodeModule *code_module) {
}
}
-bool SourceLineResolverBase::HasModule(const CodeModule *module) {
+bool SourceLineResolverBase::HasModule(const CodeModule* module) {
if (!module)
return false;
return modules_->find(module->code_file()) != modules_->end();
}
-bool SourceLineResolverBase::IsModuleCorrupt(const CodeModule *module) {
+bool SourceLineResolverBase::IsModuleCorrupt(const CodeModule* module) {
if (!module)
return false;
return corrupt_modules_->find(module->code_file()) != corrupt_modules_->end();
}
-void SourceLineResolverBase::FillSourceLineInfo(StackFrame *frame) {
+void SourceLineResolverBase::FillSourceLineInfo(
+ StackFrame* frame,
+ std::deque<std::unique_ptr<StackFrame>>* inlined_frames) {
if (frame->module) {
ModuleMap::const_iterator it = modules_->find(frame->module->code_file());
if (it != modules_->end()) {
- it->second->LookupAddress(frame);
+ it->second->LookupAddress(frame, inlined_frames);
}
}
}
-WindowsFrameInfo *SourceLineResolverBase::FindWindowsFrameInfo(
- const StackFrame *frame) {
+WindowsFrameInfo* SourceLineResolverBase::FindWindowsFrameInfo(
+ const StackFrame* frame) {
if (frame->module) {
ModuleMap::const_iterator it = modules_->find(frame->module->code_file());
if (it != modules_->end()) {
@@ -315,8 +321,8 @@ WindowsFrameInfo *SourceLineResolverBase::FindWindowsFrameInfo(
return NULL;
}
-CFIFrameInfo *SourceLineResolverBase::FindCFIFrameInfo(
- const StackFrame *frame) {
+CFIFrameInfo* SourceLineResolverBase::FindCFIFrameInfo(
+ const StackFrame* frame) {
if (frame->module) {
ModuleMap::const_iterator it = modules_->find(frame->module->code_file());
if (it != modules_->end()) {
@@ -327,12 +333,12 @@ CFIFrameInfo *SourceLineResolverBase::FindCFIFrameInfo(
}
bool SourceLineResolverBase::CompareString::operator()(
- const string &s1, const string &s2) const {
+ const string& s1, const string& s2) const {
return strcmp(s1.c_str(), s2.c_str()) < 0;
}
bool SourceLineResolverBase::Module::ParseCFIRuleSet(
- const string &rule_set, CFIFrameInfo *frame_info) const {
+ const string& rule_set, CFIFrameInfo* frame_info) const {
CFIFrameInfoParseHandler handler(frame_info);
CFIRuleParser parser(&handler);
return parser.Parse(rule_set);
diff --git a/src/processor/source_line_resolver_base_types.h b/src/processor/source_line_resolver_base_types.h
index ca744e00..4b3b366c 100644
--- a/src/processor/source_line_resolver_base_types.h
+++ b/src/processor/source_line_resolver_base_types.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2010 Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -40,13 +39,17 @@
#include <stdio.h>
+#include <deque>
#include <map>
+#include <memory>
#include <string>
#include "google_breakpad/common/breakpad_types.h"
#include "google_breakpad/processor/source_line_resolver_base.h"
#include "google_breakpad/processor/stack_frame.h"
#include "processor/cfi_frame_info.h"
+#include "processor/linked_ptr.h"
+#include "processor/range_map.h"
#include "processor/windows_frame_info.h"
#ifndef PROCESSOR_SOURCE_LINE_RESOLVER_BASE_TYPES_H__
@@ -56,14 +59,51 @@ namespace google_breakpad {
class SourceLineResolverBase::AutoFileCloser {
public:
- explicit AutoFileCloser(FILE *file) : file_(file) {}
+ explicit AutoFileCloser(FILE* file) : file_(file) {}
~AutoFileCloser() {
if (file_)
fclose(file_);
}
private:
- FILE *file_;
+ FILE* file_;
+};
+
+struct SourceLineResolverBase::InlineOrigin {
+ InlineOrigin() {}
+ InlineOrigin(bool has_file_id, int32_t source_file_id, const string& name)
+ : has_file_id(has_file_id),
+ source_file_id(source_file_id),
+ name(name) {}
+ // If it's old format, source file id is set, otherwise not useful.
+ bool has_file_id;
+ int32_t source_file_id;
+ string name;
+};
+
+struct SourceLineResolverBase::Inline {
+ // A vector of (address, size) pair for a INLINE record.
+ using InlineRanges = std::vector<std::pair<MemAddr, MemAddr>>;
+ Inline() {}
+ Inline(bool has_call_site_file_id,
+ int32_t inline_nest_level,
+ int32_t call_site_line,
+ int32_t call_site_file_id,
+ int32_t origin_id,
+ InlineRanges inline_ranges)
+ : has_call_site_file_id(has_call_site_file_id),
+ inline_nest_level(inline_nest_level),
+ call_site_line(call_site_line),
+ call_site_file_id(call_site_file_id),
+ origin_id(origin_id),
+ inline_ranges(inline_ranges) {}
+ // If it's new format, call site file id is set, otherwise not useful.
+ bool has_call_site_file_id;
+ int32_t inline_nest_level;
+ int32_t call_site_line;
+ int32_t call_site_file_id;
+ int32_t origin_id;
+ InlineRanges inline_ranges;
};
struct SourceLineResolverBase::Line {
@@ -82,7 +122,7 @@ struct SourceLineResolverBase::Line {
struct SourceLineResolverBase::Function {
Function() { }
- Function(const string &function_name,
+ Function(const string& function_name,
MemAddr function_address,
MemAddr code_size,
int set_parameter_size,
@@ -133,7 +173,7 @@ class SourceLineResolverBase::Module {
// The passed in |memory buffer| is of size |memory_buffer_size|. If it is
// not null terminated, LoadMapFromMemory will null terminate it by modifying
// the passed in buffer.
- virtual bool LoadMapFromMemory(char *memory_buffer,
+ virtual bool LoadMapFromMemory(char* memory_buffer,
size_t memory_buffer_size) = 0;
// Tells whether the loaded symbol data is corrupt. Return value is
@@ -142,24 +182,26 @@ class SourceLineResolverBase::Module {
// Looks up the given relative address, and fills the StackFrame struct
// with the result.
- virtual void LookupAddress(StackFrame *frame) const = 0;
+ virtual void LookupAddress(
+ StackFrame* frame,
+ std::deque<std::unique_ptr<StackFrame>>* inlined_frames) const = 0;
// If Windows stack walking information is available covering ADDRESS,
// return a WindowsFrameInfo structure describing it. If the information
// is not available, returns NULL. A NULL return value does not indicate
// an error. The caller takes ownership of any returned WindowsFrameInfo
// object.
- virtual WindowsFrameInfo *
- FindWindowsFrameInfo(const StackFrame *frame) const = 0;
+ virtual WindowsFrameInfo*
+ FindWindowsFrameInfo(const StackFrame* frame) const = 0;
// If CFI stack walking information is available covering ADDRESS,
// return a CFIFrameInfo structure describing it. If the information
// is not available, return NULL. The caller takes ownership of any
// returned CFIFrameInfo object.
- virtual CFIFrameInfo *FindCFIFrameInfo(const StackFrame *frame) const = 0;
+ virtual CFIFrameInfo* FindCFIFrameInfo(const StackFrame* frame) const = 0;
protected:
- virtual bool ParseCFIRuleSet(const string &rule_set,
- CFIFrameInfo *frame_info) const;
+ virtual bool ParseCFIRuleSet(const string& rule_set,
+ CFIFrameInfo* frame_info) const;
};
} // namespace google_breakpad
diff --git a/src/processor/stack_frame_cpu.cc b/src/processor/stack_frame_cpu.cc
index 6175dc7f..e31a3198 100644
--- a/src/processor/stack_frame_cpu.cc
+++ b/src/processor/stack_frame_cpu.cc
@@ -1,5 +1,4 @@
-// Copyright 2013 Google Inc.
-// All rights reserved.
+// Copyright 2013 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/processor/stack_frame_symbolizer.cc b/src/processor/stack_frame_symbolizer.cc
index 7a44f243..0d124a02 100644
--- a/src/processor/stack_frame_symbolizer.cc
+++ b/src/processor/stack_frame_symbolizer.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2012 Google Inc.
-// All rights reserved.
+// Copyright 2012 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -57,7 +56,8 @@ StackFrameSymbolizer::SymbolizerResult StackFrameSymbolizer::FillSourceLineInfo(
const CodeModules* modules,
const CodeModules* unloaded_modules,
const SystemInfo* system_info,
- StackFrame* frame) {
+ StackFrame* frame,
+ std::deque<std::unique_ptr<StackFrame>>* inlined_frames) {
assert(frame);
const CodeModule* module = NULL;
@@ -80,7 +80,7 @@ StackFrameSymbolizer::SymbolizerResult StackFrameSymbolizer::FillSourceLineInfo(
// If module is already loaded, go ahead to fill source line info and return.
if (resolver_->HasModule(frame->module)) {
- resolver_->FillSourceLineInfo(frame);
+ resolver_->FillSourceLineInfo(frame, inlined_frames);
return resolver_->IsModuleCorrupt(frame->module) ?
kWarningCorruptSymbols : kNoError;
}
@@ -108,7 +108,7 @@ StackFrameSymbolizer::SymbolizerResult StackFrameSymbolizer::FillSourceLineInfo(
}
if (load_success) {
- resolver_->FillSourceLineInfo(frame);
+ resolver_->FillSourceLineInfo(frame, inlined_frames);
return resolver_->IsModuleCorrupt(frame->module) ?
kWarningCorruptSymbols : kNoError;
} else {
diff --git a/src/processor/stackwalk_common.cc b/src/processor/stackwalk_common.cc
index 704039f3..a1b6364d 100644
--- a/src/processor/stackwalk_common.cc
+++ b/src/processor/stackwalk_common.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2010 Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -57,6 +56,7 @@ namespace google_breakpad {
namespace {
using std::vector;
+using std::unique_ptr;
// Separator character for machine readable output.
static const char kOutputSeparator = '|';
@@ -69,7 +69,7 @@ static const char kOutputSeparator = '|';
// of registers is completely printed, regardless of the number of calls
// to PrintRegister.
static const int kMaxWidth = 80; // optimize for an 80-column terminal
-static int PrintRegister(const char *name, uint32_t value, int start_col) {
+static int PrintRegister(const char* name, uint32_t value, int start_col) {
char buffer[64];
snprintf(buffer, sizeof(buffer), " %5s = 0x%08x", name, value);
@@ -83,7 +83,7 @@ static int PrintRegister(const char *name, uint32_t value, int start_col) {
}
// PrintRegister64 does the same thing, but for 64-bit registers.
-static int PrintRegister64(const char *name, uint64_t value, int start_col) {
+static int PrintRegister64(const char* name, uint64_t value, int start_col) {
char buffer[64];
snprintf(buffer, sizeof(buffer), " %5s = 0x%016" PRIx64 , name, value);
@@ -98,7 +98,7 @@ static int PrintRegister64(const char *name, uint64_t value, int start_col) {
// StripSeparator takes a string |original| and returns a copy
// of the string with all occurences of |kOutputSeparator| removed.
-static string StripSeparator(const string &original) {
+static string StripSeparator(const string& original) {
string result = original;
string::size_type position = 0;
while ((position = result.find(kOutputSeparator, position)) != string::npos) {
@@ -112,20 +112,20 @@ static string StripSeparator(const string &original) {
}
// PrintStackContents prints the stack contents of the current frame to stdout.
-static void PrintStackContents(const string &indent,
- const StackFrame *frame,
- const StackFrame *prev_frame,
- const string &cpu,
- const MemoryRegion *memory,
+static void PrintStackContents(const string& indent,
+ const StackFrame* frame,
+ const StackFrame* prev_frame,
+ const string& cpu,
+ const MemoryRegion* memory,
const CodeModules* modules,
- SourceLineResolverInterface *resolver) {
+ SourceLineResolverInterface* resolver) {
// Find stack range.
int word_length = 0;
uint64_t stack_begin = 0, stack_end = 0;
if (cpu == "x86") {
word_length = 4;
- const StackFrameX86 *frame_x86 = static_cast<const StackFrameX86*>(frame);
- const StackFrameX86 *prev_frame_x86 =
+ const StackFrameX86* frame_x86 = static_cast<const StackFrameX86*>(frame);
+ const StackFrameX86* prev_frame_x86 =
static_cast<const StackFrameX86*>(prev_frame);
if ((frame_x86->context_validity & StackFrameX86::CONTEXT_VALID_ESP) &&
(prev_frame_x86->context_validity & StackFrameX86::CONTEXT_VALID_ESP)) {
@@ -134,9 +134,9 @@ static void PrintStackContents(const string &indent,
}
} else if (cpu == "amd64") {
word_length = 8;
- const StackFrameAMD64 *frame_amd64 =
+ const StackFrameAMD64* frame_amd64 =
static_cast<const StackFrameAMD64*>(frame);
- const StackFrameAMD64 *prev_frame_amd64 =
+ const StackFrameAMD64* prev_frame_amd64 =
static_cast<const StackFrameAMD64*>(prev_frame);
if ((frame_amd64->context_validity & StackFrameAMD64::CONTEXT_VALID_RSP) &&
(prev_frame_amd64->context_validity &
@@ -146,26 +146,54 @@ static void PrintStackContents(const string &indent,
}
} else if (cpu == "arm") {
word_length = 4;
- const StackFrameARM *frame_arm = static_cast<const StackFrameARM*>(frame);
- const StackFrameARM *prev_frame_arm =
+ const StackFrameARM* frame_arm = static_cast<const StackFrameARM*>(frame);
+ const StackFrameARM* prev_frame_arm =
static_cast<const StackFrameARM*>(prev_frame);
- if ((frame_arm->context_validity & StackFrameARM::CONTEXT_VALID_SP) &&
+ if ((frame_arm->context_validity &
+ StackFrameARM::CONTEXT_VALID_SP) &&
(prev_frame_arm->context_validity & StackFrameARM::CONTEXT_VALID_SP)) {
stack_begin = frame_arm->context.iregs[13];
stack_end = prev_frame_arm->context.iregs[13];
}
} else if (cpu == "arm64") {
word_length = 8;
- const StackFrameARM64 *frame_arm64 =
+ const StackFrameARM64* frame_arm64 =
static_cast<const StackFrameARM64*>(frame);
- const StackFrameARM64 *prev_frame_arm64 =
+ const StackFrameARM64* prev_frame_arm64 =
static_cast<const StackFrameARM64*>(prev_frame);
- if ((frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_SP) &&
+ if ((frame_arm64->context_validity &
+ StackFrameARM64::CONTEXT_VALID_SP) &&
(prev_frame_arm64->context_validity &
StackFrameARM64::CONTEXT_VALID_SP)) {
stack_begin = frame_arm64->context.iregs[31];
stack_end = prev_frame_arm64->context.iregs[31];
}
+ } else if (cpu == "riscv") {
+ word_length = 4;
+ const StackFrameRISCV* frame_riscv =
+ static_cast<const StackFrameRISCV*>(frame);
+ const StackFrameRISCV* prev_frame_riscv =
+ static_cast<const StackFrameRISCV*>(prev_frame);
+ if ((frame_riscv->context_validity &
+ StackFrameRISCV::CONTEXT_VALID_SP) &&
+ (prev_frame_riscv->context_validity &
+ StackFrameRISCV::CONTEXT_VALID_SP)) {
+ stack_begin = frame_riscv->context.sp;
+ stack_end = prev_frame_riscv->context.sp;
+ }
+ } else if (cpu == "riscv64") {
+ word_length = 8;
+ const StackFrameRISCV64* frame_riscv64 =
+ static_cast<const StackFrameRISCV64*>(frame);
+ const StackFrameRISCV64* prev_frame_riscv64 =
+ static_cast<const StackFrameRISCV64*>(prev_frame);
+ if ((frame_riscv64->context_validity &
+ StackFrameRISCV64::CONTEXT_VALID_SP) &&
+ (prev_frame_riscv64->context_validity &
+ StackFrameRISCV64::CONTEXT_VALID_SP)) {
+ stack_begin = frame_riscv64->context.sp;
+ stack_end = prev_frame_riscv64->context.sp;
+ }
}
if (!word_length || !stack_begin || !stack_end)
return;
@@ -217,25 +245,30 @@ static void PrintStackContents(const string &indent,
modules->GetModuleForAddress(pointee_frame.instruction);
// Try to look up the function name.
+ std::deque<unique_ptr<StackFrame>> inlined_frames;
if (pointee_frame.module)
- resolver->FillSourceLineInfo(&pointee_frame);
+ resolver->FillSourceLineInfo(&pointee_frame, &inlined_frames);
// Print function name.
- if (!pointee_frame.function_name.empty()) {
- if (word_length == 4) {
- printf("%s *(0x%08x) = 0x%08x", indent.c_str(),
- static_cast<uint32_t>(address),
- static_cast<uint32_t>(pointee_frame.instruction));
- } else {
- printf("%s *(0x%016" PRIx64 ") = 0x%016" PRIx64,
- indent.c_str(), address, pointee_frame.instruction);
+ auto print_function_name = [&](StackFrame* frame) {
+ if (!frame->function_name.empty()) {
+ if (word_length == 4) {
+ printf("%s *(0x%08x) = 0x%08x", indent.c_str(),
+ static_cast<uint32_t>(address),
+ static_cast<uint32_t>(frame->instruction));
+ } else {
+ printf("%s *(0x%016" PRIx64 ") = 0x%016" PRIx64, indent.c_str(),
+ address, frame->instruction);
+ }
+ printf(
+ " <%s> [%s : %d + 0x%" PRIx64 "]\n", frame->function_name.c_str(),
+ PathnameStripper::File(frame->source_file_name).c_str(),
+ frame->source_line, frame->instruction - frame->source_line_base);
}
- printf(" <%s> [%s : %d + 0x%" PRIx64 "]\n",
- pointee_frame.function_name.c_str(),
- PathnameStripper::File(pointee_frame.source_file_name).c_str(),
- pointee_frame.source_line,
- pointee_frame.instruction - pointee_frame.source_line_base);
- }
+ };
+ print_function_name(&pointee_frame);
+ for (unique_ptr<StackFrame> &frame : inlined_frames)
+ print_function_name(frame.get());
}
printf("\n");
}
@@ -249,8 +282,8 @@ static void PrintStackContents(const string &indent,
//
// If |cpu| is a recognized CPU name, relevant register state for each stack
// frame printed is also output, if available.
-static void PrintStack(const CallStack *stack,
- const string &cpu,
+static void PrintStack(const CallStack* stack,
+ const string& cpu,
bool output_stack_contents,
const MemoryRegion* memory,
const CodeModules* modules,
@@ -260,7 +293,7 @@ static void PrintStack(const CallStack *stack,
printf(" <no frames>\n");
}
for (int frame_index = 0; frame_index < frame_count; ++frame_index) {
- const StackFrame *frame = stack->frames()->at(frame_index);
+ const StackFrame* frame = stack->frames()->at(frame_index);
printf("%2d ", frame_index);
uint64_t instruction_address = frame->ReturnAddress();
@@ -287,321 +320,615 @@ static void PrintStack(const CallStack *stack,
}
printf("\n ");
- int sequence = 0;
- if (cpu == "x86") {
- const StackFrameX86 *frame_x86 =
- reinterpret_cast<const StackFrameX86*>(frame);
-
- if (frame_x86->context_validity & StackFrameX86::CONTEXT_VALID_EIP)
- sequence = PrintRegister("eip", frame_x86->context.eip, sequence);
- if (frame_x86->context_validity & StackFrameX86::CONTEXT_VALID_ESP)
- sequence = PrintRegister("esp", frame_x86->context.esp, sequence);
- if (frame_x86->context_validity & StackFrameX86::CONTEXT_VALID_EBP)
- sequence = PrintRegister("ebp", frame_x86->context.ebp, sequence);
- if (frame_x86->context_validity & StackFrameX86::CONTEXT_VALID_EBX)
- sequence = PrintRegister("ebx", frame_x86->context.ebx, sequence);
- if (frame_x86->context_validity & StackFrameX86::CONTEXT_VALID_ESI)
- sequence = PrintRegister("esi", frame_x86->context.esi, sequence);
- if (frame_x86->context_validity & StackFrameX86::CONTEXT_VALID_EDI)
- sequence = PrintRegister("edi", frame_x86->context.edi, sequence);
- if (frame_x86->context_validity == StackFrameX86::CONTEXT_VALID_ALL) {
- sequence = PrintRegister("eax", frame_x86->context.eax, sequence);
- sequence = PrintRegister("ecx", frame_x86->context.ecx, sequence);
- sequence = PrintRegister("edx", frame_x86->context.edx, sequence);
- sequence = PrintRegister("efl", frame_x86->context.eflags, sequence);
- }
- } else if (cpu == "ppc") {
- const StackFramePPC *frame_ppc =
- reinterpret_cast<const StackFramePPC*>(frame);
-
- if (frame_ppc->context_validity & StackFramePPC::CONTEXT_VALID_SRR0)
- sequence = PrintRegister("srr0", frame_ppc->context.srr0, sequence);
- if (frame_ppc->context_validity & StackFramePPC::CONTEXT_VALID_GPR1)
- sequence = PrintRegister("r1", frame_ppc->context.gpr[1], sequence);
- } else if (cpu == "amd64") {
- const StackFrameAMD64 *frame_amd64 =
- reinterpret_cast<const StackFrameAMD64*>(frame);
-
- if (frame_amd64->context_validity & StackFrameAMD64::CONTEXT_VALID_RAX)
- sequence = PrintRegister64("rax", frame_amd64->context.rax, sequence);
- if (frame_amd64->context_validity & StackFrameAMD64::CONTEXT_VALID_RDX)
- sequence = PrintRegister64("rdx", frame_amd64->context.rdx, sequence);
- if (frame_amd64->context_validity & StackFrameAMD64::CONTEXT_VALID_RCX)
- sequence = PrintRegister64("rcx", frame_amd64->context.rcx, sequence);
- if (frame_amd64->context_validity & StackFrameAMD64::CONTEXT_VALID_RBX)
- sequence = PrintRegister64("rbx", frame_amd64->context.rbx, sequence);
- if (frame_amd64->context_validity & StackFrameAMD64::CONTEXT_VALID_RSI)
- sequence = PrintRegister64("rsi", frame_amd64->context.rsi, sequence);
- if (frame_amd64->context_validity & StackFrameAMD64::CONTEXT_VALID_RDI)
- sequence = PrintRegister64("rdi", frame_amd64->context.rdi, sequence);
- if (frame_amd64->context_validity & StackFrameAMD64::CONTEXT_VALID_RBP)
- sequence = PrintRegister64("rbp", frame_amd64->context.rbp, sequence);
- if (frame_amd64->context_validity & StackFrameAMD64::CONTEXT_VALID_RSP)
- sequence = PrintRegister64("rsp", frame_amd64->context.rsp, sequence);
- if (frame_amd64->context_validity & StackFrameAMD64::CONTEXT_VALID_R8)
- sequence = PrintRegister64("r8", frame_amd64->context.r8, sequence);
- if (frame_amd64->context_validity & StackFrameAMD64::CONTEXT_VALID_R9)
- sequence = PrintRegister64("r9", frame_amd64->context.r9, sequence);
- if (frame_amd64->context_validity & StackFrameAMD64::CONTEXT_VALID_R10)
- sequence = PrintRegister64("r10", frame_amd64->context.r10, sequence);
- if (frame_amd64->context_validity & StackFrameAMD64::CONTEXT_VALID_R11)
- sequence = PrintRegister64("r11", frame_amd64->context.r11, sequence);
- if (frame_amd64->context_validity & StackFrameAMD64::CONTEXT_VALID_R12)
- sequence = PrintRegister64("r12", frame_amd64->context.r12, sequence);
- if (frame_amd64->context_validity & StackFrameAMD64::CONTEXT_VALID_R13)
- sequence = PrintRegister64("r13", frame_amd64->context.r13, sequence);
- if (frame_amd64->context_validity & StackFrameAMD64::CONTEXT_VALID_R14)
- sequence = PrintRegister64("r14", frame_amd64->context.r14, sequence);
- if (frame_amd64->context_validity & StackFrameAMD64::CONTEXT_VALID_R15)
- sequence = PrintRegister64("r15", frame_amd64->context.r15, sequence);
- if (frame_amd64->context_validity & StackFrameAMD64::CONTEXT_VALID_RIP)
- sequence = PrintRegister64("rip", frame_amd64->context.rip, sequence);
- } else if (cpu == "sparc") {
- const StackFrameSPARC *frame_sparc =
- reinterpret_cast<const StackFrameSPARC*>(frame);
-
- if (frame_sparc->context_validity & StackFrameSPARC::CONTEXT_VALID_SP)
- sequence = PrintRegister("sp", frame_sparc->context.g_r[14], sequence);
- if (frame_sparc->context_validity & StackFrameSPARC::CONTEXT_VALID_FP)
- sequence = PrintRegister("fp", frame_sparc->context.g_r[30], sequence);
- if (frame_sparc->context_validity & StackFrameSPARC::CONTEXT_VALID_PC)
- sequence = PrintRegister("pc", frame_sparc->context.pc, sequence);
- } else if (cpu == "arm") {
- const StackFrameARM *frame_arm =
- reinterpret_cast<const StackFrameARM*>(frame);
-
- // Argument registers (caller-saves), which will likely only be valid
- // for the youngest frame.
- if (frame_arm->context_validity & StackFrameARM::CONTEXT_VALID_R0)
- sequence = PrintRegister("r0", frame_arm->context.iregs[0], sequence);
- if (frame_arm->context_validity & StackFrameARM::CONTEXT_VALID_R1)
- sequence = PrintRegister("r1", frame_arm->context.iregs[1], sequence);
- if (frame_arm->context_validity & StackFrameARM::CONTEXT_VALID_R2)
- sequence = PrintRegister("r2", frame_arm->context.iregs[2], sequence);
- if (frame_arm->context_validity & StackFrameARM::CONTEXT_VALID_R3)
- sequence = PrintRegister("r3", frame_arm->context.iregs[3], sequence);
-
- // General-purpose callee-saves registers.
- if (frame_arm->context_validity & StackFrameARM::CONTEXT_VALID_R4)
- sequence = PrintRegister("r4", frame_arm->context.iregs[4], sequence);
- if (frame_arm->context_validity & StackFrameARM::CONTEXT_VALID_R5)
- sequence = PrintRegister("r5", frame_arm->context.iregs[5], sequence);
- if (frame_arm->context_validity & StackFrameARM::CONTEXT_VALID_R6)
- sequence = PrintRegister("r6", frame_arm->context.iregs[6], sequence);
- if (frame_arm->context_validity & StackFrameARM::CONTEXT_VALID_R7)
- sequence = PrintRegister("r7", frame_arm->context.iregs[7], sequence);
- if (frame_arm->context_validity & StackFrameARM::CONTEXT_VALID_R8)
- sequence = PrintRegister("r8", frame_arm->context.iregs[8], sequence);
- if (frame_arm->context_validity & StackFrameARM::CONTEXT_VALID_R9)
- sequence = PrintRegister("r9", frame_arm->context.iregs[9], sequence);
- if (frame_arm->context_validity & StackFrameARM::CONTEXT_VALID_R10)
- sequence = PrintRegister("r10", frame_arm->context.iregs[10], sequence);
- if (frame_arm->context_validity & StackFrameARM::CONTEXT_VALID_R12)
- sequence = PrintRegister("r12", frame_arm->context.iregs[12], sequence);
-
- // Registers with a dedicated or conventional purpose.
- if (frame_arm->context_validity & StackFrameARM::CONTEXT_VALID_FP)
- sequence = PrintRegister("fp", frame_arm->context.iregs[11], sequence);
- if (frame_arm->context_validity & StackFrameARM::CONTEXT_VALID_SP)
- sequence = PrintRegister("sp", frame_arm->context.iregs[13], sequence);
- if (frame_arm->context_validity & StackFrameARM::CONTEXT_VALID_LR)
- sequence = PrintRegister("lr", frame_arm->context.iregs[14], sequence);
- if (frame_arm->context_validity & StackFrameARM::CONTEXT_VALID_PC)
- sequence = PrintRegister("pc", frame_arm->context.iregs[15], sequence);
- } else if (cpu == "arm64") {
- const StackFrameARM64 *frame_arm64 =
- reinterpret_cast<const StackFrameARM64*>(frame);
-
- if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X0) {
- sequence =
- PrintRegister64("x0", frame_arm64->context.iregs[0], sequence);
- }
- if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X1) {
- sequence =
- PrintRegister64("x1", frame_arm64->context.iregs[1], sequence);
- }
- if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X2) {
- sequence =
- PrintRegister64("x2", frame_arm64->context.iregs[2], sequence);
- }
- if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X3) {
- sequence =
- PrintRegister64("x3", frame_arm64->context.iregs[3], sequence);
- }
- if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X4) {
- sequence =
- PrintRegister64("x4", frame_arm64->context.iregs[4], sequence);
- }
- if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X5) {
- sequence =
- PrintRegister64("x5", frame_arm64->context.iregs[5], sequence);
- }
- if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X6) {
- sequence =
- PrintRegister64("x6", frame_arm64->context.iregs[6], sequence);
- }
- if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X7) {
- sequence =
- PrintRegister64("x7", frame_arm64->context.iregs[7], sequence);
- }
- if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X8) {
- sequence =
- PrintRegister64("x8", frame_arm64->context.iregs[8], sequence);
- }
- if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X9) {
- sequence =
- PrintRegister64("x9", frame_arm64->context.iregs[9], sequence);
- }
- if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X10) {
- sequence =
- PrintRegister64("x10", frame_arm64->context.iregs[10], sequence);
- }
- if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X11) {
- sequence =
- PrintRegister64("x11", frame_arm64->context.iregs[11], sequence);
- }
- if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X12) {
- sequence =
- PrintRegister64("x12", frame_arm64->context.iregs[12], sequence);
- }
- if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X13) {
- sequence =
- PrintRegister64("x13", frame_arm64->context.iregs[13], sequence);
- }
- if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X14) {
- sequence =
- PrintRegister64("x14", frame_arm64->context.iregs[14], sequence);
- }
- if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X15) {
- sequence =
- PrintRegister64("x15", frame_arm64->context.iregs[15], sequence);
- }
- if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X16) {
- sequence =
- PrintRegister64("x16", frame_arm64->context.iregs[16], sequence);
- }
- if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X17) {
- sequence =
- PrintRegister64("x17", frame_arm64->context.iregs[17], sequence);
- }
- if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X18) {
- sequence =
- PrintRegister64("x18", frame_arm64->context.iregs[18], sequence);
- }
- if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X19) {
- sequence =
- PrintRegister64("x19", frame_arm64->context.iregs[19], sequence);
- }
- if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X20) {
- sequence =
- PrintRegister64("x20", frame_arm64->context.iregs[20], sequence);
- }
- if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X21) {
- sequence =
- PrintRegister64("x21", frame_arm64->context.iregs[21], sequence);
- }
- if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X22) {
- sequence =
- PrintRegister64("x22", frame_arm64->context.iregs[22], sequence);
- }
- if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X23) {
- sequence =
- PrintRegister64("x23", frame_arm64->context.iregs[23], sequence);
- }
- if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X24) {
- sequence =
- PrintRegister64("x24", frame_arm64->context.iregs[24], sequence);
- }
- if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X25) {
- sequence =
- PrintRegister64("x25", frame_arm64->context.iregs[25], sequence);
- }
- if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X26) {
- sequence =
- PrintRegister64("x26", frame_arm64->context.iregs[26], sequence);
- }
- if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X27) {
- sequence =
- PrintRegister64("x27", frame_arm64->context.iregs[27], sequence);
- }
- if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X28) {
- sequence =
- PrintRegister64("x28", frame_arm64->context.iregs[28], sequence);
- }
+ // Inlined frames don't have registers info.
+ if (frame->trust != StackFrameAMD64::FRAME_TRUST_INLINE) {
+ int sequence = 0;
+ if (cpu == "x86") {
+ const StackFrameX86* frame_x86 =
+ reinterpret_cast<const StackFrameX86*>(frame);
+
+ if (frame_x86->context_validity & StackFrameX86::CONTEXT_VALID_EIP)
+ sequence = PrintRegister("eip", frame_x86->context.eip, sequence);
+ if (frame_x86->context_validity & StackFrameX86::CONTEXT_VALID_ESP)
+ sequence = PrintRegister("esp", frame_x86->context.esp, sequence);
+ if (frame_x86->context_validity & StackFrameX86::CONTEXT_VALID_EBP)
+ sequence = PrintRegister("ebp", frame_x86->context.ebp, sequence);
+ if (frame_x86->context_validity & StackFrameX86::CONTEXT_VALID_EBX)
+ sequence = PrintRegister("ebx", frame_x86->context.ebx, sequence);
+ if (frame_x86->context_validity & StackFrameX86::CONTEXT_VALID_ESI)
+ sequence = PrintRegister("esi", frame_x86->context.esi, sequence);
+ if (frame_x86->context_validity & StackFrameX86::CONTEXT_VALID_EDI)
+ sequence = PrintRegister("edi", frame_x86->context.edi, sequence);
+ if (frame_x86->context_validity == StackFrameX86::CONTEXT_VALID_ALL) {
+ sequence = PrintRegister("eax", frame_x86->context.eax, sequence);
+ sequence = PrintRegister("ecx", frame_x86->context.ecx, sequence);
+ sequence = PrintRegister("edx", frame_x86->context.edx, sequence);
+ sequence = PrintRegister("efl", frame_x86->context.eflags, sequence);
+ }
+ } else if (cpu == "ppc") {
+ const StackFramePPC* frame_ppc =
+ reinterpret_cast<const StackFramePPC*>(frame);
+
+ if (frame_ppc->context_validity & StackFramePPC::CONTEXT_VALID_SRR0)
+ sequence = PrintRegister("srr0", frame_ppc->context.srr0, sequence);
+ if (frame_ppc->context_validity & StackFramePPC::CONTEXT_VALID_GPR1)
+ sequence = PrintRegister("r1", frame_ppc->context.gpr[1], sequence);
+ } else if (cpu == "amd64") {
+ const StackFrameAMD64* frame_amd64 =
+ reinterpret_cast<const StackFrameAMD64*>(frame);
+
+ if (frame_amd64->context_validity & StackFrameAMD64::CONTEXT_VALID_RAX)
+ sequence = PrintRegister64("rax", frame_amd64->context.rax, sequence);
+ if (frame_amd64->context_validity & StackFrameAMD64::CONTEXT_VALID_RDX)
+ sequence = PrintRegister64("rdx", frame_amd64->context.rdx, sequence);
+ if (frame_amd64->context_validity & StackFrameAMD64::CONTEXT_VALID_RCX)
+ sequence = PrintRegister64("rcx", frame_amd64->context.rcx, sequence);
+ if (frame_amd64->context_validity & StackFrameAMD64::CONTEXT_VALID_RBX)
+ sequence = PrintRegister64("rbx", frame_amd64->context.rbx, sequence);
+ if (frame_amd64->context_validity & StackFrameAMD64::CONTEXT_VALID_RSI)
+ sequence = PrintRegister64("rsi", frame_amd64->context.rsi, sequence);
+ if (frame_amd64->context_validity & StackFrameAMD64::CONTEXT_VALID_RDI)
+ sequence = PrintRegister64("rdi", frame_amd64->context.rdi, sequence);
+ if (frame_amd64->context_validity & StackFrameAMD64::CONTEXT_VALID_RBP)
+ sequence = PrintRegister64("rbp", frame_amd64->context.rbp, sequence);
+ if (frame_amd64->context_validity & StackFrameAMD64::CONTEXT_VALID_RSP)
+ sequence = PrintRegister64("rsp", frame_amd64->context.rsp, sequence);
+ if (frame_amd64->context_validity & StackFrameAMD64::CONTEXT_VALID_R8)
+ sequence = PrintRegister64("r8", frame_amd64->context.r8, sequence);
+ if (frame_amd64->context_validity & StackFrameAMD64::CONTEXT_VALID_R9)
+ sequence = PrintRegister64("r9", frame_amd64->context.r9, sequence);
+ if (frame_amd64->context_validity & StackFrameAMD64::CONTEXT_VALID_R10)
+ sequence = PrintRegister64("r10", frame_amd64->context.r10, sequence);
+ if (frame_amd64->context_validity & StackFrameAMD64::CONTEXT_VALID_R11)
+ sequence = PrintRegister64("r11", frame_amd64->context.r11, sequence);
+ if (frame_amd64->context_validity & StackFrameAMD64::CONTEXT_VALID_R12)
+ sequence = PrintRegister64("r12", frame_amd64->context.r12, sequence);
+ if (frame_amd64->context_validity & StackFrameAMD64::CONTEXT_VALID_R13)
+ sequence = PrintRegister64("r13", frame_amd64->context.r13, sequence);
+ if (frame_amd64->context_validity & StackFrameAMD64::CONTEXT_VALID_R14)
+ sequence = PrintRegister64("r14", frame_amd64->context.r14, sequence);
+ if (frame_amd64->context_validity & StackFrameAMD64::CONTEXT_VALID_R15)
+ sequence = PrintRegister64("r15", frame_amd64->context.r15, sequence);
+ if (frame_amd64->context_validity & StackFrameAMD64::CONTEXT_VALID_RIP)
+ sequence = PrintRegister64("rip", frame_amd64->context.rip, sequence);
+ } else if (cpu == "sparc") {
+ const StackFrameSPARC* frame_sparc =
+ reinterpret_cast<const StackFrameSPARC*>(frame);
+
+ if (frame_sparc->context_validity & StackFrameSPARC::CONTEXT_VALID_SP)
+ sequence =
+ PrintRegister("sp", frame_sparc->context.g_r[14], sequence);
+ if (frame_sparc->context_validity & StackFrameSPARC::CONTEXT_VALID_FP)
+ sequence =
+ PrintRegister("fp", frame_sparc->context.g_r[30], sequence);
+ if (frame_sparc->context_validity & StackFrameSPARC::CONTEXT_VALID_PC)
+ sequence = PrintRegister("pc", frame_sparc->context.pc, sequence);
+ } else if (cpu == "arm") {
+ const StackFrameARM* frame_arm =
+ reinterpret_cast<const StackFrameARM*>(frame);
+
+ // Argument registers (caller-saves), which will likely only be valid
+ // for the youngest frame.
+ if (frame_arm->context_validity & StackFrameARM::CONTEXT_VALID_R0)
+ sequence = PrintRegister("r0", frame_arm->context.iregs[0], sequence);
+ if (frame_arm->context_validity & StackFrameARM::CONTEXT_VALID_R1)
+ sequence = PrintRegister("r1", frame_arm->context.iregs[1], sequence);
+ if (frame_arm->context_validity & StackFrameARM::CONTEXT_VALID_R2)
+ sequence = PrintRegister("r2", frame_arm->context.iregs[2], sequence);
+ if (frame_arm->context_validity & StackFrameARM::CONTEXT_VALID_R3)
+ sequence = PrintRegister("r3", frame_arm->context.iregs[3], sequence);
+
+ // General-purpose callee-saves registers.
+ if (frame_arm->context_validity & StackFrameARM::CONTEXT_VALID_R4)
+ sequence = PrintRegister("r4", frame_arm->context.iregs[4], sequence);
+ if (frame_arm->context_validity & StackFrameARM::CONTEXT_VALID_R5)
+ sequence = PrintRegister("r5", frame_arm->context.iregs[5], sequence);
+ if (frame_arm->context_validity & StackFrameARM::CONTEXT_VALID_R6)
+ sequence = PrintRegister("r6", frame_arm->context.iregs[6], sequence);
+ if (frame_arm->context_validity & StackFrameARM::CONTEXT_VALID_R7)
+ sequence = PrintRegister("r7", frame_arm->context.iregs[7], sequence);
+ if (frame_arm->context_validity & StackFrameARM::CONTEXT_VALID_R8)
+ sequence = PrintRegister("r8", frame_arm->context.iregs[8], sequence);
+ if (frame_arm->context_validity & StackFrameARM::CONTEXT_VALID_R9)
+ sequence = PrintRegister("r9", frame_arm->context.iregs[9], sequence);
+ if (frame_arm->context_validity & StackFrameARM::CONTEXT_VALID_R10)
+ sequence =
+ PrintRegister("r10", frame_arm->context.iregs[10], sequence);
+ if (frame_arm->context_validity & StackFrameARM::CONTEXT_VALID_R12)
+ sequence =
+ PrintRegister("r12", frame_arm->context.iregs[12], sequence);
+
+ // Registers with a dedicated or conventional purpose.
+ if (frame_arm->context_validity & StackFrameARM::CONTEXT_VALID_FP)
+ sequence =
+ PrintRegister("fp", frame_arm->context.iregs[11], sequence);
+ if (frame_arm->context_validity & StackFrameARM::CONTEXT_VALID_SP)
+ sequence =
+ PrintRegister("sp", frame_arm->context.iregs[13], sequence);
+ if (frame_arm->context_validity & StackFrameARM::CONTEXT_VALID_LR)
+ sequence =
+ PrintRegister("lr", frame_arm->context.iregs[14], sequence);
+ if (frame_arm->context_validity & StackFrameARM::CONTEXT_VALID_PC)
+ sequence =
+ PrintRegister("pc", frame_arm->context.iregs[15], sequence);
+ } else if (cpu == "arm64") {
+ const StackFrameARM64* frame_arm64 =
+ reinterpret_cast<const StackFrameARM64*>(frame);
+
+ if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X0) {
+ sequence =
+ PrintRegister64("x0", frame_arm64->context.iregs[0], sequence);
+ }
+ if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X1) {
+ sequence =
+ PrintRegister64("x1", frame_arm64->context.iregs[1], sequence);
+ }
+ if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X2) {
+ sequence =
+ PrintRegister64("x2", frame_arm64->context.iregs[2], sequence);
+ }
+ if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X3) {
+ sequence =
+ PrintRegister64("x3", frame_arm64->context.iregs[3], sequence);
+ }
+ if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X4) {
+ sequence =
+ PrintRegister64("x4", frame_arm64->context.iregs[4], sequence);
+ }
+ if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X5) {
+ sequence =
+ PrintRegister64("x5", frame_arm64->context.iregs[5], sequence);
+ }
+ if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X6) {
+ sequence =
+ PrintRegister64("x6", frame_arm64->context.iregs[6], sequence);
+ }
+ if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X7) {
+ sequence =
+ PrintRegister64("x7", frame_arm64->context.iregs[7], sequence);
+ }
+ if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X8) {
+ sequence =
+ PrintRegister64("x8", frame_arm64->context.iregs[8], sequence);
+ }
+ if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X9) {
+ sequence =
+ PrintRegister64("x9", frame_arm64->context.iregs[9], sequence);
+ }
+ if (frame_arm64->context_validity &
+ StackFrameARM64::CONTEXT_VALID_X10) {
+ sequence =
+ PrintRegister64("x10", frame_arm64->context.iregs[10], sequence);
+ }
+ if (frame_arm64->context_validity &
+ StackFrameARM64::CONTEXT_VALID_X11) {
+ sequence =
+ PrintRegister64("x11", frame_arm64->context.iregs[11], sequence);
+ }
+ if (frame_arm64->context_validity &
+ StackFrameARM64::CONTEXT_VALID_X12) {
+ sequence =
+ PrintRegister64("x12", frame_arm64->context.iregs[12], sequence);
+ }
+ if (frame_arm64->context_validity &
+ StackFrameARM64::CONTEXT_VALID_X13) {
+ sequence =
+ PrintRegister64("x13", frame_arm64->context.iregs[13], sequence);
+ }
+ if (frame_arm64->context_validity &
+ StackFrameARM64::CONTEXT_VALID_X14) {
+ sequence =
+ PrintRegister64("x14", frame_arm64->context.iregs[14], sequence);
+ }
+ if (frame_arm64->context_validity &
+ StackFrameARM64::CONTEXT_VALID_X15) {
+ sequence =
+ PrintRegister64("x15", frame_arm64->context.iregs[15], sequence);
+ }
+ if (frame_arm64->context_validity &
+ StackFrameARM64::CONTEXT_VALID_X16) {
+ sequence =
+ PrintRegister64("x16", frame_arm64->context.iregs[16], sequence);
+ }
+ if (frame_arm64->context_validity &
+ StackFrameARM64::CONTEXT_VALID_X17) {
+ sequence =
+ PrintRegister64("x17", frame_arm64->context.iregs[17], sequence);
+ }
+ if (frame_arm64->context_validity &
+ StackFrameARM64::CONTEXT_VALID_X18) {
+ sequence =
+ PrintRegister64("x18", frame_arm64->context.iregs[18], sequence);
+ }
+ if (frame_arm64->context_validity &
+ StackFrameARM64::CONTEXT_VALID_X19) {
+ sequence =
+ PrintRegister64("x19", frame_arm64->context.iregs[19], sequence);
+ }
+ if (frame_arm64->context_validity &
+ StackFrameARM64::CONTEXT_VALID_X20) {
+ sequence =
+ PrintRegister64("x20", frame_arm64->context.iregs[20], sequence);
+ }
+ if (frame_arm64->context_validity &
+ StackFrameARM64::CONTEXT_VALID_X21) {
+ sequence =
+ PrintRegister64("x21", frame_arm64->context.iregs[21], sequence);
+ }
+ if (frame_arm64->context_validity &
+ StackFrameARM64::CONTEXT_VALID_X22) {
+ sequence =
+ PrintRegister64("x22", frame_arm64->context.iregs[22], sequence);
+ }
+ if (frame_arm64->context_validity &
+ StackFrameARM64::CONTEXT_VALID_X23) {
+ sequence =
+ PrintRegister64("x23", frame_arm64->context.iregs[23], sequence);
+ }
+ if (frame_arm64->context_validity &
+ StackFrameARM64::CONTEXT_VALID_X24) {
+ sequence =
+ PrintRegister64("x24", frame_arm64->context.iregs[24], sequence);
+ }
+ if (frame_arm64->context_validity &
+ StackFrameARM64::CONTEXT_VALID_X25) {
+ sequence =
+ PrintRegister64("x25", frame_arm64->context.iregs[25], sequence);
+ }
+ if (frame_arm64->context_validity &
+ StackFrameARM64::CONTEXT_VALID_X26) {
+ sequence =
+ PrintRegister64("x26", frame_arm64->context.iregs[26], sequence);
+ }
+ if (frame_arm64->context_validity &
+ StackFrameARM64::CONTEXT_VALID_X27) {
+ sequence =
+ PrintRegister64("x27", frame_arm64->context.iregs[27], sequence);
+ }
+ if (frame_arm64->context_validity &
+ StackFrameARM64::CONTEXT_VALID_X28) {
+ sequence =
+ PrintRegister64("x28", frame_arm64->context.iregs[28], sequence);
+ }
- // Registers with a dedicated or conventional purpose.
- if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_FP) {
- sequence =
- PrintRegister64("fp", frame_arm64->context.iregs[29], sequence);
- }
- if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_LR) {
- sequence =
- PrintRegister64("lr", frame_arm64->context.iregs[30], sequence);
- }
- if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_SP) {
- sequence =
- PrintRegister64("sp", frame_arm64->context.iregs[31], sequence);
- }
- if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_PC) {
- sequence =
- PrintRegister64("pc", frame_arm64->context.iregs[32], sequence);
+ // Registers with a dedicated or conventional purpose.
+ if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_FP) {
+ sequence =
+ PrintRegister64("fp", frame_arm64->context.iregs[29], sequence);
+ }
+ if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_LR) {
+ sequence =
+ PrintRegister64("lr", frame_arm64->context.iregs[30], sequence);
+ }
+ if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_SP) {
+ sequence =
+ PrintRegister64("sp", frame_arm64->context.iregs[31], sequence);
+ }
+ if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_PC) {
+ sequence =
+ PrintRegister64("pc", frame_arm64->context.iregs[32], sequence);
+ }
+ } else if ((cpu == "mips") || (cpu == "mips64")) {
+ const StackFrameMIPS* frame_mips =
+ reinterpret_cast<const StackFrameMIPS*>(frame);
+
+ if (frame_mips->context_validity & StackFrameMIPS::CONTEXT_VALID_GP)
+ sequence = PrintRegister64(
+ "gp", frame_mips->context.iregs[MD_CONTEXT_MIPS_REG_GP],
+ sequence);
+ if (frame_mips->context_validity & StackFrameMIPS::CONTEXT_VALID_SP)
+ sequence = PrintRegister64(
+ "sp", frame_mips->context.iregs[MD_CONTEXT_MIPS_REG_SP],
+ sequence);
+ if (frame_mips->context_validity & StackFrameMIPS::CONTEXT_VALID_FP)
+ sequence = PrintRegister64(
+ "fp", frame_mips->context.iregs[MD_CONTEXT_MIPS_REG_FP],
+ sequence);
+ if (frame_mips->context_validity & StackFrameMIPS::CONTEXT_VALID_RA)
+ sequence = PrintRegister64(
+ "ra", frame_mips->context.iregs[MD_CONTEXT_MIPS_REG_RA],
+ sequence);
+ if (frame_mips->context_validity & StackFrameMIPS::CONTEXT_VALID_PC)
+ sequence = PrintRegister64("pc", frame_mips->context.epc, sequence);
+
+ // Save registers s0-s7
+ if (frame_mips->context_validity & StackFrameMIPS::CONTEXT_VALID_S0)
+ sequence = PrintRegister64(
+ "s0", frame_mips->context.iregs[MD_CONTEXT_MIPS_REG_S0],
+ sequence);
+ if (frame_mips->context_validity & StackFrameMIPS::CONTEXT_VALID_S1)
+ sequence = PrintRegister64(
+ "s1", frame_mips->context.iregs[MD_CONTEXT_MIPS_REG_S1],
+ sequence);
+ if (frame_mips->context_validity & StackFrameMIPS::CONTEXT_VALID_S2)
+ sequence = PrintRegister64(
+ "s2", frame_mips->context.iregs[MD_CONTEXT_MIPS_REG_S2],
+ sequence);
+ if (frame_mips->context_validity & StackFrameMIPS::CONTEXT_VALID_S3)
+ sequence = PrintRegister64(
+ "s3", frame_mips->context.iregs[MD_CONTEXT_MIPS_REG_S3],
+ sequence);
+ if (frame_mips->context_validity & StackFrameMIPS::CONTEXT_VALID_S4)
+ sequence = PrintRegister64(
+ "s4", frame_mips->context.iregs[MD_CONTEXT_MIPS_REG_S4],
+ sequence);
+ if (frame_mips->context_validity & StackFrameMIPS::CONTEXT_VALID_S5)
+ sequence = PrintRegister64(
+ "s5", frame_mips->context.iregs[MD_CONTEXT_MIPS_REG_S5],
+ sequence);
+ if (frame_mips->context_validity & StackFrameMIPS::CONTEXT_VALID_S6)
+ sequence = PrintRegister64(
+ "s6", frame_mips->context.iregs[MD_CONTEXT_MIPS_REG_S6],
+ sequence);
+ if (frame_mips->context_validity & StackFrameMIPS::CONTEXT_VALID_S7)
+ sequence = PrintRegister64(
+ "s7", frame_mips->context.iregs[MD_CONTEXT_MIPS_REG_S7],
+ sequence);
+ } else if (cpu == "riscv") {
+ const StackFrameRISCV* frame_riscv =
+ reinterpret_cast<const StackFrameRISCV*>(frame);
+
+ if (frame_riscv->context_validity &
+ StackFrameRISCV::CONTEXT_VALID_PC)
+ sequence = PrintRegister(
+ "pc", frame_riscv->context.pc, sequence);
+ if (frame_riscv->context_validity &
+ StackFrameRISCV::CONTEXT_VALID_RA)
+ sequence = PrintRegister(
+ "ra", frame_riscv->context.ra, sequence);
+ if (frame_riscv->context_validity &
+ StackFrameRISCV::CONTEXT_VALID_SP)
+ sequence = PrintRegister(
+ "sp", frame_riscv->context.sp, sequence);
+ if (frame_riscv->context_validity &
+ StackFrameRISCV::CONTEXT_VALID_GP)
+ sequence = PrintRegister(
+ "gp", frame_riscv->context.gp, sequence);
+ if (frame_riscv->context_validity &
+ StackFrameRISCV::CONTEXT_VALID_TP)
+ sequence = PrintRegister(
+ "tp", frame_riscv->context.tp, sequence);
+ if (frame_riscv->context_validity &
+ StackFrameRISCV::CONTEXT_VALID_T0)
+ sequence = PrintRegister(
+ "t0", frame_riscv->context.t0, sequence);
+ if (frame_riscv->context_validity &
+ StackFrameRISCV::CONTEXT_VALID_T1)
+ sequence = PrintRegister(
+ "t1", frame_riscv->context.t1, sequence);
+ if (frame_riscv->context_validity &
+ StackFrameRISCV::CONTEXT_VALID_T2)
+ sequence = PrintRegister(
+ "t2", frame_riscv->context.t2, sequence);
+ if (frame_riscv->context_validity &
+ StackFrameRISCV::CONTEXT_VALID_S0)
+ sequence = PrintRegister(
+ "s0", frame_riscv->context.s0, sequence);
+ if (frame_riscv->context_validity &
+ StackFrameRISCV::CONTEXT_VALID_S1)
+ sequence = PrintRegister(
+ "s1", frame_riscv->context.s1, sequence);
+ if (frame_riscv->context_validity &
+ StackFrameRISCV::CONTEXT_VALID_A0)
+ sequence = PrintRegister(
+ "a0", frame_riscv->context.a0, sequence);
+ if (frame_riscv->context_validity &
+ StackFrameRISCV::CONTEXT_VALID_A1)
+ sequence = PrintRegister(
+ "a1", frame_riscv->context.a1, sequence);
+ if (frame_riscv->context_validity &
+ StackFrameRISCV::CONTEXT_VALID_A2)
+ sequence = PrintRegister(
+ "a2", frame_riscv->context.a2, sequence);
+ if (frame_riscv->context_validity &
+ StackFrameRISCV::CONTEXT_VALID_A3)
+ sequence = PrintRegister(
+ "a3", frame_riscv->context.a3, sequence);
+ if (frame_riscv->context_validity &
+ StackFrameRISCV::CONTEXT_VALID_A4)
+ sequence = PrintRegister(
+ "a4", frame_riscv->context.a4, sequence);
+ if (frame_riscv->context_validity &
+ StackFrameRISCV::CONTEXT_VALID_A5)
+ sequence = PrintRegister(
+ "a5", frame_riscv->context.a5, sequence);
+ if (frame_riscv->context_validity &
+ StackFrameRISCV::CONTEXT_VALID_A6)
+ sequence = PrintRegister(
+ "a6", frame_riscv->context.a6, sequence);
+ if (frame_riscv->context_validity &
+ StackFrameRISCV::CONTEXT_VALID_A7)
+ sequence = PrintRegister(
+ "a7", frame_riscv->context.a7, sequence);
+ if (frame_riscv->context_validity &
+ StackFrameRISCV::CONTEXT_VALID_S2)
+ sequence = PrintRegister(
+ "s2", frame_riscv->context.s2, sequence);
+ if (frame_riscv->context_validity &
+ StackFrameRISCV::CONTEXT_VALID_S3)
+ sequence = PrintRegister(
+ "s3", frame_riscv->context.s3, sequence);
+ if (frame_riscv->context_validity &
+ StackFrameRISCV::CONTEXT_VALID_S4)
+ sequence = PrintRegister(
+ "s4", frame_riscv->context.s4, sequence);
+ if (frame_riscv->context_validity &
+ StackFrameRISCV::CONTEXT_VALID_S5)
+ sequence = PrintRegister(
+ "s5", frame_riscv->context.s5, sequence);
+ if (frame_riscv->context_validity &
+ StackFrameRISCV::CONTEXT_VALID_S6)
+ sequence = PrintRegister(
+ "s6", frame_riscv->context.s6, sequence);
+ if (frame_riscv->context_validity &
+ StackFrameRISCV::CONTEXT_VALID_S7)
+ sequence = PrintRegister(
+ "s7", frame_riscv->context.s7, sequence);
+ if (frame_riscv->context_validity &
+ StackFrameRISCV::CONTEXT_VALID_S8)
+ sequence = PrintRegister(
+ "s8", frame_riscv->context.s8, sequence);
+ if (frame_riscv->context_validity &
+ StackFrameRISCV::CONTEXT_VALID_S9)
+ sequence = PrintRegister(
+ "s9", frame_riscv->context.s9, sequence);
+ if (frame_riscv->context_validity &
+ StackFrameRISCV::CONTEXT_VALID_S10)
+ sequence = PrintRegister(
+ "s10", frame_riscv->context.s10, sequence);
+ if (frame_riscv->context_validity &
+ StackFrameRISCV::CONTEXT_VALID_S11)
+ sequence = PrintRegister(
+ "s11", frame_riscv->context.s11, sequence);
+ if (frame_riscv->context_validity &
+ StackFrameRISCV::CONTEXT_VALID_T3)
+ sequence = PrintRegister(
+ "t3", frame_riscv->context.t3, sequence);
+ if (frame_riscv->context_validity &
+ StackFrameRISCV::CONTEXT_VALID_T4)
+ sequence = PrintRegister(
+ "t4", frame_riscv->context.t4, sequence);
+ if (frame_riscv->context_validity &
+ StackFrameRISCV::CONTEXT_VALID_T5)
+ sequence = PrintRegister(
+ "t5", frame_riscv->context.t5, sequence);
+ if (frame_riscv->context_validity &
+ StackFrameRISCV::CONTEXT_VALID_T6)
+ sequence = PrintRegister(
+ "t6", frame_riscv->context.t6, sequence);
+ } else if (cpu == "riscv64") {
+ const StackFrameRISCV64* frame_riscv64 =
+ reinterpret_cast<const StackFrameRISCV64*>(frame);
+
+ if (frame_riscv64->context_validity &
+ StackFrameRISCV64::CONTEXT_VALID_PC)
+ sequence = PrintRegister64(
+ "pc", frame_riscv64->context.pc, sequence);
+ if (frame_riscv64->context_validity &
+ StackFrameRISCV64::CONTEXT_VALID_RA)
+ sequence = PrintRegister64(
+ "ra", frame_riscv64->context.ra, sequence);
+ if (frame_riscv64->context_validity &
+ StackFrameRISCV64::CONTEXT_VALID_SP)
+ sequence = PrintRegister64(
+ "sp", frame_riscv64->context.sp, sequence);
+ if (frame_riscv64->context_validity &
+ StackFrameRISCV64::CONTEXT_VALID_GP)
+ sequence = PrintRegister64(
+ "gp", frame_riscv64->context.gp, sequence);
+ if (frame_riscv64->context_validity &
+ StackFrameRISCV64::CONTEXT_VALID_TP)
+ sequence = PrintRegister64(
+ "tp", frame_riscv64->context.tp, sequence);
+ if (frame_riscv64->context_validity &
+ StackFrameRISCV64::CONTEXT_VALID_T0)
+ sequence = PrintRegister64(
+ "t0", frame_riscv64->context.t0, sequence);
+ if (frame_riscv64->context_validity &
+ StackFrameRISCV64::CONTEXT_VALID_T1)
+ sequence = PrintRegister64(
+ "t1", frame_riscv64->context.t1, sequence);
+ if (frame_riscv64->context_validity &
+ StackFrameRISCV64::CONTEXT_VALID_T2)
+ sequence = PrintRegister64(
+ "t2", frame_riscv64->context.t2, sequence);
+ if (frame_riscv64->context_validity &
+ StackFrameRISCV64::CONTEXT_VALID_S0)
+ sequence = PrintRegister64(
+ "s0", frame_riscv64->context.s0, sequence);
+ if (frame_riscv64->context_validity &
+ StackFrameRISCV64::CONTEXT_VALID_S1)
+ sequence = PrintRegister64(
+ "s1", frame_riscv64->context.s1, sequence);
+ if (frame_riscv64->context_validity &
+ StackFrameRISCV64::CONTEXT_VALID_A0)
+ sequence = PrintRegister64(
+ "a0", frame_riscv64->context.a0, sequence);
+ if (frame_riscv64->context_validity &
+ StackFrameRISCV64::CONTEXT_VALID_A1)
+ sequence = PrintRegister64(
+ "a1", frame_riscv64->context.a1, sequence);
+ if (frame_riscv64->context_validity &
+ StackFrameRISCV64::CONTEXT_VALID_A2)
+ sequence = PrintRegister64(
+ "a2", frame_riscv64->context.a2, sequence);
+ if (frame_riscv64->context_validity &
+ StackFrameRISCV64::CONTEXT_VALID_A3)
+ sequence = PrintRegister64(
+ "a3", frame_riscv64->context.a3, sequence);
+ if (frame_riscv64->context_validity &
+ StackFrameRISCV64::CONTEXT_VALID_A4)
+ sequence = PrintRegister64(
+ "a4", frame_riscv64->context.a4, sequence);
+ if (frame_riscv64->context_validity &
+ StackFrameRISCV64::CONTEXT_VALID_A5)
+ sequence = PrintRegister64(
+ "a5", frame_riscv64->context.a5, sequence);
+ if (frame_riscv64->context_validity &
+ StackFrameRISCV64::CONTEXT_VALID_A6)
+ sequence = PrintRegister64(
+ "a6", frame_riscv64->context.a6, sequence);
+ if (frame_riscv64->context_validity &
+ StackFrameRISCV64::CONTEXT_VALID_A7)
+ sequence = PrintRegister64(
+ "a7", frame_riscv64->context.a7, sequence);
+ if (frame_riscv64->context_validity &
+ StackFrameRISCV64::CONTEXT_VALID_S2)
+ sequence = PrintRegister64(
+ "s2", frame_riscv64->context.s2, sequence);
+ if (frame_riscv64->context_validity &
+ StackFrameRISCV64::CONTEXT_VALID_S3)
+ sequence = PrintRegister64(
+ "s3", frame_riscv64->context.s3, sequence);
+ if (frame_riscv64->context_validity &
+ StackFrameRISCV64::CONTEXT_VALID_S4)
+ sequence = PrintRegister64(
+ "s4", frame_riscv64->context.s4, sequence);
+ if (frame_riscv64->context_validity &
+ StackFrameRISCV64::CONTEXT_VALID_S5)
+ sequence = PrintRegister64(
+ "s5", frame_riscv64->context.s5, sequence);
+ if (frame_riscv64->context_validity &
+ StackFrameRISCV64::CONTEXT_VALID_S6)
+ sequence = PrintRegister64(
+ "s6", frame_riscv64->context.s6, sequence);
+ if (frame_riscv64->context_validity &
+ StackFrameRISCV64::CONTEXT_VALID_S7)
+ sequence = PrintRegister64(
+ "s7", frame_riscv64->context.s7, sequence);
+ if (frame_riscv64->context_validity &
+ StackFrameRISCV64::CONTEXT_VALID_S8)
+ sequence = PrintRegister64(
+ "s8", frame_riscv64->context.s8, sequence);
+ if (frame_riscv64->context_validity &
+ StackFrameRISCV64::CONTEXT_VALID_S9)
+ sequence = PrintRegister64(
+ "s9", frame_riscv64->context.s9, sequence);
+ if (frame_riscv64->context_validity &
+ StackFrameRISCV64::CONTEXT_VALID_S10)
+ sequence = PrintRegister64(
+ "s10", frame_riscv64->context.s10, sequence);
+ if (frame_riscv64->context_validity &
+ StackFrameRISCV64::CONTEXT_VALID_S11)
+ sequence = PrintRegister64(
+ "s11", frame_riscv64->context.s11, sequence);
+ if (frame_riscv64->context_validity &
+ StackFrameRISCV64::CONTEXT_VALID_T3)
+ sequence = PrintRegister64(
+ "t3", frame_riscv64->context.t3, sequence);
+ if (frame_riscv64->context_validity &
+ StackFrameRISCV64::CONTEXT_VALID_T4)
+ sequence = PrintRegister64(
+ "t4", frame_riscv64->context.t4, sequence);
+ if (frame_riscv64->context_validity &
+ StackFrameRISCV64::CONTEXT_VALID_T5)
+ sequence = PrintRegister64(
+ "t5", frame_riscv64->context.t5, sequence);
+ if (frame_riscv64->context_validity &
+ StackFrameRISCV64::CONTEXT_VALID_T6)
+ sequence = PrintRegister64(
+ "t6", frame_riscv64->context.t6, sequence);
}
- } else if ((cpu == "mips") || (cpu == "mips64")) {
- const StackFrameMIPS* frame_mips =
- reinterpret_cast<const StackFrameMIPS*>(frame);
-
- if (frame_mips->context_validity & StackFrameMIPS::CONTEXT_VALID_GP)
- sequence = PrintRegister64("gp",
- frame_mips->context.iregs[MD_CONTEXT_MIPS_REG_GP],
- sequence);
- if (frame_mips->context_validity & StackFrameMIPS::CONTEXT_VALID_SP)
- sequence = PrintRegister64("sp",
- frame_mips->context.iregs[MD_CONTEXT_MIPS_REG_SP],
- sequence);
- if (frame_mips->context_validity & StackFrameMIPS::CONTEXT_VALID_FP)
- sequence = PrintRegister64("fp",
- frame_mips->context.iregs[MD_CONTEXT_MIPS_REG_FP],
- sequence);
- if (frame_mips->context_validity & StackFrameMIPS::CONTEXT_VALID_RA)
- sequence = PrintRegister64("ra",
- frame_mips->context.iregs[MD_CONTEXT_MIPS_REG_RA],
- sequence);
- if (frame_mips->context_validity & StackFrameMIPS::CONTEXT_VALID_PC)
- sequence = PrintRegister64("pc", frame_mips->context.epc, sequence);
-
- // Save registers s0-s7
- if (frame_mips->context_validity & StackFrameMIPS::CONTEXT_VALID_S0)
- sequence = PrintRegister64("s0",
- frame_mips->context.iregs[MD_CONTEXT_MIPS_REG_S0],
- sequence);
- if (frame_mips->context_validity & StackFrameMIPS::CONTEXT_VALID_S1)
- sequence = PrintRegister64("s1",
- frame_mips->context.iregs[MD_CONTEXT_MIPS_REG_S1],
- sequence);
- if (frame_mips->context_validity & StackFrameMIPS::CONTEXT_VALID_S2)
- sequence = PrintRegister64("s2",
- frame_mips->context.iregs[MD_CONTEXT_MIPS_REG_S2],
- sequence);
- if (frame_mips->context_validity & StackFrameMIPS::CONTEXT_VALID_S3)
- sequence = PrintRegister64("s3",
- frame_mips->context.iregs[MD_CONTEXT_MIPS_REG_S3],
- sequence);
- if (frame_mips->context_validity & StackFrameMIPS::CONTEXT_VALID_S4)
- sequence = PrintRegister64("s4",
- frame_mips->context.iregs[MD_CONTEXT_MIPS_REG_S4],
- sequence);
- if (frame_mips->context_validity & StackFrameMIPS::CONTEXT_VALID_S5)
- sequence = PrintRegister64("s5",
- frame_mips->context.iregs[MD_CONTEXT_MIPS_REG_S5],
- sequence);
- if (frame_mips->context_validity & StackFrameMIPS::CONTEXT_VALID_S6)
- sequence = PrintRegister64("s6",
- frame_mips->context.iregs[MD_CONTEXT_MIPS_REG_S6],
- sequence);
- if (frame_mips->context_validity & StackFrameMIPS::CONTEXT_VALID_S7)
- sequence = PrintRegister64("s7",
- frame_mips->context.iregs[MD_CONTEXT_MIPS_REG_S7],
- sequence);
}
printf("\n Found by: %s\n", frame->trust_description().c_str());
@@ -621,10 +948,10 @@ static void PrintStack(const CallStack *stack,
// Module, function, source file, and source line may all be empty
// depending on availability. The code offset follows the same rules as
// PrintStack above.
-static void PrintStackMachineReadable(int thread_num, const CallStack *stack) {
+static void PrintStackMachineReadable(int thread_num, const CallStack* stack) {
int frame_count = stack->frames()->size();
for (int frame_index = 0; frame_index < frame_count; ++frame_index) {
- const StackFrame *frame = stack->frames()->at(frame_index);
+ const StackFrame* frame = stack->frames()->at(frame_index);
printf("%d%c%d%c", thread_num, kOutputSeparator, frame_index,
kOutputSeparator);
@@ -676,8 +1003,8 @@ static void PrintStackMachineReadable(int thread_num, const CallStack *stack) {
// ContainsModule checks whether a given |module| is in the vector
// |modules_without_symbols|.
static bool ContainsModule(
- const vector<const CodeModule*> *modules,
- const CodeModule *module) {
+ const vector<const CodeModule*>* modules,
+ const CodeModule* module) {
assert(modules);
assert(module);
vector<const CodeModule*>::const_iterator iter;
@@ -694,9 +1021,9 @@ static bool ContainsModule(
// |modules_without_symbols| should contain the list of modules that were
// confirmed to be missing their symbols during the stack walk.
static void PrintModule(
- const CodeModule *module,
- const vector<const CodeModule*> *modules_without_symbols,
- const vector<const CodeModule*> *modules_with_corrupt_symbols,
+ const CodeModule* module,
+ const vector<const CodeModule*>* modules_without_symbols,
+ const vector<const CodeModule*>* modules_with_corrupt_symbols,
uint64_t main_address) {
string symbol_issues;
if (ContainsModule(modules_without_symbols, module)) {
@@ -721,9 +1048,9 @@ static void PrintModule(
// |modules_without_symbols| should contain the list of modules that were
// confirmed to be missing their symbols during the stack walk.
static void PrintModules(
- const CodeModules *modules,
- const vector<const CodeModule*> *modules_without_symbols,
- const vector<const CodeModule*> *modules_with_corrupt_symbols) {
+ const CodeModules* modules,
+ const vector<const CodeModule*>* modules_without_symbols,
+ const vector<const CodeModule*>* modules_with_corrupt_symbols) {
if (!modules)
return;
@@ -731,7 +1058,7 @@ static void PrintModules(
printf("Loaded modules:\n");
uint64_t main_address = 0;
- const CodeModule *main_module = modules->GetMainModule();
+ const CodeModule* main_module = modules->GetMainModule();
if (main_module) {
main_address = main_module->base_address();
}
@@ -740,7 +1067,7 @@ static void PrintModules(
for (unsigned int module_sequence = 0;
module_sequence < module_count;
++module_sequence) {
- const CodeModule *module = modules->GetModuleAtSequence(module_sequence);
+ const CodeModule* module = modules->GetModuleAtSequence(module_sequence);
PrintModule(module, modules_without_symbols, modules_with_corrupt_symbols,
main_address);
}
@@ -751,12 +1078,12 @@ static void PrintModules(
// text format:
// Module|{Module Filename}|{Version}|{Debug Filename}|{Debug Identifier}|
// {Base Address}|{Max Address}|{Main}
-static void PrintModulesMachineReadable(const CodeModules *modules) {
+static void PrintModulesMachineReadable(const CodeModules* modules) {
if (!modules)
return;
uint64_t main_address = 0;
- const CodeModule *main_module = modules->GetMainModule();
+ const CodeModule* main_module = modules->GetMainModule();
if (main_module) {
main_address = main_module->base_address();
}
@@ -765,7 +1092,7 @@ static void PrintModulesMachineReadable(const CodeModules *modules) {
for (unsigned int module_sequence = 0;
module_sequence < module_count;
++module_sequence) {
- const CodeModule *module = modules->GetModuleAtSequence(module_sequence);
+ const CodeModule* module = modules->GetModuleAtSequence(module_sequence);
uint64_t base_address = module->base_address();
printf("Module%c%s%c%s%c%s%c%s%c0x%08" PRIx64 "%c0x%08" PRIx64 "%c%d\n",
kOutputSeparator,
@@ -786,6 +1113,7 @@ static void PrintModulesMachineReadable(const CodeModules *modules) {
void PrintProcessState(const ProcessState& process_state,
bool output_stack_contents,
+ bool output_requesting_thread_only,
SourceLineResolverInterface* resolver) {
// Print OS and CPU information.
string cpu = process_state.system_info()->cpu;
@@ -856,17 +1184,19 @@ void PrintProcessState(const ProcessState& process_state,
process_state.modules(), resolver);
}
- // Print all of the threads in the dump.
- int thread_count = process_state.threads()->size();
- for (int thread_index = 0; thread_index < thread_count; ++thread_index) {
- if (thread_index != requesting_thread) {
- // Don't print the crash thread again, it was already printed.
- printf("\n");
- printf("Thread %d\n", thread_index);
- PrintStack(process_state.threads()->at(thread_index), cpu,
- output_stack_contents,
- process_state.thread_memory_regions()->at(thread_index),
- process_state.modules(), resolver);
+ if (!output_requesting_thread_only) {
+ // Print all of the threads in the dump.
+ int thread_count = process_state.threads()->size();
+ for (int thread_index = 0; thread_index < thread_count; ++thread_index) {
+ if (thread_index != requesting_thread) {
+ // Don't print the crash thread again, it was already printed.
+ printf("\n");
+ printf("Thread %d\n", thread_index);
+ PrintStack(process_state.threads()->at(thread_index), cpu,
+ output_stack_contents,
+ process_state.thread_memory_regions()->at(thread_index),
+ process_state.modules(), resolver);
+ }
}
}
diff --git a/src/processor/stackwalk_common.h b/src/processor/stackwalk_common.h
index a74f7b6d..bb12b98f 100644
--- a/src/processor/stackwalk_common.h
+++ b/src/processor/stackwalk_common.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2010 Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -42,6 +41,7 @@ class SourceLineResolverInterface;
void PrintProcessStateMachineReadable(const ProcessState& process_state);
void PrintProcessState(const ProcessState& process_state,
bool output_stack_contents,
+ bool output_requesting_thread_only,
SourceLineResolverInterface* resolver);
} // namespace google_breakpad
diff --git a/src/processor/stackwalker.cc b/src/processor/stackwalker.cc
index 4988ef1e..e607b721 100644
--- a/src/processor/stackwalker.cc
+++ b/src/processor/stackwalker.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2010 Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -55,6 +54,8 @@
#include "processor/stackwalker_arm.h"
#include "processor/stackwalker_arm64.h"
#include "processor/stackwalker_mips.h"
+#include "processor/stackwalker_riscv.h"
+#include "processor/stackwalker_riscv64.h"
namespace google_breakpad {
@@ -138,11 +139,12 @@ bool Stackwalker::Walk(
// frame_pointer fields. The frame structure comes from either the
// context frame (above) or a caller frame (below).
+ std::deque<std::unique_ptr<StackFrame>> inlined_frames;
// Resolve the module information, if a module map was provided.
StackFrameSymbolizer::SymbolizerResult symbolizer_result =
frame_symbolizer_->FillSourceLineInfo(modules_, unloaded_modules_,
system_info_,
- frame.get());
+ frame.get(), &inlined_frames);
switch (symbolizer_result) {
case StackFrameSymbolizer::kInterrupt:
BPLOG(INFO) << "Stack walk is interrupted.";
@@ -173,7 +175,12 @@ bool Stackwalker::Walk(
default:
break;
}
-
+ // Add all nested inlined frames belonging to this frame from the innermost
+ // frame to the outermost frame.
+ while (!inlined_frames.empty()) {
+ stack->frames_.push_back(inlined_frames.front().release());
+ inlined_frames.pop_front();
+ }
// Add the frame to the call stack. Relinquish the ownership claim
// over the frame, because the stack now owns it.
stack->frames_.push_back(frame.release());
@@ -265,6 +272,20 @@ Stackwalker* Stackwalker::StackwalkerForCPU(
memory, modules,
frame_symbolizer);
break;
+
+ case MD_CONTEXT_RISCV:
+ cpu_stackwalker = new StackwalkerRISCV(system_info,
+ context->GetContextRISCV(),
+ memory, modules,
+ frame_symbolizer);
+ break;
+
+ case MD_CONTEXT_RISCV64:
+ cpu_stackwalker = new StackwalkerRISCV64(system_info,
+ context->GetContextRISCV64(),
+ memory, modules,
+ frame_symbolizer);
+ break;
}
BPLOG_IF(ERROR, !cpu_stackwalker) << "Unknown CPU type " << HexString(cpu) <<
@@ -307,7 +328,7 @@ bool Stackwalker::InstructionAddressSeemsValid(uint64_t address) const {
frame.instruction = address;
StackFrameSymbolizer::SymbolizerResult symbolizer_result =
frame_symbolizer_->FillSourceLineInfo(modules_, unloaded_modules_,
- system_info_, &frame);
+ system_info_, &frame, nullptr);
if (!frame.module) {
// not inside any loaded module
diff --git a/src/processor/stackwalker_address_list.cc b/src/processor/stackwalker_address_list.cc
index e81fec28..b393d475 100644
--- a/src/processor/stackwalker_address_list.cc
+++ b/src/processor/stackwalker_address_list.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2013 Google Inc.
-// All rights reserved.
+// Copyright 2013 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/processor/stackwalker_address_list.h b/src/processor/stackwalker_address_list.h
index 0f8c989e..28d377c3 100644
--- a/src/processor/stackwalker_address_list.h
+++ b/src/processor/stackwalker_address_list.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2013 Google Inc.
-// All rights reserved.
+// Copyright 2013 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/processor/stackwalker_address_list_unittest.cc b/src/processor/stackwalker_address_list_unittest.cc
index ab4e9c08..feda6268 100644
--- a/src/processor/stackwalker_address_list_unittest.cc
+++ b/src/processor/stackwalker_address_list_unittest.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2013, Google Inc.
-// All rights reserved.
+// Copyright 2013 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -56,6 +55,7 @@ using google_breakpad::StackwalkerAddressList;
using std::vector;
using testing::_;
using testing::AnyNumber;
+using testing::DoAll;
using testing::Return;
using testing::SetArgumentPointee;
@@ -94,9 +94,9 @@ class StackwalkerAddressListTest : public testing::Test {
// Set the Breakpad symbol information that supplier should return for
// MODULE to INFO.
- void SetModuleSymbols(MockCodeModule *module, const string &info) {
+ void SetModuleSymbols(MockCodeModule* module, const string& info) {
size_t buffer_size;
- char *buffer = supplier.CopySymbolDataAndOwnTheCopy(info, &buffer_size);
+ char* buffer = supplier.CopySymbolDataAndOwnTheCopy(info, &buffer_size);
EXPECT_CALL(supplier, GetCStringSymbolData(module, NULL, _, _, _))
.WillRepeatedly(DoAll(SetArgumentPointee<3>(buffer),
SetArgumentPointee<4>(buffer_size),
diff --git a/src/processor/stackwalker_amd64.cc b/src/processor/stackwalker_amd64.cc
index d5ac6c65..6a539709 100644
--- a/src/processor/stackwalker_amd64.cc
+++ b/src/processor/stackwalker_amd64.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2010 Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -126,7 +125,7 @@ StackFrame* StackwalkerAMD64::GetContextFrame() {
}
StackFrameAMD64* StackwalkerAMD64::GetCallerByCFIFrameInfo(
- const vector<StackFrame*> &frames,
+ const vector<StackFrame*>& frames,
CFIFrameInfo* cfi_frame_info) {
StackFrameAMD64* last_frame = static_cast<StackFrameAMD64*>(frames.back());
@@ -143,6 +142,11 @@ StackFrameAMD64* StackwalkerAMD64::GetCallerByCFIFrameInfo(
if ((frame->context_validity & essentials) != essentials)
return NULL;
+ if (!frame->context.rip || !frame->context.rsp) {
+ BPLOG(ERROR) << "invalid rip/rsp";
+ return NULL;
+ }
+
frame->trust = StackFrame::FRAME_TRUST_CFI;
return frame.release();
}
@@ -216,14 +220,44 @@ StackFrameAMD64* StackwalkerAMD64::GetCallerByFramePointerRecovery(
return NULL;
}
+StackFrameAMD64* StackwalkerAMD64::GetCallerBySimulatingReturn(
+ const vector<StackFrame*>& frames) {
+ assert(frames.back()->trust == StackFrame::FRAME_TRUST_CONTEXT);
+ StackFrameAMD64* last_frame = static_cast<StackFrameAMD64*>(frames.back());
+ uint64_t last_rsp = last_frame->context.rsp;
+ uint64_t caller_rip_address, caller_rip;
+ int searchwords = 1;
+ if (!ScanForReturnAddress(last_rsp, &caller_rip_address, &caller_rip,
+ searchwords)) {
+ // No plausible return address at the top of the stack. Unable to simulate
+ // a return.
+ return NULL;
+ }
+
+ // Create a new stack frame (ownership will be transferred to the caller)
+ // and fill it in.
+ StackFrameAMD64* frame = new StackFrameAMD64();
+
+ frame->trust = StackFrame::FRAME_TRUST_LEAF;
+ frame->context = last_frame->context;
+ frame->context.rip = caller_rip;
+ // The caller's %rsp is directly underneath the return address pushed by
+ // the call.
+ frame->context.rsp = caller_rip_address + 8;
+ frame->context_validity = last_frame->context_validity;
+
+ return frame;
+}
+
StackFrameAMD64* StackwalkerAMD64::GetCallerByStackScan(
- const vector<StackFrame*> &frames) {
+ const vector<StackFrame*>& frames) {
StackFrameAMD64* last_frame = static_cast<StackFrameAMD64*>(frames.back());
uint64_t last_rsp = last_frame->context.rsp;
uint64_t caller_rip_address, caller_rip;
if (!ScanForReturnAddress(last_rsp, &caller_rip_address, &caller_rip,
- frames.size() == 1 /* is_context_frame */)) {
+ /*is_context_frame=*/last_frame->trust ==
+ StackFrame::FRAME_TRUST_CONTEXT)) {
// No plausible return address was found.
return NULL;
}
@@ -273,18 +307,32 @@ StackFrame* StackwalkerAMD64::GetCallerFrame(const CallStack* stack,
return NULL;
}
- const vector<StackFrame*> &frames = *stack->frames();
+ const vector<StackFrame*>& frames = *stack->frames();
StackFrameAMD64* last_frame = static_cast<StackFrameAMD64*>(frames.back());
scoped_ptr<StackFrameAMD64> new_frame;
- // If we have DWARF CFI information, use it.
+ // If we have CFI information, use it.
scoped_ptr<CFIFrameInfo> cfi_frame_info(
frame_symbolizer_->FindCFIFrameInfo(last_frame));
if (cfi_frame_info.get())
new_frame.reset(GetCallerByCFIFrameInfo(frames, cfi_frame_info.get()));
+ // If CFI was not available and this is a Windows x64 stack, check whether
+ // this is a leaf function which doesn't touch any callee-saved registers.
+ // According to https://reviews.llvm.org/D24748, LLVM doesn't generate unwind
+ // info for such functions. According to MSDN, leaf functions can be unwound
+ // simply by simulating a return.
+ if (!new_frame.get() &&
+ last_frame->trust == StackFrame::FRAME_TRUST_CONTEXT &&
+ system_info_->os_short == "windows") {
+ new_frame.reset(GetCallerBySimulatingReturn(frames));
+ }
+
// If CFI was not available or failed, try using frame pointer recovery.
- if (!new_frame.get()) {
+ // Never try to use frame pointer unwinding on Windows x64 stack. MSVC never
+ // generates code that works with frame pointer chasing, and LLVM does the
+ // same. Stack scanning would be better.
+ if (!new_frame.get() && system_info_->os_short != "windows") {
new_frame.reset(GetCallerByFramePointerRecovery(frames));
}
@@ -309,7 +357,9 @@ StackFrame* StackwalkerAMD64::GetCallerFrame(const CallStack* stack,
// Should we terminate the stack walk? (end-of-stack or broken invariant)
if (TerminateWalk(new_frame->context.rip, new_frame->context.rsp,
- last_frame->context.rsp, frames.size() == 1)) {
+ last_frame->context.rsp,
+ /*first_unwind=*/last_frame->trust ==
+ StackFrame::FRAME_TRUST_CONTEXT)) {
return NULL;
}
diff --git a/src/processor/stackwalker_amd64.h b/src/processor/stackwalker_amd64.h
index 8f3dbd52..307f2444 100644
--- a/src/processor/stackwalker_amd64.h
+++ b/src/processor/stackwalker_amd64.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2010 Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -75,7 +74,7 @@ class StackwalkerAMD64 : public Stackwalker {
// Use cfi_frame_info (derived from STACK CFI records) to construct
// the frame that called frames.back(). The caller takes ownership
// of the returned frame. Return NULL on failure.
- StackFrameAMD64* GetCallerByCFIFrameInfo(const vector<StackFrame*> &frames,
+ StackFrameAMD64* GetCallerByCFIFrameInfo(const vector<StackFrame*>& frames,
CFIFrameInfo* cfi_frame_info);
// Assumes a traditional frame layout where the frame pointer has not been
@@ -88,7 +87,12 @@ class StackwalkerAMD64 : public Stackwalker {
// Scan the stack for plausible return addresses. The caller takes ownership
// of the returned frame. Return NULL on failure.
- StackFrameAMD64* GetCallerByStackScan(const vector<StackFrame*> &frames);
+ StackFrameAMD64* GetCallerByStackScan(const vector<StackFrame*>& frames);
+
+ // Trying to simulate a return. The caller takes ownership of the returned
+ // frame. Return NULL on failure.
+ StackFrameAMD64* GetCallerBySimulatingReturn(
+ const vector<StackFrame*>& frames);
// Stores the CPU context corresponding to the innermost stack frame to
// be returned by GetContextFrame.
diff --git a/src/processor/stackwalker_amd64_unittest.cc b/src/processor/stackwalker_amd64_unittest.cc
index efcd812a..a7e513e9 100644
--- a/src/processor/stackwalker_amd64_unittest.cc
+++ b/src/processor/stackwalker_amd64_unittest.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2010, Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -104,7 +103,7 @@ class StackwalkerAMD64Fixture {
// Set the Breakpad symbol information that supplier should return for
// MODULE to INFO.
- void SetModuleSymbols(MockCodeModule *module, const string &info) {
+ void SetModuleSymbols(MockCodeModule* module, const string& info) {
size_t buffer_size;
char *buffer = supplier.CopySymbolDataAndOwnTheCopy(info, &buffer_size);
EXPECT_CALL(supplier, GetCStringSymbolData(module, &system_info, _, _, _))
@@ -125,7 +124,7 @@ class StackwalkerAMD64Fixture {
void BrandContext(MDRawContextAMD64 *raw_context) {
uint8_t x = 173;
for (size_t i = 0; i < sizeof(*raw_context); i++)
- reinterpret_cast<uint8_t *>(raw_context)[i] = (x += 17);
+ reinterpret_cast<uint8_t*>(raw_context)[i] = (x += 17);
}
SystemInfo system_info;
@@ -138,7 +137,7 @@ class StackwalkerAMD64Fixture {
MockSymbolSupplier supplier;
BasicSourceLineResolver resolver;
CallStack call_stack;
- const vector<StackFrame *> *frames;
+ const vector<StackFrame*>* frames;
};
class GetContextFrame: public StackwalkerAMD64Fixture, public Test { };
@@ -166,7 +165,7 @@ TEST_F(SanityCheck, NoResolver) {
ASSERT_EQ(0U, modules_with_corrupt_symbols.size());
frames = call_stack.frames();
ASSERT_GE(1U, frames->size());
- StackFrameAMD64 *frame = static_cast<StackFrameAMD64 *>(frames->at(0));
+ StackFrameAMD64 *frame = static_cast<StackFrameAMD64*>(frames->at(0));
// Check that the values from the original raw context made it
// through to the context in the stack frame.
EXPECT_EQ(0, memcmp(&raw_context, &frame->context, sizeof(raw_context)));
@@ -192,7 +191,7 @@ TEST_F(GetContextFrame, Simple) {
ASSERT_EQ(0U, modules_with_corrupt_symbols.size());
frames = call_stack.frames();
ASSERT_GE(1U, frames->size());
- StackFrameAMD64 *frame = static_cast<StackFrameAMD64 *>(frames->at(0));
+ StackFrameAMD64 *frame = static_cast<StackFrameAMD64*>(frames->at(0));
// Check that the values from the original raw context made it
// through to the context in the stack frame.
EXPECT_EQ(0, memcmp(&raw_context, &frame->context, sizeof(raw_context)));
@@ -216,7 +215,7 @@ TEST_F(GetContextFrame, NoStackMemory) {
ASSERT_EQ(0U, modules_with_corrupt_symbols.size());
frames = call_stack.frames();
ASSERT_GE(1U, frames->size());
- StackFrameAMD64 *frame = static_cast<StackFrameAMD64 *>(frames->at(0));
+ StackFrameAMD64 *frame = static_cast<StackFrameAMD64*>(frames->at(0));
// Check that the values from the original raw context made it
// through to the context in the stack frame.
EXPECT_EQ(0, memcmp(&raw_context, &frame->context, sizeof(raw_context)));
@@ -279,12 +278,12 @@ TEST_F(GetCallerFrame, ScanWithoutSymbols) {
frames = call_stack.frames();
ASSERT_EQ(3U, frames->size());
- StackFrameAMD64 *frame0 = static_cast<StackFrameAMD64 *>(frames->at(0));
+ StackFrameAMD64 *frame0 = static_cast<StackFrameAMD64*>(frames->at(0));
EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust);
ASSERT_EQ(StackFrameAMD64::CONTEXT_VALID_ALL, frame0->context_validity);
EXPECT_EQ(0, memcmp(&raw_context, &frame0->context, sizeof(raw_context)));
- StackFrameAMD64 *frame1 = static_cast<StackFrameAMD64 *>(frames->at(1));
+ StackFrameAMD64 *frame1 = static_cast<StackFrameAMD64*>(frames->at(1));
EXPECT_EQ(StackFrame::FRAME_TRUST_SCAN, frame1->trust);
ASSERT_EQ((StackFrameAMD64::CONTEXT_VALID_RIP |
StackFrameAMD64::CONTEXT_VALID_RSP |
@@ -294,7 +293,7 @@ TEST_F(GetCallerFrame, ScanWithoutSymbols) {
EXPECT_EQ(frame1_sp.Value(), frame1->context.rsp);
EXPECT_EQ(frame1_rbp.Value(), frame1->context.rbp);
- StackFrameAMD64 *frame2 = static_cast<StackFrameAMD64 *>(frames->at(2));
+ StackFrameAMD64 *frame2 = static_cast<StackFrameAMD64*>(frames->at(2));
EXPECT_EQ(StackFrame::FRAME_TRUST_SCAN, frame2->trust);
ASSERT_EQ((StackFrameAMD64::CONTEXT_VALID_RIP |
StackFrameAMD64::CONTEXT_VALID_RSP),
@@ -352,13 +351,13 @@ TEST_F(GetCallerFrame, ScanWithFunctionSymbols) {
frames = call_stack.frames();
ASSERT_EQ(2U, frames->size());
- StackFrameAMD64 *frame0 = static_cast<StackFrameAMD64 *>(frames->at(0));
+ StackFrameAMD64 *frame0 = static_cast<StackFrameAMD64*>(frames->at(0));
EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust);
ASSERT_EQ(StackFrameAMD64::CONTEXT_VALID_ALL, frame0->context_validity);
EXPECT_EQ("platypus", frame0->function_name);
EXPECT_EQ(0x00007400c0000100ULL, frame0->function_base);
- StackFrameAMD64 *frame1 = static_cast<StackFrameAMD64 *>(frames->at(1));
+ StackFrameAMD64 *frame1 = static_cast<StackFrameAMD64*>(frames->at(1));
EXPECT_EQ(StackFrame::FRAME_TRUST_SCAN, frame1->trust);
ASSERT_EQ((StackFrameAMD64::CONTEXT_VALID_RIP |
StackFrameAMD64::CONTEXT_VALID_RSP |
@@ -464,7 +463,7 @@ TEST_F(GetCallerFrame, GetCallerByFramePointerRecovery) {
ASSERT_EQ(3U, frames->size());
{ // To avoid reusing locals by mistake
- StackFrameAMD64 *frame = static_cast<StackFrameAMD64 *>(frames->at(0));
+ StackFrameAMD64 *frame = static_cast<StackFrameAMD64*>(frames->at(0));
EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame->trust);
ASSERT_EQ(StackFrameAMD64::CONTEXT_VALID_ALL, frame->context_validity);
EXPECT_EQ("", frame->function_name);
@@ -475,7 +474,7 @@ TEST_F(GetCallerFrame, GetCallerByFramePointerRecovery) {
}
{ // To avoid reusing locals by mistake
- StackFrameAMD64 *frame = static_cast<StackFrameAMD64 *>(frames->at(1));
+ StackFrameAMD64 *frame = static_cast<StackFrameAMD64*>(frames->at(1));
EXPECT_EQ(StackFrame::FRAME_TRUST_SCAN, frame->trust);
ASSERT_EQ((StackFrameAMD64::CONTEXT_VALID_RIP |
StackFrameAMD64::CONTEXT_VALID_RSP |
@@ -489,7 +488,7 @@ TEST_F(GetCallerFrame, GetCallerByFramePointerRecovery) {
}
{ // To avoid reusing locals by mistake
- StackFrameAMD64 *frame = static_cast<StackFrameAMD64 *>(frames->at(2));
+ StackFrameAMD64 *frame = static_cast<StackFrameAMD64*>(frames->at(2));
EXPECT_EQ(StackFrame::FRAME_TRUST_CFI, frame->trust);
ASSERT_EQ((StackFrameAMD64::CONTEXT_VALID_RIP |
StackFrameAMD64::CONTEXT_VALID_RSP |
@@ -540,12 +539,12 @@ TEST_F(GetCallerFrame, FramePointerNotAligned) {
frames = call_stack.frames();
ASSERT_EQ(2U, frames->size());
- StackFrameAMD64 *frame0 = static_cast<StackFrameAMD64 *>(frames->at(0));
+ StackFrameAMD64 *frame0 = static_cast<StackFrameAMD64*>(frames->at(0));
EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust);
ASSERT_EQ(StackFrameAMD64::CONTEXT_VALID_ALL, frame0->context_validity);
EXPECT_EQ(0, memcmp(&raw_context, &frame0->context, sizeof(raw_context)));
- StackFrameAMD64 *frame1 = static_cast<StackFrameAMD64 *>(frames->at(1));
+ StackFrameAMD64 *frame1 = static_cast<StackFrameAMD64*>(frames->at(1));
EXPECT_EQ(StackFrame::FRAME_TRUST_SCAN, frame1->trust);
ASSERT_EQ((StackFrameAMD64::CONTEXT_VALID_RIP |
StackFrameAMD64::CONTEXT_VALID_RSP),
@@ -590,12 +589,12 @@ TEST_F(GetCallerFrame, NonCanonicalInstructionPointerFromFramePointer) {
frames = call_stack.frames();
ASSERT_EQ(2U, frames->size());
- StackFrameAMD64 *frame0 = static_cast<StackFrameAMD64 *>(frames->at(0));
+ StackFrameAMD64 *frame0 = static_cast<StackFrameAMD64*>(frames->at(0));
EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust);
ASSERT_EQ(StackFrameAMD64::CONTEXT_VALID_ALL, frame0->context_validity);
EXPECT_EQ(0, memcmp(&raw_context, &frame0->context, sizeof(raw_context)));
- StackFrameAMD64 *frame1 = static_cast<StackFrameAMD64 *>(frames->at(1));
+ StackFrameAMD64 *frame1 = static_cast<StackFrameAMD64*>(frames->at(1));
EXPECT_EQ(StackFrame::FRAME_TRUST_SCAN, frame1->trust);
ASSERT_EQ((StackFrameAMD64::CONTEXT_VALID_RIP |
StackFrameAMD64::CONTEXT_VALID_RSP),
@@ -660,7 +659,7 @@ TEST_F(GetCallerFrame, ScanningNotAllowed) {
frames = call_stack.frames();
ASSERT_EQ(1U, frames->size());
- StackFrameAMD64 *frame0 = static_cast<StackFrameAMD64 *>(frames->at(0));
+ StackFrameAMD64 *frame0 = static_cast<StackFrameAMD64*>(frames->at(0));
EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust);
ASSERT_EQ(StackFrameAMD64::CONTEXT_VALID_ALL, frame0->context_validity);
EXPECT_EQ(0, memcmp(&raw_context, &frame0->context, sizeof(raw_context)));
@@ -718,14 +717,14 @@ TEST_F(GetCallerFrame, CallerPushedRBP) {
frames = call_stack.frames();
ASSERT_EQ(2U, frames->size());
- StackFrameAMD64 *frame0 = static_cast<StackFrameAMD64 *>(frames->at(0));
+ StackFrameAMD64 *frame0 = static_cast<StackFrameAMD64*>(frames->at(0));
EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust);
ASSERT_EQ(StackFrameAMD64::CONTEXT_VALID_ALL, frame0->context_validity);
EXPECT_EQ(frame0_rbp.Value(), frame0->context.rbp);
EXPECT_EQ("sasquatch", frame0->function_name);
EXPECT_EQ(0x00007400c0000100ULL, frame0->function_base);
- StackFrameAMD64 *frame1 = static_cast<StackFrameAMD64 *>(frames->at(1));
+ StackFrameAMD64 *frame1 = static_cast<StackFrameAMD64*>(frames->at(1));
EXPECT_EQ(StackFrame::FRAME_TRUST_FP, frame1->trust);
ASSERT_EQ((StackFrameAMD64::CONTEXT_VALID_RIP |
StackFrameAMD64::CONTEXT_VALID_RSP |
@@ -799,13 +798,13 @@ struct CFIFixture: public StackwalkerAMD64Fixture {
frames = call_stack.frames();
ASSERT_EQ(2U, frames->size());
- StackFrameAMD64 *frame0 = static_cast<StackFrameAMD64 *>(frames->at(0));
+ StackFrameAMD64 *frame0 = static_cast<StackFrameAMD64*>(frames->at(0));
EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust);
ASSERT_EQ(StackFrameAMD64::CONTEXT_VALID_ALL, frame0->context_validity);
EXPECT_EQ("enchiridion", frame0->function_name);
EXPECT_EQ(0x00007400c0004000ULL, frame0->function_base);
- StackFrameAMD64 *frame1 = static_cast<StackFrameAMD64 *>(frames->at(1));
+ StackFrameAMD64 *frame1 = static_cast<StackFrameAMD64*>(frames->at(1));
EXPECT_EQ(StackFrame::FRAME_TRUST_CFI, frame1->trust);
ASSERT_EQ((StackFrameAMD64::CONTEXT_VALID_RIP |
StackFrameAMD64::CONTEXT_VALID_RSP |
diff --git a/src/processor/stackwalker_arm.cc b/src/processor/stackwalker_arm.cc
index 1313416f..7df2eb6d 100644
--- a/src/processor/stackwalker_arm.cc
+++ b/src/processor/stackwalker_arm.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2010 Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -78,7 +77,7 @@ StackFrame* StackwalkerARM::GetContextFrame() {
}
StackFrameARM* StackwalkerARM::GetCallerByCFIFrameInfo(
- const vector<StackFrame*> &frames,
+ const vector<StackFrame*>& frames,
CFIFrameInfo* cfi_frame_info) {
StackFrameARM* last_frame = static_cast<StackFrameARM*>(frames.back());
@@ -162,13 +161,14 @@ StackFrameARM* StackwalkerARM::GetCallerByCFIFrameInfo(
}
StackFrameARM* StackwalkerARM::GetCallerByStackScan(
- const vector<StackFrame*> &frames) {
+ const vector<StackFrame*>& frames) {
StackFrameARM* last_frame = static_cast<StackFrameARM*>(frames.back());
uint32_t last_sp = last_frame->context.iregs[MD_CONTEXT_ARM_REG_SP];
uint32_t caller_sp, caller_pc;
if (!ScanForReturnAddress(last_sp, &caller_sp, &caller_pc,
- frames.size() == 1 /* is_context_frame */)) {
+ /*is_context_frame=*/last_frame->trust ==
+ StackFrame::FRAME_TRUST_CONTEXT)) {
// No plausible return address was found.
return NULL;
}
@@ -193,7 +193,7 @@ StackFrameARM* StackwalkerARM::GetCallerByStackScan(
}
StackFrameARM* StackwalkerARM::GetCallerByFramePointer(
- const vector<StackFrame*> &frames) {
+ const vector<StackFrame*>& frames) {
StackFrameARM* last_frame = static_cast<StackFrameARM*>(frames.back());
if (!(last_frame->context_validity &
@@ -245,7 +245,7 @@ StackFrame* StackwalkerARM::GetCallerFrame(const CallStack* stack,
return NULL;
}
- const vector<StackFrame*> &frames = *stack->frames();
+ const vector<StackFrame*>& frames = *stack->frames();
StackFrameARM* last_frame = static_cast<StackFrameARM*>(frames.back());
scoped_ptr<StackFrameARM> frame;
@@ -276,7 +276,8 @@ StackFrame* StackwalkerARM::GetCallerFrame(const CallStack* stack,
if (TerminateWalk(frame->context.iregs[MD_CONTEXT_ARM_REG_PC],
frame->context.iregs[MD_CONTEXT_ARM_REG_SP],
last_frame->context.iregs[MD_CONTEXT_ARM_REG_SP],
- frames.size() == 1)) {
+ /*first_unwind=*/last_frame->trust ==
+ StackFrame::FRAME_TRUST_CONTEXT)) {
return NULL;
}
diff --git a/src/processor/stackwalker_arm.h b/src/processor/stackwalker_arm.h
index 9081a40c..d95b4e32 100644
--- a/src/processor/stackwalker_arm.h
+++ b/src/processor/stackwalker_arm.h
@@ -1,7 +1,6 @@
// -*- mode: C++ -*-
-// Copyright (c) 2010 Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -13,7 +12,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -75,16 +74,16 @@ class StackwalkerARM : public Stackwalker {
// Use cfi_frame_info (derived from STACK CFI records) to construct
// the frame that called frames.back(). The caller takes ownership
// of the returned frame. Return NULL on failure.
- StackFrameARM* GetCallerByCFIFrameInfo(const vector<StackFrame*> &frames,
+ StackFrameARM* GetCallerByCFIFrameInfo(const vector<StackFrame*>& frames,
CFIFrameInfo* cfi_frame_info);
// Use the frame pointer. The caller takes ownership of the returned frame.
// Return NULL on failure.
- StackFrameARM* GetCallerByFramePointer(const vector<StackFrame*> &frames);
+ StackFrameARM* GetCallerByFramePointer(const vector<StackFrame*>& frames);
// Scan the stack for plausible return addresses. The caller takes ownership
// of the returned frame. Return NULL on failure.
- StackFrameARM* GetCallerByStackScan(const vector<StackFrame*> &frames);
+ StackFrameARM* GetCallerByStackScan(const vector<StackFrame*>& frames);
// Stores the CPU context corresponding to the youngest stack frame, to
// be returned by GetContextFrame.
diff --git a/src/processor/stackwalker_arm64.cc b/src/processor/stackwalker_arm64.cc
index 5bfd2636..ae3a0595 100644
--- a/src/processor/stackwalker_arm64.cc
+++ b/src/processor/stackwalker_arm64.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2013 Google Inc.
-// All rights reserved.
+// Copyright 2013 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -99,7 +98,7 @@ StackFrame* StackwalkerARM64::GetContextFrame() {
}
StackFrameARM64* StackwalkerARM64::GetCallerByCFIFrameInfo(
- const vector<StackFrame*> &frames,
+ const vector<StackFrame*>& frames,
CFIFrameInfo* cfi_frame_info) {
StackFrameARM64* last_frame = static_cast<StackFrameARM64*>(frames.back());
@@ -170,18 +169,21 @@ StackFrameARM64* StackwalkerARM64::GetCallerByCFIFrameInfo(
if ((frame->context_validity & essentials) != essentials)
return NULL;
+ frame->context.iregs[MD_CONTEXT_ARM64_REG_PC] =
+ PtrauthStrip(frame->context.iregs[MD_CONTEXT_ARM64_REG_PC]);
frame->trust = StackFrame::FRAME_TRUST_CFI;
return frame.release();
}
StackFrameARM64* StackwalkerARM64::GetCallerByStackScan(
- const vector<StackFrame*> &frames) {
+ const vector<StackFrame*>& frames) {
StackFrameARM64* last_frame = static_cast<StackFrameARM64*>(frames.back());
uint64_t last_sp = last_frame->context.iregs[MD_CONTEXT_ARM64_REG_SP];
uint64_t caller_sp, caller_pc;
if (!ScanForReturnAddress(last_sp, &caller_sp, &caller_pc,
- frames.size() == 1 /* is_context_frame */)) {
+ /*is_context_frame=*/last_frame->trust ==
+ StackFrame::FRAME_TRUST_CONTEXT)) {
// No plausible return address was found.
return NULL;
}
@@ -206,7 +208,7 @@ StackFrameARM64* StackwalkerARM64::GetCallerByStackScan(
}
StackFrameARM64* StackwalkerARM64::GetCallerByFramePointer(
- const vector<StackFrame*> &frames) {
+ const vector<StackFrame*>& frames) {
StackFrameARM64* last_frame = static_cast<StackFrameARM64*>(frames.back());
if (!(last_frame->context_validity & StackFrameARM64::CONTEXT_VALID_LR)) {
CorrectRegLRByFramePointer(frames, last_frame);
@@ -294,7 +296,7 @@ StackFrame* StackwalkerARM64::GetCallerFrame(const CallStack* stack,
return NULL;
}
- const vector<StackFrame*> &frames = *stack->frames();
+ const vector<StackFrame*>& frames = *stack->frames();
StackFrameARM64* last_frame = static_cast<StackFrameARM64*>(frames.back());
scoped_ptr<StackFrameARM64> frame;
@@ -320,7 +322,8 @@ StackFrame* StackwalkerARM64::GetCallerFrame(const CallStack* stack,
if (TerminateWalk(frame->context.iregs[MD_CONTEXT_ARM64_REG_PC],
frame->context.iregs[MD_CONTEXT_ARM64_REG_SP],
last_frame->context.iregs[MD_CONTEXT_ARM64_REG_SP],
- frames.size() == 1)) {
+ /*first_unwind=*/last_frame->trust ==
+ StackFrame::FRAME_TRUST_CONTEXT)) {
return NULL;
}
diff --git a/src/processor/stackwalker_arm64.h b/src/processor/stackwalker_arm64.h
index 39735c67..193ab302 100644
--- a/src/processor/stackwalker_arm64.h
+++ b/src/processor/stackwalker_arm64.h
@@ -1,7 +1,6 @@
// -*- mode: C++ -*-
-// Copyright (c) 2013 Google Inc.
-// All rights reserved.
+// Copyright 2013 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -13,7 +12,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -79,16 +78,16 @@ class StackwalkerARM64 : public Stackwalker {
// Use cfi_frame_info (derived from STACK CFI records) to construct
// the frame that called frames.back(). The caller takes ownership
// of the returned frame. Return NULL on failure.
- StackFrameARM64* GetCallerByCFIFrameInfo(const vector<StackFrame*> &frames,
+ StackFrameARM64* GetCallerByCFIFrameInfo(const vector<StackFrame*>& frames,
CFIFrameInfo* cfi_frame_info);
// Use the frame pointer. The caller takes ownership of the returned frame.
// Return NULL on failure.
- StackFrameARM64* GetCallerByFramePointer(const vector<StackFrame*> &frames);
+ StackFrameARM64* GetCallerByFramePointer(const vector<StackFrame*>& frames);
// Scan the stack for plausible return addresses. The caller takes ownership
// of the returned frame. Return NULL on failure.
- StackFrameARM64* GetCallerByStackScan(const vector<StackFrame*> &frames);
+ StackFrameARM64* GetCallerByStackScan(const vector<StackFrame*>& frames);
// GetCallerByFramePointer() depends on the previous frame having recovered
// x30($LR) which may not have been done when using CFI.
diff --git a/src/processor/stackwalker_arm64_unittest.cc b/src/processor/stackwalker_arm64_unittest.cc
index d86fa127..37475058 100644
--- a/src/processor/stackwalker_arm64_unittest.cc
+++ b/src/processor/stackwalker_arm64_unittest.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2010, Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -105,7 +104,7 @@ class StackwalkerARM64Fixture {
// Set the Breakpad symbol information that supplier should return for
// MODULE to INFO.
- void SetModuleSymbols(MockCodeModule *module, const string &info) {
+ void SetModuleSymbols(MockCodeModule* module, const string& info) {
size_t buffer_size;
char *buffer = supplier.CopySymbolDataAndOwnTheCopy(info, &buffer_size);
EXPECT_CALL(supplier, GetCStringSymbolData(module, &system_info, _, _, _))
@@ -126,7 +125,7 @@ class StackwalkerARM64Fixture {
void BrandContext(MDRawContextARM64 *raw_context) {
uint8_t x = 173;
for (size_t i = 0; i < sizeof(*raw_context); i++)
- reinterpret_cast<uint8_t *>(raw_context)[i] = (x += 17);
+ reinterpret_cast<uint8_t*>(raw_context)[i] = (x += 17);
}
SystemInfo system_info;
@@ -139,7 +138,7 @@ class StackwalkerARM64Fixture {
MockSymbolSupplier supplier;
BasicSourceLineResolver resolver;
CallStack call_stack;
- const vector<StackFrame *> *frames;
+ const vector<StackFrame*>* frames;
};
class SanityCheck: public StackwalkerARM64Fixture, public Test { };
@@ -159,7 +158,7 @@ TEST_F(SanityCheck, NoResolver) {
ASSERT_EQ(0U, modules_with_corrupt_symbols.size());
frames = call_stack.frames();
ASSERT_EQ(1U, frames->size());
- StackFrameARM64 *frame = static_cast<StackFrameARM64 *>(frames->at(0));
+ StackFrameARM64 *frame = static_cast<StackFrameARM64*>(frames->at(0));
// Check that the values from the original raw context made it
// through to the context in the stack frame.
EXPECT_EQ(0, memcmp(&raw_context, &frame->context, sizeof(raw_context)));
@@ -181,7 +180,7 @@ TEST_F(GetContextFrame, NoStackMemory) {
ASSERT_EQ(0U, modules_with_corrupt_symbols.size());
frames = call_stack.frames();
ASSERT_EQ(1U, frames->size());
- StackFrameARM64 *frame = static_cast<StackFrameARM64 *>(frames->at(0));
+ StackFrameARM64 *frame = static_cast<StackFrameARM64*>(frames->at(0));
// Check that the values from the original raw context made it
// through to the context in the stack frame.
EXPECT_EQ(0, memcmp(&raw_context, &frame->context, sizeof(raw_context)));
@@ -237,13 +236,13 @@ TEST_F(GetCallerFrame, ScanWithoutSymbols) {
frames = call_stack.frames();
ASSERT_EQ(3U, frames->size());
- StackFrameARM64 *frame0 = static_cast<StackFrameARM64 *>(frames->at(0));
+ StackFrameARM64 *frame0 = static_cast<StackFrameARM64*>(frames->at(0));
EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust);
ASSERT_EQ(StackFrameARM64::CONTEXT_VALID_ALL,
frame0->context_validity);
EXPECT_EQ(0, memcmp(&raw_context, &frame0->context, sizeof(raw_context)));
- StackFrameARM64 *frame1 = static_cast<StackFrameARM64 *>(frames->at(1));
+ StackFrameARM64 *frame1 = static_cast<StackFrameARM64*>(frames->at(1));
EXPECT_EQ(StackFrame::FRAME_TRUST_SCAN, frame1->trust);
ASSERT_EQ((StackFrameARM64::CONTEXT_VALID_PC |
StackFrameARM64::CONTEXT_VALID_SP),
@@ -251,7 +250,7 @@ TEST_F(GetCallerFrame, ScanWithoutSymbols) {
EXPECT_EQ(return_address1, frame1->context.iregs[MD_CONTEXT_ARM64_REG_PC]);
EXPECT_EQ(frame1_sp.Value(), frame1->context.iregs[MD_CONTEXT_ARM64_REG_SP]);
- StackFrameARM64 *frame2 = static_cast<StackFrameARM64 *>(frames->at(2));
+ StackFrameARM64 *frame2 = static_cast<StackFrameARM64*>(frames->at(2));
EXPECT_EQ(StackFrame::FRAME_TRUST_SCAN, frame2->trust);
ASSERT_EQ((StackFrameARM64::CONTEXT_VALID_PC |
StackFrameARM64::CONTEXT_VALID_SP),
@@ -307,7 +306,7 @@ TEST_F(GetCallerFrame, ScanWithFunctionSymbols) {
frames = call_stack.frames();
ASSERT_EQ(2U, frames->size());
- StackFrameARM64 *frame0 = static_cast<StackFrameARM64 *>(frames->at(0));
+ StackFrameARM64 *frame0 = static_cast<StackFrameARM64*>(frames->at(0));
EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust);
ASSERT_EQ(StackFrameARM64::CONTEXT_VALID_ALL,
frame0->context_validity);
@@ -315,7 +314,7 @@ TEST_F(GetCallerFrame, ScanWithFunctionSymbols) {
EXPECT_EQ("monotreme", frame0->function_name);
EXPECT_EQ(0x40000100ULL, frame0->function_base);
- StackFrameARM64 *frame1 = static_cast<StackFrameARM64 *>(frames->at(1));
+ StackFrameARM64 *frame1 = static_cast<StackFrameARM64*>(frames->at(1));
EXPECT_EQ(StackFrame::FRAME_TRUST_SCAN, frame1->trust);
ASSERT_EQ((StackFrameARM64::CONTEXT_VALID_PC |
StackFrameARM64::CONTEXT_VALID_SP),
@@ -376,13 +375,13 @@ TEST_F(GetCallerFrame, ScanFirstFrame) {
frames = call_stack.frames();
ASSERT_EQ(2U, frames->size());
- StackFrameARM64 *frame0 = static_cast<StackFrameARM64 *>(frames->at(0));
+ StackFrameARM64 *frame0 = static_cast<StackFrameARM64*>(frames->at(0));
EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust);
ASSERT_EQ(StackFrameARM64::CONTEXT_VALID_ALL,
frame0->context_validity);
EXPECT_EQ(0, memcmp(&raw_context, &frame0->context, sizeof(raw_context)));
- StackFrameARM64 *frame1 = static_cast<StackFrameARM64 *>(frames->at(1));
+ StackFrameARM64 *frame1 = static_cast<StackFrameARM64*>(frames->at(1));
EXPECT_EQ(StackFrame::FRAME_TRUST_SCAN, frame1->trust);
ASSERT_EQ((StackFrameARM64::CONTEXT_VALID_PC |
StackFrameARM64::CONTEXT_VALID_SP),
@@ -440,7 +439,7 @@ TEST_F(GetCallerFrame, ScanningNotAllowed) {
frames = call_stack.frames();
ASSERT_EQ(1U, frames->size());
- StackFrameARM64 *frame0 = static_cast<StackFrameARM64 *>(frames->at(0));
+ StackFrameARM64 *frame0 = static_cast<StackFrameARM64*>(frames->at(0));
EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust);
ASSERT_EQ(StackFrameARM64::CONTEXT_VALID_ALL,
frame0->context_validity);
@@ -503,13 +502,13 @@ TEST_F(GetFramesByFramePointer, OnlyFramePointer) {
frames = call_stack.frames();
ASSERT_EQ(3U, frames->size());
- StackFrameARM64 *frame0 = static_cast<StackFrameARM64 *>(frames->at(0));
+ StackFrameARM64 *frame0 = static_cast<StackFrameARM64*>(frames->at(0));
EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust);
ASSERT_EQ(StackFrameARM64::CONTEXT_VALID_ALL,
frame0->context_validity);
EXPECT_EQ(0, memcmp(&raw_context, &frame0->context, sizeof(raw_context)));
- StackFrameARM64 *frame1 = static_cast<StackFrameARM64 *>(frames->at(1));
+ StackFrameARM64 *frame1 = static_cast<StackFrameARM64*>(frames->at(1));
EXPECT_EQ(StackFrame::FRAME_TRUST_FP, frame1->trust);
ASSERT_EQ((StackFrameARM64::CONTEXT_VALID_PC |
StackFrameARM64::CONTEXT_VALID_LR |
@@ -522,7 +521,7 @@ TEST_F(GetFramesByFramePointer, OnlyFramePointer) {
EXPECT_EQ(frame2_fp.Value(),
frame1->context.iregs[MD_CONTEXT_ARM64_REG_FP]);
- StackFrameARM64 *frame2 = static_cast<StackFrameARM64 *>(frames->at(2));
+ StackFrameARM64 *frame2 = static_cast<StackFrameARM64*>(frames->at(2));
EXPECT_EQ(StackFrame::FRAME_TRUST_FP, frame2->trust);
ASSERT_EQ((StackFrameARM64::CONTEXT_VALID_PC |
StackFrameARM64::CONTEXT_VALID_LR |
@@ -642,13 +641,13 @@ struct CFIFixture: public StackwalkerARM64Fixture {
frames = call_stack.frames();
ASSERT_EQ(2U, frames->size());
- StackFrameARM64 *frame0 = static_cast<StackFrameARM64 *>(frames->at(0));
+ StackFrameARM64 *frame0 = static_cast<StackFrameARM64*>(frames->at(0));
EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust);
ASSERT_EQ(context_frame_validity, frame0->context_validity);
EXPECT_EQ("enchiridion", frame0->function_name);
EXPECT_EQ(0x0000000040004000UL, frame0->function_base);
- StackFrameARM64 *frame1 = static_cast<StackFrameARM64 *>(frames->at(1));
+ StackFrameARM64 *frame1 = static_cast<StackFrameARM64*>(frames->at(1));
EXPECT_EQ(StackFrame::FRAME_TRUST_CFI, frame1->trust);
ASSERT_EQ(expected_validity, frame1->context_validity);
if (expected_validity & StackFrameARM64::CONTEXT_VALID_X1)
diff --git a/src/processor/stackwalker_arm_unittest.cc b/src/processor/stackwalker_arm_unittest.cc
index 256f7648..20c810a7 100644
--- a/src/processor/stackwalker_arm_unittest.cc
+++ b/src/processor/stackwalker_arm_unittest.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2010, Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -106,7 +105,7 @@ class StackwalkerARMFixture {
// Set the Breakpad symbol information that supplier should return for
// MODULE to INFO.
- void SetModuleSymbols(MockCodeModule *module, const string &info) {
+ void SetModuleSymbols(MockCodeModule* module, const string& info) {
size_t buffer_size;
char *buffer = supplier.CopySymbolDataAndOwnTheCopy(info, &buffer_size);
EXPECT_CALL(supplier, GetCStringSymbolData(module, &system_info, _, _, _))
@@ -127,7 +126,7 @@ class StackwalkerARMFixture {
void BrandContext(MDRawContextARM *raw_context) {
uint8_t x = 173;
for (size_t i = 0; i < sizeof(*raw_context); i++)
- reinterpret_cast<uint8_t *>(raw_context)[i] = (x += 17);
+ reinterpret_cast<uint8_t*>(raw_context)[i] = (x += 17);
}
SystemInfo system_info;
@@ -140,7 +139,7 @@ class StackwalkerARMFixture {
MockSymbolSupplier supplier;
BasicSourceLineResolver resolver;
CallStack call_stack;
- const vector<StackFrame *> *frames;
+ const vector<StackFrame*>* frames;
};
class SanityCheck: public StackwalkerARMFixture, public Test { };
@@ -161,7 +160,7 @@ TEST_F(SanityCheck, NoResolver) {
ASSERT_EQ(0U, modules_with_corrupt_symbols.size());
frames = call_stack.frames();
ASSERT_EQ(1U, frames->size());
- StackFrameARM *frame = static_cast<StackFrameARM *>(frames->at(0));
+ StackFrameARM *frame = static_cast<StackFrameARM*>(frames->at(0));
// Check that the values from the original raw context made it
// through to the context in the stack frame.
EXPECT_EQ(0, memcmp(&raw_context, &frame->context, sizeof(raw_context)));
@@ -184,7 +183,7 @@ TEST_F(GetContextFrame, Simple) {
ASSERT_EQ(0U, modules_with_corrupt_symbols.size());
frames = call_stack.frames();
ASSERT_EQ(1U, frames->size());
- StackFrameARM *frame = static_cast<StackFrameARM *>(frames->at(0));
+ StackFrameARM *frame = static_cast<StackFrameARM*>(frames->at(0));
// Check that the values from the original raw context made it
// through to the context in the stack frame.
EXPECT_EQ(0, memcmp(&raw_context, &frame->context, sizeof(raw_context)));
@@ -204,7 +203,7 @@ TEST_F(GetContextFrame, NoStackMemory) {
ASSERT_EQ(0U, modules_with_corrupt_symbols.size());
frames = call_stack.frames();
ASSERT_EQ(1U, frames->size());
- StackFrameARM *frame = static_cast<StackFrameARM *>(frames->at(0));
+ StackFrameARM *frame = static_cast<StackFrameARM*>(frames->at(0));
// Check that the values from the original raw context made it
// through to the context in the stack frame.
EXPECT_EQ(0, memcmp(&raw_context, &frame->context, sizeof(raw_context)));
@@ -260,12 +259,12 @@ TEST_F(GetCallerFrame, ScanWithoutSymbols) {
frames = call_stack.frames();
ASSERT_EQ(3U, frames->size());
- StackFrameARM *frame0 = static_cast<StackFrameARM *>(frames->at(0));
+ StackFrameARM *frame0 = static_cast<StackFrameARM*>(frames->at(0));
EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust);
ASSERT_EQ(StackFrameARM::CONTEXT_VALID_ALL, frame0->context_validity);
EXPECT_EQ(0, memcmp(&raw_context, &frame0->context, sizeof(raw_context)));
- StackFrameARM *frame1 = static_cast<StackFrameARM *>(frames->at(1));
+ StackFrameARM *frame1 = static_cast<StackFrameARM*>(frames->at(1));
EXPECT_EQ(StackFrame::FRAME_TRUST_SCAN, frame1->trust);
ASSERT_EQ((StackFrameARM::CONTEXT_VALID_PC |
StackFrameARM::CONTEXT_VALID_SP),
@@ -273,7 +272,7 @@ TEST_F(GetCallerFrame, ScanWithoutSymbols) {
EXPECT_EQ(return_address1, frame1->context.iregs[MD_CONTEXT_ARM_REG_PC]);
EXPECT_EQ(frame1_sp.Value(), frame1->context.iregs[MD_CONTEXT_ARM_REG_SP]);
- StackFrameARM *frame2 = static_cast<StackFrameARM *>(frames->at(2));
+ StackFrameARM *frame2 = static_cast<StackFrameARM*>(frames->at(2));
EXPECT_EQ(StackFrame::FRAME_TRUST_SCAN, frame2->trust);
ASSERT_EQ((StackFrameARM::CONTEXT_VALID_PC |
StackFrameARM::CONTEXT_VALID_SP),
@@ -329,14 +328,14 @@ TEST_F(GetCallerFrame, ScanWithFunctionSymbols) {
frames = call_stack.frames();
ASSERT_EQ(2U, frames->size());
- StackFrameARM *frame0 = static_cast<StackFrameARM *>(frames->at(0));
+ StackFrameARM *frame0 = static_cast<StackFrameARM*>(frames->at(0));
EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust);
ASSERT_EQ(StackFrameARM::CONTEXT_VALID_ALL, frame0->context_validity);
EXPECT_EQ(0, memcmp(&raw_context, &frame0->context, sizeof(raw_context)));
EXPECT_EQ("monotreme", frame0->function_name);
EXPECT_EQ(0x40000100U, frame0->function_base);
- StackFrameARM *frame1 = static_cast<StackFrameARM *>(frames->at(1));
+ StackFrameARM *frame1 = static_cast<StackFrameARM*>(frames->at(1));
EXPECT_EQ(StackFrame::FRAME_TRUST_SCAN, frame1->trust);
ASSERT_EQ((StackFrameARM::CONTEXT_VALID_PC |
StackFrameARM::CONTEXT_VALID_SP),
@@ -397,12 +396,12 @@ TEST_F(GetCallerFrame, ScanFirstFrame) {
frames = call_stack.frames();
ASSERT_EQ(2U, frames->size());
- StackFrameARM *frame0 = static_cast<StackFrameARM *>(frames->at(0));
+ StackFrameARM *frame0 = static_cast<StackFrameARM*>(frames->at(0));
EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust);
ASSERT_EQ(StackFrameARM::CONTEXT_VALID_ALL, frame0->context_validity);
EXPECT_EQ(0, memcmp(&raw_context, &frame0->context, sizeof(raw_context)));
- StackFrameARM *frame1 = static_cast<StackFrameARM *>(frames->at(1));
+ StackFrameARM *frame1 = static_cast<StackFrameARM*>(frames->at(1));
EXPECT_EQ(StackFrame::FRAME_TRUST_SCAN, frame1->trust);
ASSERT_EQ((StackFrameARM::CONTEXT_VALID_PC |
StackFrameARM::CONTEXT_VALID_SP),
@@ -460,7 +459,7 @@ TEST_F(GetCallerFrame, ScanningNotAllowed) {
frames = call_stack.frames();
ASSERT_EQ(1U, frames->size());
- StackFrameARM *frame0 = static_cast<StackFrameARM *>(frames->at(0));
+ StackFrameARM *frame0 = static_cast<StackFrameARM*>(frames->at(0));
EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust);
ASSERT_EQ(StackFrameARM::CONTEXT_VALID_ALL, frame0->context_validity);
EXPECT_EQ(0, memcmp(&raw_context, &frame0->context, sizeof(raw_context)));
@@ -565,13 +564,13 @@ struct CFIFixture: public StackwalkerARMFixture {
frames = call_stack.frames();
ASSERT_EQ(2U, frames->size());
- StackFrameARM *frame0 = static_cast<StackFrameARM *>(frames->at(0));
+ StackFrameARM *frame0 = static_cast<StackFrameARM*>(frames->at(0));
EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust);
ASSERT_EQ(context_frame_validity, frame0->context_validity);
EXPECT_EQ("enchiridion", frame0->function_name);
EXPECT_EQ(0x40004000U, frame0->function_base);
- StackFrameARM *frame1 = static_cast<StackFrameARM *>(frames->at(1));
+ StackFrameARM *frame1 = static_cast<StackFrameARM*>(frames->at(1));
EXPECT_EQ(StackFrame::FRAME_TRUST_CFI, frame1->trust);
ASSERT_EQ(expected_validity, frame1->context_validity);
if (expected_validity & StackFrameARM::CONTEXT_VALID_R1)
@@ -848,12 +847,12 @@ TEST_F(GetFramesByFramePointer, OnlyFramePointer) {
frames = call_stack.frames();
ASSERT_EQ(3U, frames->size());
- StackFrameARM *frame0 = static_cast<StackFrameARM *>(frames->at(0));
+ StackFrameARM *frame0 = static_cast<StackFrameARM*>(frames->at(0));
EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust);
ASSERT_EQ(StackFrameARM::CONTEXT_VALID_ALL, frame0->context_validity);
EXPECT_EQ(0, memcmp(&raw_context, &frame0->context, sizeof(raw_context)));
- StackFrameARM *frame1 = static_cast<StackFrameARM *>(frames->at(1));
+ StackFrameARM *frame1 = static_cast<StackFrameARM*>(frames->at(1));
EXPECT_EQ(StackFrame::FRAME_TRUST_FP, frame1->trust);
ASSERT_EQ((StackFrameARM::CONTEXT_VALID_PC |
StackFrameARM::CONTEXT_VALID_LR |
@@ -866,7 +865,7 @@ TEST_F(GetFramesByFramePointer, OnlyFramePointer) {
EXPECT_EQ(frame2_fp.Value(),
frame1->context.iregs[MD_CONTEXT_ARM_REG_IOS_FP]);
- StackFrameARM *frame2 = static_cast<StackFrameARM *>(frames->at(2));
+ StackFrameARM *frame2 = static_cast<StackFrameARM*>(frames->at(2));
EXPECT_EQ(StackFrame::FRAME_TRUST_FP, frame2->trust);
ASSERT_EQ((StackFrameARM::CONTEXT_VALID_PC |
StackFrameARM::CONTEXT_VALID_LR |
@@ -944,12 +943,12 @@ TEST_F(GetFramesByFramePointer, FramePointerAndCFI) {
frames = call_stack.frames();
ASSERT_EQ(3U, frames->size());
- StackFrameARM *frame0 = static_cast<StackFrameARM *>(frames->at(0));
+ StackFrameARM *frame0 = static_cast<StackFrameARM*>(frames->at(0));
EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust);
ASSERT_EQ(StackFrameARM::CONTEXT_VALID_ALL, frame0->context_validity);
EXPECT_EQ(0, memcmp(&raw_context, &frame0->context, sizeof(raw_context)));
- StackFrameARM *frame1 = static_cast<StackFrameARM *>(frames->at(1));
+ StackFrameARM *frame1 = static_cast<StackFrameARM*>(frames->at(1));
EXPECT_EQ(StackFrame::FRAME_TRUST_FP, frame1->trust);
ASSERT_EQ((StackFrameARM::CONTEXT_VALID_PC |
StackFrameARM::CONTEXT_VALID_LR |
@@ -965,7 +964,7 @@ TEST_F(GetFramesByFramePointer, FramePointerAndCFI) {
EXPECT_EQ(0x40004000U, frame1->function_base);
- StackFrameARM *frame2 = static_cast<StackFrameARM *>(frames->at(2));
+ StackFrameARM *frame2 = static_cast<StackFrameARM*>(frames->at(2));
EXPECT_EQ(StackFrame::FRAME_TRUST_CFI, frame2->trust);
ASSERT_EQ((StackFrameARM::CONTEXT_VALID_PC |
StackFrameARM::CONTEXT_VALID_LR |
diff --git a/src/processor/stackwalker_mips.cc b/src/processor/stackwalker_mips.cc
index c33ecdbe..11b08fae 100644
--- a/src/processor/stackwalker_mips.cc
+++ b/src/processor/stackwalker_mips.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2013 Google Inc.
-// All rights reserved.
+// Copyright 2013 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -276,7 +275,8 @@ StackFrame* StackwalkerMIPS::GetCallerFrame(const CallStack* stack,
if (TerminateWalk(new_frame->context.epc,
new_frame->context.iregs[MD_CONTEXT_MIPS_REG_SP],
last_frame->context.iregs[MD_CONTEXT_MIPS_REG_SP],
- frames.size() == 1)) {
+ /*first_unwind=*/last_frame->trust ==
+ StackFrame::FRAME_TRUST_CONTEXT)) {
return NULL;
}
diff --git a/src/processor/stackwalker_mips.h b/src/processor/stackwalker_mips.h
index 5f97791f..e9776074 100644
--- a/src/processor/stackwalker_mips.h
+++ b/src/processor/stackwalker_mips.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2013 Google Inc.
-// All rights reserved.
+// Copyright 2013 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/processor/stackwalker_mips64_unittest.cc b/src/processor/stackwalker_mips64_unittest.cc
index 2a9784bf..aefcf8ee 100644
--- a/src/processor/stackwalker_mips64_unittest.cc
+++ b/src/processor/stackwalker_mips64_unittest.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2013, Google Inc.
-// All rights reserved.
+// Copyright 2013 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -65,6 +64,7 @@ using google_breakpad::test_assembler::Section;
using std::vector;
using testing::_;
using testing::AnyNumber;
+using testing::DoAll;
using testing::Return;
using testing::SetArgumentPointee;
using testing::Test;
@@ -644,8 +644,10 @@ struct CFIFixture: public StackwalkerMIPSFixture {
EXPECT_EQ(0x00405000U, frame1->function_base);
}
- // The values we expect to find for the caller's registers.
- MDRawContextMIPS expected;
+ // The values we expect to find for the caller's registers. Forcibly
+ // default-init it, since it's POD and not all bits are always overwritten by
+ // the constructor.
+ MDRawContextMIPS expected{};
// The validity mask for expected.
int expected_validity;
diff --git a/src/processor/stackwalker_mips_unittest.cc b/src/processor/stackwalker_mips_unittest.cc
index a172f17b..ac7324c4 100644
--- a/src/processor/stackwalker_mips_unittest.cc
+++ b/src/processor/stackwalker_mips_unittest.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2013, Google Inc.
-// All rights reserved.
+// Copyright 2013 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -64,6 +63,7 @@ using google_breakpad::test_assembler::Section;
using std::vector;
using testing::_;
using testing::AnyNumber;
+using testing::DoAll;
using testing::Return;
using testing::SetArgumentPointee;
using testing::Test;
diff --git a/src/processor/stackwalker_ppc.cc b/src/processor/stackwalker_ppc.cc
index 1e34c383..e71d9138 100644
--- a/src/processor/stackwalker_ppc.cc
+++ b/src/processor/stackwalker_ppc.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2010 Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -132,10 +131,9 @@ StackFrame* StackwalkerPPC::GetCallerFrame(const CallStack* stack,
frame->trust = StackFrame::FRAME_TRUST_FP;
// Should we terminate the stack walk? (end-of-stack or broken invariant)
- if (TerminateWalk(instruction,
- stack_pointer,
- last_frame->context.gpr[1],
- stack->frames()->size() == 1)) {
+ if (TerminateWalk(instruction, stack_pointer, last_frame->context.gpr[1],
+ /*first_unwind=*/last_frame->trust ==
+ StackFrame::FRAME_TRUST_CONTEXT)) {
return NULL;
}
diff --git a/src/processor/stackwalker_ppc.h b/src/processor/stackwalker_ppc.h
index 012e5c32..182e46d4 100644
--- a/src/processor/stackwalker_ppc.h
+++ b/src/processor/stackwalker_ppc.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2010 Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/processor/stackwalker_ppc64.cc b/src/processor/stackwalker_ppc64.cc
index fb2bac3c..9ac8e45b 100644
--- a/src/processor/stackwalker_ppc64.cc
+++ b/src/processor/stackwalker_ppc64.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2013 Google Inc.
-// All rights reserved.
+// Copyright 2013 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -123,10 +122,9 @@ StackFrame* StackwalkerPPC64::GetCallerFrame(const CallStack* stack,
frame->trust = StackFrame::FRAME_TRUST_FP;
// Should we terminate the stack walk? (end-of-stack or broken invariant)
- if (TerminateWalk(instruction,
- stack_pointer,
- last_frame->context.gpr[1],
- stack->frames()->size() == 1)) {
+ if (TerminateWalk(instruction, stack_pointer, last_frame->context.gpr[1],
+ /*is_context_frame=*/last_frame->trust ==
+ StackFrame::FRAME_TRUST_CONTEXT)) {
return NULL;
}
diff --git a/src/processor/stackwalker_ppc64.h b/src/processor/stackwalker_ppc64.h
index a406343a..ede0b51c 100644
--- a/src/processor/stackwalker_ppc64.h
+++ b/src/processor/stackwalker_ppc64.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2013 Google Inc.
-// All rights reserved.
+// Copyright 2013 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/processor/stackwalker_riscv.cc b/src/processor/stackwalker_riscv.cc
new file mode 100644
index 00000000..3d8a64f4
--- /dev/null
+++ b/src/processor/stackwalker_riscv.cc
@@ -0,0 +1,535 @@
+// Copyright 2013 Google LLC
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google LLC nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+/* stackwalker_riscv.cc: riscv-specific stackwalker.
+ *
+ * See stackwalker_riscv.h for documentation.
+ *
+ * Author: Iacopo Colonnelli
+ */
+
+#include "common/scoped_ptr.h"
+#include "google_breakpad/processor/call_stack.h"
+#include "google_breakpad/processor/code_modules.h"
+#include "google_breakpad/processor/memory_region.h"
+#include "google_breakpad/processor/stack_frame_cpu.h"
+#include "google_breakpad/processor/system_info.h"
+#include "processor/cfi_frame_info.h"
+#include "processor/logging.h"
+#include "processor/stackwalker_riscv.h"
+
+namespace google_breakpad {
+
+StackwalkerRISCV::StackwalkerRISCV(const SystemInfo* system_info,
+ const MDRawContextRISCV* context,
+ MemoryRegion* memory,
+ const CodeModules* modules,
+ StackFrameSymbolizer* resolver_helper)
+ : Stackwalker(system_info, memory, modules, resolver_helper),
+ context_(context),
+ context_frame_validity_(StackFrameRISCV::CONTEXT_VALID_ALL) {
+}
+
+
+StackFrame* StackwalkerRISCV::GetContextFrame() {
+ if (!context_) {
+ BPLOG(ERROR) << "Can't get context frame without context";
+ return NULL;
+ }
+
+ StackFrameRISCV* frame = new StackFrameRISCV();
+
+ frame->context = *context_;
+ frame->context_validity = context_frame_validity_;
+ frame->trust = StackFrame::FRAME_TRUST_CONTEXT;
+ frame->instruction = frame->context.pc;
+
+ return frame;
+}
+
+StackFrameRISCV* StackwalkerRISCV::GetCallerByCFIFrameInfo(
+ const vector<StackFrame*>& frames,
+ CFIFrameInfo* cfi_frame_info) {
+ StackFrameRISCV* last_frame =
+ static_cast<StackFrameRISCV*>(frames.back());
+
+ // Populate a dictionary with the valid register values in last_frame.
+ CFIFrameInfo::RegisterValueMap<uint32_t> callee_registers;
+ if (last_frame->context_validity & StackFrameRISCV::CONTEXT_VALID_PC)
+ callee_registers["pc"] = last_frame->context.pc;
+ if (last_frame->context_validity & StackFrameRISCV::CONTEXT_VALID_RA)
+ callee_registers["ra"] = last_frame->context.ra;
+ if (last_frame->context_validity & StackFrameRISCV::CONTEXT_VALID_SP)
+ callee_registers["sp"] = last_frame->context.sp;
+ if (last_frame->context_validity & StackFrameRISCV::CONTEXT_VALID_GP)
+ callee_registers["gp"] = last_frame->context.gp;
+ if (last_frame->context_validity & StackFrameRISCV::CONTEXT_VALID_TP)
+ callee_registers["tp"] = last_frame->context.tp;
+ if (last_frame->context_validity & StackFrameRISCV::CONTEXT_VALID_T0)
+ callee_registers["t0"] = last_frame->context.t0;
+ if (last_frame->context_validity & StackFrameRISCV::CONTEXT_VALID_T1)
+ callee_registers["t1"] = last_frame->context.t1;
+ if (last_frame->context_validity & StackFrameRISCV::CONTEXT_VALID_T2)
+ callee_registers["t2"] = last_frame->context.t2;
+ if (last_frame->context_validity & StackFrameRISCV::CONTEXT_VALID_S0)
+ callee_registers["s0"] = last_frame->context.s0;
+ if (last_frame->context_validity & StackFrameRISCV::CONTEXT_VALID_S1)
+ callee_registers["s1"] = last_frame->context.s1;
+ if (last_frame->context_validity & StackFrameRISCV::CONTEXT_VALID_A0)
+ callee_registers["a0"] = last_frame->context.a0;
+ if (last_frame->context_validity & StackFrameRISCV::CONTEXT_VALID_A1)
+ callee_registers["a1"] = last_frame->context.a1;
+ if (last_frame->context_validity & StackFrameRISCV::CONTEXT_VALID_A2)
+ callee_registers["a2"] = last_frame->context.a2;
+ if (last_frame->context_validity & StackFrameRISCV::CONTEXT_VALID_A3)
+ callee_registers["a3"] = last_frame->context.a3;
+ if (last_frame->context_validity & StackFrameRISCV::CONTEXT_VALID_A4)
+ callee_registers["a4"] = last_frame->context.a4;
+ if (last_frame->context_validity & StackFrameRISCV::CONTEXT_VALID_A5)
+ callee_registers["a5"] = last_frame->context.a5;
+ if (last_frame->context_validity & StackFrameRISCV::CONTEXT_VALID_A6)
+ callee_registers["a6"] = last_frame->context.a6;
+ if (last_frame->context_validity & StackFrameRISCV::CONTEXT_VALID_A7)
+ callee_registers["a7"] = last_frame->context.a7;
+ if (last_frame->context_validity & StackFrameRISCV::CONTEXT_VALID_S2)
+ callee_registers["s2"] = last_frame->context.s2;
+ if (last_frame->context_validity & StackFrameRISCV::CONTEXT_VALID_S3)
+ callee_registers["s3"] = last_frame->context.s3;
+ if (last_frame->context_validity & StackFrameRISCV::CONTEXT_VALID_S4)
+ callee_registers["s4"] = last_frame->context.s4;
+ if (last_frame->context_validity & StackFrameRISCV::CONTEXT_VALID_S5)
+ callee_registers["s5"] = last_frame->context.s5;
+ if (last_frame->context_validity & StackFrameRISCV::CONTEXT_VALID_S6)
+ callee_registers["s6"] = last_frame->context.s6;
+ if (last_frame->context_validity & StackFrameRISCV::CONTEXT_VALID_S7)
+ callee_registers["s7"] = last_frame->context.s7;
+ if (last_frame->context_validity & StackFrameRISCV::CONTEXT_VALID_S8)
+ callee_registers["s8"] = last_frame->context.s8;
+ if (last_frame->context_validity & StackFrameRISCV::CONTEXT_VALID_S9)
+ callee_registers["s9"] = last_frame->context.s9;
+ if (last_frame->context_validity & StackFrameRISCV::CONTEXT_VALID_S10)
+ callee_registers["s10"] = last_frame->context.s10;
+ if (last_frame->context_validity & StackFrameRISCV::CONTEXT_VALID_S11)
+ callee_registers["s11"] = last_frame->context.s11;
+ if (last_frame->context_validity & StackFrameRISCV::CONTEXT_VALID_T3)
+ callee_registers["t3"] = last_frame->context.t3;
+ if (last_frame->context_validity & StackFrameRISCV::CONTEXT_VALID_T4)
+ callee_registers["t4"] = last_frame->context.t4;
+ if (last_frame->context_validity & StackFrameRISCV::CONTEXT_VALID_T5)
+ callee_registers["t5"] = last_frame->context.t5;
+ if (last_frame->context_validity & StackFrameRISCV::CONTEXT_VALID_T6)
+ callee_registers["t6"] = last_frame->context.t6;
+
+ // Use the STACK CFI data to recover the caller's register values.
+ CFIFrameInfo::RegisterValueMap<uint32_t> caller_registers;
+ if (!cfi_frame_info->FindCallerRegs(callee_registers, *memory_,
+ &caller_registers)) {
+ return NULL;
+ }
+
+ // Construct a new stack frame given the values the CFI recovered.
+ CFIFrameInfo::RegisterValueMap<uint32_t>::iterator entry;
+ scoped_ptr<StackFrameRISCV> frame(new StackFrameRISCV());
+ entry = caller_registers.find("pc");
+ if (entry != caller_registers.end()) {
+ frame->context_validity |= StackFrameRISCV::CONTEXT_VALID_PC;
+ frame->context.pc = entry->second;
+ } else{
+ // If the CFI doesn't recover the PC explicitly, then use .ra.
+ entry = caller_registers.find(".ra");
+ if (entry != caller_registers.end()) {
+ frame->context_validity |= StackFrameRISCV::CONTEXT_VALID_PC;
+ frame->context.pc = entry->second;
+ }
+ }
+ entry = caller_registers.find("ra");
+ if (entry != caller_registers.end()) {
+ frame->context_validity |= StackFrameRISCV::CONTEXT_VALID_RA;
+ frame->context.ra = entry->second;
+ }
+ entry = caller_registers.find("sp");
+ if (entry != caller_registers.end()) {
+ frame->context_validity |= StackFrameRISCV::CONTEXT_VALID_SP;
+ frame->context.sp = entry->second;
+ } else {
+ // If the CFI doesn't recover the SP explicitly, then use .cfa.
+ entry = caller_registers.find(".cfa");
+ if (entry != caller_registers.end()) {
+ frame->context_validity |= StackFrameRISCV::CONTEXT_VALID_SP;
+ frame->context.sp = entry->second;
+ }
+ }
+ entry = caller_registers.find("gp");
+ if (entry != caller_registers.end()) {
+ frame->context_validity |= StackFrameRISCV::CONTEXT_VALID_GP;
+ frame->context.gp = entry->second;
+ }
+ entry = caller_registers.find("tp");
+ if (entry != caller_registers.end()) {
+ frame->context_validity |= StackFrameRISCV::CONTEXT_VALID_TP;
+ frame->context.tp = entry->second;
+ }
+ entry = caller_registers.find("t0");
+ if (entry != caller_registers.end()) {
+ frame->context_validity |= StackFrameRISCV::CONTEXT_VALID_T0;
+ frame->context.t0 = entry->second;
+ }
+ entry = caller_registers.find("t1");
+ if (entry != caller_registers.end()) {
+ frame->context_validity |= StackFrameRISCV::CONTEXT_VALID_T1;
+ frame->context.t1 = entry->second;
+ }
+ entry = caller_registers.find("t2");
+ if (entry != caller_registers.end()) {
+ frame->context_validity |= StackFrameRISCV::CONTEXT_VALID_T2;
+ frame->context.t2 = entry->second;
+ }
+ entry = caller_registers.find("s0");
+ if (entry != caller_registers.end()) {
+ frame->context_validity |= StackFrameRISCV::CONTEXT_VALID_S0;
+ frame->context.s0 = entry->second;
+ } else if (last_frame->context_validity &
+ StackFrameRISCV::CONTEXT_VALID_S0) {
+ // Since the register is callee-saves, assume the callee
+ // has not yet changed it.
+ frame->context_validity |= StackFrameRISCV::CONTEXT_VALID_S0;
+ frame->context.s0 = last_frame->context.s0;
+ }
+ entry = caller_registers.find("s1");
+ if (entry != caller_registers.end()) {
+ frame->context_validity |= StackFrameRISCV::CONTEXT_VALID_S1;
+ frame->context.s1 = entry->second;
+ } else if (last_frame->context_validity &
+ StackFrameRISCV::CONTEXT_VALID_S1) {
+ // Since the register is callee-saves, assume the callee
+ // has not yet changed it.
+ frame->context_validity |= StackFrameRISCV::CONTEXT_VALID_S1;
+ frame->context.s1 = last_frame->context.s1;
+ }
+ entry = caller_registers.find("a0");
+ if (entry != caller_registers.end()) {
+ frame->context_validity |= StackFrameRISCV::CONTEXT_VALID_A0;
+ frame->context.a0 = entry->second;
+ }
+ entry = caller_registers.find("a1");
+ if (entry != caller_registers.end()) {
+ frame->context_validity |= StackFrameRISCV::CONTEXT_VALID_A1;
+ frame->context.a1 = entry->second;
+ }
+ entry = caller_registers.find("a2");
+ if (entry != caller_registers.end()) {
+ frame->context_validity |= StackFrameRISCV::CONTEXT_VALID_A2;
+ frame->context.a2 = entry->second;
+ }
+ entry = caller_registers.find("a3");
+ if (entry != caller_registers.end()) {
+ frame->context_validity |= StackFrameRISCV::CONTEXT_VALID_A3;
+ frame->context.a3 = entry->second;
+ }
+ entry = caller_registers.find("a4");
+ if (entry != caller_registers.end()) {
+ frame->context_validity |= StackFrameRISCV::CONTEXT_VALID_A4;
+ frame->context.a4 = entry->second;
+ }
+ entry = caller_registers.find("a5");
+ if (entry != caller_registers.end()) {
+ frame->context_validity |= StackFrameRISCV::CONTEXT_VALID_A5;
+ frame->context.a5 = entry->second;
+ }
+ entry = caller_registers.find("a6");
+ if (entry != caller_registers.end()) {
+ frame->context_validity |= StackFrameRISCV::CONTEXT_VALID_A6;
+ frame->context.a6 = entry->second;
+ }
+ entry = caller_registers.find("a7");
+ if (entry != caller_registers.end()) {
+ frame->context_validity |= StackFrameRISCV::CONTEXT_VALID_A7;
+ frame->context.a7 = entry->second;
+ }
+ entry = caller_registers.find("s2");
+ if (entry != caller_registers.end()) {
+ frame->context_validity |= StackFrameRISCV::CONTEXT_VALID_S2;
+ frame->context.s2 = entry->second;
+ } else if (last_frame->context_validity &
+ StackFrameRISCV::CONTEXT_VALID_S2) {
+ // Since the register is callee-saves, assume the callee
+ // has not yet changed it.
+ frame->context_validity |= StackFrameRISCV::CONTEXT_VALID_S2;
+ frame->context.s2 = last_frame->context.s2;
+ }
+ entry = caller_registers.find("s3");
+ if (entry != caller_registers.end()) {
+ frame->context_validity |= StackFrameRISCV::CONTEXT_VALID_S3;
+ frame->context.s3 = entry->second;
+ } else if (last_frame->context_validity &
+ StackFrameRISCV::CONTEXT_VALID_S3) {
+ // Since the register is callee-saves, assume the callee
+ // has not yet changed it.
+ frame->context_validity |= StackFrameRISCV::CONTEXT_VALID_S3;
+ frame->context.s3 = last_frame->context.s3;
+ }
+ entry = caller_registers.find("s4");
+ if (entry != caller_registers.end()) {
+ frame->context_validity |= StackFrameRISCV::CONTEXT_VALID_S4;
+ frame->context.s4 = entry->second;
+ } else if (last_frame->context_validity &
+ StackFrameRISCV::CONTEXT_VALID_S4) {
+ // Since the register is callee-saves, assume the callee
+ // has not yet changed it.
+ frame->context_validity |= StackFrameRISCV::CONTEXT_VALID_S4;
+ frame->context.s4 = last_frame->context.s4;
+ }
+ entry = caller_registers.find("s5");
+ if (entry != caller_registers.end()) {
+ frame->context_validity |= StackFrameRISCV::CONTEXT_VALID_S5;
+ frame->context.s5 = entry->second;
+ } else if (last_frame->context_validity &
+ StackFrameRISCV::CONTEXT_VALID_S5) {
+ // Since the register is callee-saves, assume the callee
+ // has not yet changed it.
+ frame->context_validity |= StackFrameRISCV::CONTEXT_VALID_S5;
+ frame->context.s5 = last_frame->context.s5;
+ }
+ entry = caller_registers.find("s6");
+ if (entry != caller_registers.end()) {
+ frame->context_validity |= StackFrameRISCV::CONTEXT_VALID_S6;
+ frame->context.s6 = entry->second;
+ } else if (last_frame->context_validity &
+ StackFrameRISCV::CONTEXT_VALID_S6) {
+ // Since the register is callee-saves, assume the callee
+ // has not yet changed it.
+ frame->context_validity |= StackFrameRISCV::CONTEXT_VALID_S6;
+ frame->context.s6 = last_frame->context.s6;
+ }
+ entry = caller_registers.find("s7");
+ if (entry != caller_registers.end()) {
+ frame->context_validity |= StackFrameRISCV::CONTEXT_VALID_S7;
+ frame->context.s7 = entry->second;
+ } else if (last_frame->context_validity &
+ StackFrameRISCV::CONTEXT_VALID_S7) {
+ // Since the register is callee-saves, assume the callee
+ // has not yet changed it.
+ frame->context_validity |= StackFrameRISCV::CONTEXT_VALID_S7;
+ frame->context.s7 = last_frame->context.s7;
+ }
+ entry = caller_registers.find("s8");
+ if (entry != caller_registers.end()) {
+ frame->context_validity |= StackFrameRISCV::CONTEXT_VALID_S8;
+ frame->context.s8 = entry->second;
+ } else if (last_frame->context_validity &
+ StackFrameRISCV::CONTEXT_VALID_S8) {
+ // Since the register is callee-saves, assume the callee
+ // has not yet changed it.
+ frame->context_validity |= StackFrameRISCV::CONTEXT_VALID_S8;
+ frame->context.s8 = last_frame->context.s8;
+ }
+ entry = caller_registers.find("s9");
+ if (entry != caller_registers.end()) {
+ frame->context_validity |= StackFrameRISCV::CONTEXT_VALID_S9;
+ frame->context.s9 = entry->second;
+ } else if (last_frame->context_validity &
+ StackFrameRISCV::CONTEXT_VALID_S9) {
+ // Since the register is callee-saves, assume the callee
+ // has not yet changed it.
+ frame->context_validity |= StackFrameRISCV::CONTEXT_VALID_S9;
+ frame->context.s9 = last_frame->context.s9;
+ }
+ entry = caller_registers.find("s10");
+ if (entry != caller_registers.end()) {
+ frame->context_validity |= StackFrameRISCV::CONTEXT_VALID_S10;
+ frame->context.s10 = entry->second;
+ } else if (last_frame->context_validity &
+ StackFrameRISCV::CONTEXT_VALID_S10) {
+ // Since the register is callee-saves, assume the callee
+ // has not yet changed it.
+ frame->context_validity |= StackFrameRISCV::CONTEXT_VALID_S10;
+ frame->context.s10 = last_frame->context.s10;
+ }
+ entry = caller_registers.find("s11");
+ if (entry != caller_registers.end()) {
+ frame->context_validity |= StackFrameRISCV::CONTEXT_VALID_S11;
+ frame->context.s11 = entry->second;
+ } else if (last_frame->context_validity &
+ StackFrameRISCV::CONTEXT_VALID_S11) {
+ // Since the register is callee-saves, assume the callee
+ // has not yet changed it.
+ frame->context_validity |= StackFrameRISCV::CONTEXT_VALID_S11;
+ frame->context.s11 = last_frame->context.s11;
+ }
+ entry = caller_registers.find("t3");
+ if (entry != caller_registers.end()) {
+ frame->context_validity |= StackFrameRISCV::CONTEXT_VALID_T3;
+ frame->context.t3 = entry->second;
+ }
+ entry = caller_registers.find("t4");
+ if (entry != caller_registers.end()) {
+ frame->context_validity |= StackFrameRISCV::CONTEXT_VALID_T4;
+ frame->context.t4 = entry->second;
+ }
+ entry = caller_registers.find("t5");
+ if (entry != caller_registers.end()) {
+ frame->context_validity |= StackFrameRISCV::CONTEXT_VALID_T5;
+ frame->context.t5 = entry->second;
+ }
+ entry = caller_registers.find("t6");
+ if (entry != caller_registers.end()) {
+ frame->context_validity |= StackFrameRISCV::CONTEXT_VALID_T6;
+ frame->context.t6 = entry->second;
+ }
+
+ // If we didn't recover the PC and the SP, then the frame isn't very useful.
+ static const uint64_t essentials = (StackFrameRISCV::CONTEXT_VALID_SP
+ | StackFrameRISCV::CONTEXT_VALID_PC);
+ if ((frame->context_validity & essentials) != essentials)
+ return NULL;
+
+ frame->trust = StackFrame::FRAME_TRUST_CFI;
+ return frame.release();
+}
+
+StackFrameRISCV* StackwalkerRISCV::GetCallerByStackScan(
+ const vector<StackFrame*>& frames) {
+ StackFrameRISCV* last_frame =
+ static_cast<StackFrameRISCV*>(frames.back());
+ uint32_t last_sp = last_frame->context.sp;
+ uint32_t caller_sp, caller_pc;
+
+ if (!ScanForReturnAddress(last_sp, &caller_sp, &caller_pc,
+ last_frame->trust == StackFrame::FRAME_TRUST_CONTEXT)) {
+ // No plausible return address was found.
+ return NULL;
+ }
+
+ // ScanForReturnAddress found a reasonable return address. Advance
+ // sp to the location above the one where the return address was
+ // found.
+ caller_sp += 4;
+
+ // Create a new stack frame (ownership will be transferred to the caller)
+ // and fill it in.
+ StackFrameRISCV* frame = new StackFrameRISCV();
+
+ frame->trust = StackFrame::FRAME_TRUST_SCAN;
+ frame->context = last_frame->context;
+ frame->context.pc = caller_pc;
+ frame->context.sp = caller_sp;
+ frame->context_validity = StackFrameRISCV::CONTEXT_VALID_PC |
+ StackFrameRISCV::CONTEXT_VALID_SP;
+
+ return frame;
+}
+
+ StackFrameRISCV* StackwalkerRISCV::GetCallerByFramePointer(
+ const vector<StackFrame*>& frames) {
+ StackFrameRISCV* last_frame =
+ static_cast<StackFrameRISCV*>(frames.back());
+
+ uint32_t last_fp = last_frame->context.s0;
+
+ uint32_t caller_fp = 0;
+ if (last_fp && !memory_->GetMemoryAtAddress(last_fp, &caller_fp)) {
+ BPLOG(ERROR) << "Unable to read caller_fp from last_fp: 0x"
+ << std::hex << last_fp;
+ return NULL;
+ }
+
+ uint32_t caller_ra = 0;
+ if (last_fp && !memory_->GetMemoryAtAddress(last_fp + 4, &caller_ra)) {
+ BPLOG(ERROR) << "Unable to read caller_ra from last_fp + 4: 0x"
+ << std::hex << (last_fp + 4);
+ return NULL;
+ }
+
+ uint32_t caller_sp = last_fp ? last_fp + 8 : last_frame->context.s0;
+
+ // Create a new stack frame (ownership will be transferred to the caller)
+ // and fill it in.
+ StackFrameRISCV* frame = new StackFrameRISCV();
+
+ frame->trust = StackFrame::FRAME_TRUST_FP;
+ frame->context = last_frame->context;
+ frame->context.s0 = caller_fp;
+ frame->context.sp = caller_sp;
+ frame->context.pc = last_frame->context.ra;
+ frame->context.ra = caller_ra;
+ frame->context_validity = StackFrameRISCV::CONTEXT_VALID_PC |
+ StackFrameRISCV::CONTEXT_VALID_RA |
+ StackFrameRISCV::CONTEXT_VALID_S0 |
+ StackFrameRISCV::CONTEXT_VALID_SP;
+ return frame;
+}
+
+StackFrame* StackwalkerRISCV::GetCallerFrame(const CallStack* stack,
+ bool stack_scan_allowed) {
+ if (!memory_ || !stack) {
+ BPLOG(ERROR) << "Can't get caller frame without memory or stack";
+ return NULL;
+ }
+
+ const vector<StackFrame*>& frames = *stack->frames();
+ StackFrameRISCV* last_frame =
+ static_cast<StackFrameRISCV*>(frames.back());
+ scoped_ptr<StackFrameRISCV> frame;
+
+ // Try to recover caller information from CFI.
+ scoped_ptr<CFIFrameInfo> cfi_frame_info(
+ frame_symbolizer_->FindCFIFrameInfo(last_frame));
+ if (cfi_frame_info.get())
+ frame.reset(GetCallerByCFIFrameInfo(frames, cfi_frame_info.get()));
+
+ // If CFI failed, or there wasn't CFI available, fall back to frame pointer.
+ if (!frame.get())
+ frame.reset(GetCallerByFramePointer(frames));
+
+ // If everything failed, fall back to stack scanning.
+ if (stack_scan_allowed && !frame.get())
+ frame.reset(GetCallerByStackScan(frames));
+
+ // If nothing worked, tell the caller.
+ if (!frame.get())
+ return NULL;
+
+ // Should we terminate the stack walk? (end-of-stack or broken invariant)
+ if (TerminateWalk(frame->context.pc, frame->context.sp,
+ last_frame->context.sp,
+ last_frame->trust == StackFrame::FRAME_TRUST_CONTEXT)) {
+ return NULL;
+ }
+
+ // The new frame's context's PC is the return address, which is one
+ // instruction past the instruction that caused us to arrive at the callee.
+ // RISCV instructions have a uniform 4-byte encoding, so subtracting 4 off
+ // the return address gets back to the beginning of the call instruction.
+ // Callers that require the exact return address value may access
+ // frame->context.pc.
+ frame->instruction = frame->context.pc - 4;
+
+ return frame.release();
+}
+
+} // namespace google_breakpad
diff --git a/src/processor/stackwalker_riscv.h b/src/processor/stackwalker_riscv.h
new file mode 100644
index 00000000..863914d8
--- /dev/null
+++ b/src/processor/stackwalker_riscv.h
@@ -0,0 +1,100 @@
+// Copyright 2013 Google LLC
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google LLC nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+/* stackwalker_riscv.h: riscv-specific stackwalker.
+ *
+ * Provides stack frames given riscv register context and a memory region
+ * corresponding to a riscv stack.
+ *
+ * Author: Iacopo Colonnelli
+ */
+
+#ifndef PROCESSOR_STACKWALKER_RISCV_H__
+#define PROCESSOR_STACKWALKER_RISCV_H__
+
+#include "google_breakpad/common/minidump_format.h"
+#include "google_breakpad/processor/stackwalker.h"
+
+namespace google_breakpad {
+
+class CodeModules;
+
+class StackwalkerRISCV : public Stackwalker {
+public:
+ // Context is a riscv context object that gives access to riscv-specific
+ // register state corresponding to the innermost called frame to be
+ // included in the stack. The other arguments are passed directly
+ // through to the base Stackwalker constructor.
+ StackwalkerRISCV(const SystemInfo* system_info,
+ const MDRawContextRISCV* context,
+ MemoryRegion* memory,
+ const CodeModules* modules,
+ StackFrameSymbolizer* frame_symbolizer);
+
+ // Change the context validity mask of the frame returned by
+ // GetContextFrame to VALID. This is only for use by unit tests; the
+ // default behavior is correct for all application code.
+ void SetContextFrameValidity(int valid) {
+ context_frame_validity_ = valid;
+ }
+
+private:
+ // Implementation of Stackwalker, using riscv context and stack conventions.
+ virtual StackFrame* GetContextFrame();
+ virtual StackFrame* GetCallerFrame(
+ const CallStack* stack, bool stack_scan_allowed);
+
+ // Use cfi_frame_info (derived from STACK CFI records) to construct
+ // the frame that called frames.back(). The caller takes ownership
+ // of the returned frame. Return NULL on failure.
+ StackFrameRISCV* GetCallerByCFIFrameInfo(
+ const vector<StackFrame*>& frames, CFIFrameInfo* cfi_frame_info);
+
+ // Use the frame pointer. The caller takes ownership of the returned frame.
+ // Return NULL on failure.
+ StackFrameRISCV* GetCallerByFramePointer(
+ const vector<StackFrame*>& frames);
+
+ // Scan the stack for plausible return addresses. The caller takes ownership
+ // of the returned frame. Return NULL on failure.
+ StackFrameRISCV* GetCallerByStackScan(
+ const vector<StackFrame*>& frames);
+
+ // Stores the CPU context corresponding to the innermost stack frame to
+ // be returned by GetContextFrame.
+ const MDRawContextRISCV* context_;
+
+ // Validity mask for youngest stack frame. This is always
+ // CONTEXT_VALID_ALL in real use; it is only changeable for the sake of
+ // unit tests.
+ int context_frame_validity_;
+};
+
+} // namespace google_breakpad
+
+#endif // PROCESSOR_STACKWALKER_RISCV_H__
diff --git a/src/processor/stackwalker_riscv64.cc b/src/processor/stackwalker_riscv64.cc
new file mode 100644
index 00000000..d97bad63
--- /dev/null
+++ b/src/processor/stackwalker_riscv64.cc
@@ -0,0 +1,535 @@
+// Copyright 2013 Google LLC
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google LLC nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+/* stackwalker_riscv64.cc: riscv64-specific stackwalker.
+ *
+ * See stackwalker_riscv64.h for documentation.
+ *
+ * Author: Iacopo Colonnelli
+ */
+
+#include "common/scoped_ptr.h"
+#include "google_breakpad/processor/call_stack.h"
+#include "google_breakpad/processor/code_modules.h"
+#include "google_breakpad/processor/memory_region.h"
+#include "google_breakpad/processor/stack_frame_cpu.h"
+#include "google_breakpad/processor/system_info.h"
+#include "processor/cfi_frame_info.h"
+#include "processor/logging.h"
+#include "processor/stackwalker_riscv64.h"
+
+namespace google_breakpad {
+
+StackwalkerRISCV64::StackwalkerRISCV64(const SystemInfo* system_info,
+ const MDRawContextRISCV64* context,
+ MemoryRegion* memory,
+ const CodeModules* modules,
+ StackFrameSymbolizer* resolver_helper)
+ : Stackwalker(system_info, memory, modules, resolver_helper),
+ context_(context),
+ context_frame_validity_(StackFrameRISCV::CONTEXT_VALID_ALL) {
+}
+
+
+StackFrame* StackwalkerRISCV64::GetContextFrame() {
+ if (!context_) {
+ BPLOG(ERROR) << "Can't get context frame without context";
+ return NULL;
+ }
+
+ StackFrameRISCV64* frame = new StackFrameRISCV64();
+
+ frame->context = *context_;
+ frame->context_validity = context_frame_validity_;
+ frame->trust = StackFrame::FRAME_TRUST_CONTEXT;
+ frame->instruction = frame->context.pc;
+
+ return frame;
+}
+
+StackFrameRISCV64* StackwalkerRISCV64::GetCallerByCFIFrameInfo(
+ const vector<StackFrame*>& frames,
+ CFIFrameInfo* cfi_frame_info) {
+ StackFrameRISCV64* last_frame =
+ static_cast<StackFrameRISCV64*>(frames.back());
+
+ // Populate a dictionary with the valid register values in last_frame.
+ CFIFrameInfo::RegisterValueMap<uint64_t> callee_registers;
+ if (last_frame->context_validity & StackFrameRISCV64::CONTEXT_VALID_PC)
+ callee_registers["pc"] = last_frame->context.pc;
+ if (last_frame->context_validity & StackFrameRISCV64::CONTEXT_VALID_RA)
+ callee_registers["ra"] = last_frame->context.ra;
+ if (last_frame->context_validity & StackFrameRISCV64::CONTEXT_VALID_SP)
+ callee_registers["sp"] = last_frame->context.sp;
+ if (last_frame->context_validity & StackFrameRISCV64::CONTEXT_VALID_GP)
+ callee_registers["gp"] = last_frame->context.gp;
+ if (last_frame->context_validity & StackFrameRISCV64::CONTEXT_VALID_TP)
+ callee_registers["tp"] = last_frame->context.tp;
+ if (last_frame->context_validity & StackFrameRISCV64::CONTEXT_VALID_T0)
+ callee_registers["t0"] = last_frame->context.t0;
+ if (last_frame->context_validity & StackFrameRISCV64::CONTEXT_VALID_T1)
+ callee_registers["t1"] = last_frame->context.t1;
+ if (last_frame->context_validity & StackFrameRISCV64::CONTEXT_VALID_T2)
+ callee_registers["t2"] = last_frame->context.t2;
+ if (last_frame->context_validity & StackFrameRISCV64::CONTEXT_VALID_S0)
+ callee_registers["s0"] = last_frame->context.s0;
+ if (last_frame->context_validity & StackFrameRISCV64::CONTEXT_VALID_S1)
+ callee_registers["s1"] = last_frame->context.s1;
+ if (last_frame->context_validity & StackFrameRISCV64::CONTEXT_VALID_A0)
+ callee_registers["a0"] = last_frame->context.a0;
+ if (last_frame->context_validity & StackFrameRISCV64::CONTEXT_VALID_A1)
+ callee_registers["a1"] = last_frame->context.a1;
+ if (last_frame->context_validity & StackFrameRISCV64::CONTEXT_VALID_A2)
+ callee_registers["a2"] = last_frame->context.a2;
+ if (last_frame->context_validity & StackFrameRISCV64::CONTEXT_VALID_A3)
+ callee_registers["a3"] = last_frame->context.a3;
+ if (last_frame->context_validity & StackFrameRISCV64::CONTEXT_VALID_A4)
+ callee_registers["a4"] = last_frame->context.a4;
+ if (last_frame->context_validity & StackFrameRISCV64::CONTEXT_VALID_A5)
+ callee_registers["a5"] = last_frame->context.a5;
+ if (last_frame->context_validity & StackFrameRISCV64::CONTEXT_VALID_A6)
+ callee_registers["a6"] = last_frame->context.a6;
+ if (last_frame->context_validity & StackFrameRISCV64::CONTEXT_VALID_A7)
+ callee_registers["a7"] = last_frame->context.a7;
+ if (last_frame->context_validity & StackFrameRISCV64::CONTEXT_VALID_S2)
+ callee_registers["s2"] = last_frame->context.s2;
+ if (last_frame->context_validity & StackFrameRISCV64::CONTEXT_VALID_S3)
+ callee_registers["s3"] = last_frame->context.s3;
+ if (last_frame->context_validity & StackFrameRISCV64::CONTEXT_VALID_S4)
+ callee_registers["s4"] = last_frame->context.s4;
+ if (last_frame->context_validity & StackFrameRISCV64::CONTEXT_VALID_S5)
+ callee_registers["s5"] = last_frame->context.s5;
+ if (last_frame->context_validity & StackFrameRISCV64::CONTEXT_VALID_S6)
+ callee_registers["s6"] = last_frame->context.s6;
+ if (last_frame->context_validity & StackFrameRISCV64::CONTEXT_VALID_S7)
+ callee_registers["s7"] = last_frame->context.s7;
+ if (last_frame->context_validity & StackFrameRISCV64::CONTEXT_VALID_S8)
+ callee_registers["s8"] = last_frame->context.s8;
+ if (last_frame->context_validity & StackFrameRISCV64::CONTEXT_VALID_S9)
+ callee_registers["s9"] = last_frame->context.s9;
+ if (last_frame->context_validity & StackFrameRISCV64::CONTEXT_VALID_S10)
+ callee_registers["s10"] = last_frame->context.s10;
+ if (last_frame->context_validity & StackFrameRISCV64::CONTEXT_VALID_S11)
+ callee_registers["s11"] = last_frame->context.s11;
+ if (last_frame->context_validity & StackFrameRISCV64::CONTEXT_VALID_T3)
+ callee_registers["t3"] = last_frame->context.t3;
+ if (last_frame->context_validity & StackFrameRISCV64::CONTEXT_VALID_T4)
+ callee_registers["t4"] = last_frame->context.t4;
+ if (last_frame->context_validity & StackFrameRISCV64::CONTEXT_VALID_T5)
+ callee_registers["t5"] = last_frame->context.t5;
+ if (last_frame->context_validity & StackFrameRISCV64::CONTEXT_VALID_T6)
+ callee_registers["t6"] = last_frame->context.t6;
+
+ // Use the STACK CFI data to recover the caller's register values.
+ CFIFrameInfo::RegisterValueMap<uint64_t> caller_registers;
+ if (!cfi_frame_info->FindCallerRegs(callee_registers, *memory_,
+ &caller_registers)) {
+ return NULL;
+ }
+
+ // Construct a new stack frame given the values the CFI recovered.
+ CFIFrameInfo::RegisterValueMap<uint64_t>::iterator entry;
+ scoped_ptr<StackFrameRISCV64> frame(new StackFrameRISCV64());
+ entry = caller_registers.find("pc");
+ if (entry != caller_registers.end()) {
+ frame->context_validity |= StackFrameRISCV64::CONTEXT_VALID_PC;
+ frame->context.pc = entry->second;
+ } else{
+ // If the CFI doesn't recover the PC explicitly, then use .ra.
+ entry = caller_registers.find(".ra");
+ if (entry != caller_registers.end()) {
+ frame->context_validity |= StackFrameRISCV64::CONTEXT_VALID_PC;
+ frame->context.pc = entry->second;
+ }
+ }
+ entry = caller_registers.find("ra");
+ if (entry != caller_registers.end()) {
+ frame->context_validity |= StackFrameRISCV64::CONTEXT_VALID_RA;
+ frame->context.ra = entry->second;
+ }
+ entry = caller_registers.find("sp");
+ if (entry != caller_registers.end()) {
+ frame->context_validity |= StackFrameRISCV64::CONTEXT_VALID_SP;
+ frame->context.sp = entry->second;
+ } else {
+ // If the CFI doesn't recover the SP explicitly, then use .cfa.
+ entry = caller_registers.find(".cfa");
+ if (entry != caller_registers.end()) {
+ frame->context_validity |= StackFrameRISCV64::CONTEXT_VALID_SP;
+ frame->context.sp = entry->second;
+ }
+ }
+ entry = caller_registers.find("gp");
+ if (entry != caller_registers.end()) {
+ frame->context_validity |= StackFrameRISCV64::CONTEXT_VALID_GP;
+ frame->context.gp = entry->second;
+ }
+ entry = caller_registers.find("tp");
+ if (entry != caller_registers.end()) {
+ frame->context_validity |= StackFrameRISCV64::CONTEXT_VALID_TP;
+ frame->context.tp = entry->second;
+ }
+ entry = caller_registers.find("t0");
+ if (entry != caller_registers.end()) {
+ frame->context_validity |= StackFrameRISCV64::CONTEXT_VALID_T0;
+ frame->context.t0 = entry->second;
+ }
+ entry = caller_registers.find("t1");
+ if (entry != caller_registers.end()) {
+ frame->context_validity |= StackFrameRISCV64::CONTEXT_VALID_T1;
+ frame->context.t1 = entry->second;
+ }
+ entry = caller_registers.find("t2");
+ if (entry != caller_registers.end()) {
+ frame->context_validity |= StackFrameRISCV64::CONTEXT_VALID_T2;
+ frame->context.t2 = entry->second;
+ }
+ entry = caller_registers.find("s0");
+ if (entry != caller_registers.end()) {
+ frame->context_validity |= StackFrameRISCV64::CONTEXT_VALID_S0;
+ frame->context.s0 = entry->second;
+ } else if (last_frame->context_validity &
+ StackFrameRISCV64::CONTEXT_VALID_S0) {
+ // Since the register is callee-saves, assume the callee
+ // has not yet changed it.
+ frame->context_validity |= StackFrameRISCV64::CONTEXT_VALID_S0;
+ frame->context.s0 = last_frame->context.s0;
+ }
+ entry = caller_registers.find("s1");
+ if (entry != caller_registers.end()) {
+ frame->context_validity |= StackFrameRISCV64::CONTEXT_VALID_S1;
+ frame->context.s1 = entry->second;
+ } else if (last_frame->context_validity &
+ StackFrameRISCV64::CONTEXT_VALID_S1) {
+ // Since the register is callee-saves, assume the callee
+ // has not yet changed it.
+ frame->context_validity |= StackFrameRISCV64::CONTEXT_VALID_S1;
+ frame->context.s1 = last_frame->context.s1;
+ }
+ entry = caller_registers.find("a0");
+ if (entry != caller_registers.end()) {
+ frame->context_validity |= StackFrameRISCV64::CONTEXT_VALID_A0;
+ frame->context.a0 = entry->second;
+ }
+ entry = caller_registers.find("a1");
+ if (entry != caller_registers.end()) {
+ frame->context_validity |= StackFrameRISCV64::CONTEXT_VALID_A1;
+ frame->context.a1 = entry->second;
+ }
+ entry = caller_registers.find("a2");
+ if (entry != caller_registers.end()) {
+ frame->context_validity |= StackFrameRISCV64::CONTEXT_VALID_A2;
+ frame->context.a2 = entry->second;
+ }
+ entry = caller_registers.find("a3");
+ if (entry != caller_registers.end()) {
+ frame->context_validity |= StackFrameRISCV64::CONTEXT_VALID_A3;
+ frame->context.a3 = entry->second;
+ }
+ entry = caller_registers.find("a4");
+ if (entry != caller_registers.end()) {
+ frame->context_validity |= StackFrameRISCV64::CONTEXT_VALID_A4;
+ frame->context.a4 = entry->second;
+ }
+ entry = caller_registers.find("a5");
+ if (entry != caller_registers.end()) {
+ frame->context_validity |= StackFrameRISCV64::CONTEXT_VALID_A5;
+ frame->context.a5 = entry->second;
+ }
+ entry = caller_registers.find("a6");
+ if (entry != caller_registers.end()) {
+ frame->context_validity |= StackFrameRISCV64::CONTEXT_VALID_A6;
+ frame->context.a6 = entry->second;
+ }
+ entry = caller_registers.find("a7");
+ if (entry != caller_registers.end()) {
+ frame->context_validity |= StackFrameRISCV64::CONTEXT_VALID_A7;
+ frame->context.a7 = entry->second;
+ }
+ entry = caller_registers.find("s2");
+ if (entry != caller_registers.end()) {
+ frame->context_validity |= StackFrameRISCV64::CONTEXT_VALID_S2;
+ frame->context.s2 = entry->second;
+ } else if (last_frame->context_validity &
+ StackFrameRISCV64::CONTEXT_VALID_S2) {
+ // Since the register is callee-saves, assume the callee
+ // has not yet changed it.
+ frame->context_validity |= StackFrameRISCV64::CONTEXT_VALID_S2;
+ frame->context.s2 = last_frame->context.s2;
+ }
+ entry = caller_registers.find("s3");
+ if (entry != caller_registers.end()) {
+ frame->context_validity |= StackFrameRISCV64::CONTEXT_VALID_S3;
+ frame->context.s3 = entry->second;
+ } else if (last_frame->context_validity &
+ StackFrameRISCV64::CONTEXT_VALID_S3) {
+ // Since the register is callee-saves, assume the callee
+ // has not yet changed it.
+ frame->context_validity |= StackFrameRISCV64::CONTEXT_VALID_S3;
+ frame->context.s3 = last_frame->context.s3;
+ }
+ entry = caller_registers.find("s4");
+ if (entry != caller_registers.end()) {
+ frame->context_validity |= StackFrameRISCV64::CONTEXT_VALID_S4;
+ frame->context.s4 = entry->second;
+ } else if (last_frame->context_validity &
+ StackFrameRISCV64::CONTEXT_VALID_S4) {
+ // Since the register is callee-saves, assume the callee
+ // has not yet changed it.
+ frame->context_validity |= StackFrameRISCV64::CONTEXT_VALID_S4;
+ frame->context.s4 = last_frame->context.s4;
+ }
+ entry = caller_registers.find("s5");
+ if (entry != caller_registers.end()) {
+ frame->context_validity |= StackFrameRISCV64::CONTEXT_VALID_S5;
+ frame->context.s5 = entry->second;
+ } else if (last_frame->context_validity &
+ StackFrameRISCV64::CONTEXT_VALID_S5) {
+ // Since the register is callee-saves, assume the callee
+ // has not yet changed it.
+ frame->context_validity |= StackFrameRISCV64::CONTEXT_VALID_S5;
+ frame->context.s5 = last_frame->context.s5;
+ }
+ entry = caller_registers.find("s6");
+ if (entry != caller_registers.end()) {
+ frame->context_validity |= StackFrameRISCV64::CONTEXT_VALID_S6;
+ frame->context.s6 = entry->second;
+ } else if (last_frame->context_validity &
+ StackFrameRISCV64::CONTEXT_VALID_S6) {
+ // Since the register is callee-saves, assume the callee
+ // has not yet changed it.
+ frame->context_validity |= StackFrameRISCV64::CONTEXT_VALID_S6;
+ frame->context.s6 = last_frame->context.s6;
+ }
+ entry = caller_registers.find("s7");
+ if (entry != caller_registers.end()) {
+ frame->context_validity |= StackFrameRISCV64::CONTEXT_VALID_S7;
+ frame->context.s7 = entry->second;
+ } else if (last_frame->context_validity &
+ StackFrameRISCV64::CONTEXT_VALID_S7) {
+ // Since the register is callee-saves, assume the callee
+ // has not yet changed it.
+ frame->context_validity |= StackFrameRISCV64::CONTEXT_VALID_S7;
+ frame->context.s7 = last_frame->context.s7;
+ }
+ entry = caller_registers.find("s8");
+ if (entry != caller_registers.end()) {
+ frame->context_validity |= StackFrameRISCV64::CONTEXT_VALID_S8;
+ frame->context.s8 = entry->second;
+ } else if (last_frame->context_validity &
+ StackFrameRISCV64::CONTEXT_VALID_S8) {
+ // Since the register is callee-saves, assume the callee
+ // has not yet changed it.
+ frame->context_validity |= StackFrameRISCV64::CONTEXT_VALID_S8;
+ frame->context.s8 = last_frame->context.s8;
+ }
+ entry = caller_registers.find("s9");
+ if (entry != caller_registers.end()) {
+ frame->context_validity |= StackFrameRISCV64::CONTEXT_VALID_S9;
+ frame->context.s9 = entry->second;
+ } else if (last_frame->context_validity &
+ StackFrameRISCV64::CONTEXT_VALID_S9) {
+ // Since the register is callee-saves, assume the callee
+ // has not yet changed it.
+ frame->context_validity |= StackFrameRISCV64::CONTEXT_VALID_S9;
+ frame->context.s9 = last_frame->context.s9;
+ }
+ entry = caller_registers.find("s10");
+ if (entry != caller_registers.end()) {
+ frame->context_validity |= StackFrameRISCV64::CONTEXT_VALID_S10;
+ frame->context.s10 = entry->second;
+ } else if (last_frame->context_validity &
+ StackFrameRISCV64::CONTEXT_VALID_S10) {
+ // Since the register is callee-saves, assume the callee
+ // has not yet changed it.
+ frame->context_validity |= StackFrameRISCV64::CONTEXT_VALID_S10;
+ frame->context.s10 = last_frame->context.s10;
+ }
+ entry = caller_registers.find("s11");
+ if (entry != caller_registers.end()) {
+ frame->context_validity |= StackFrameRISCV64::CONTEXT_VALID_S11;
+ frame->context.s11 = entry->second;
+ } else if (last_frame->context_validity &
+ StackFrameRISCV64::CONTEXT_VALID_S11) {
+ // Since the register is callee-saves, assume the callee
+ // has not yet changed it.
+ frame->context_validity |= StackFrameRISCV64::CONTEXT_VALID_S11;
+ frame->context.s11 = last_frame->context.s11;
+ }
+ entry = caller_registers.find("t3");
+ if (entry != caller_registers.end()) {
+ frame->context_validity |= StackFrameRISCV64::CONTEXT_VALID_T3;
+ frame->context.t3 = entry->second;
+ }
+ entry = caller_registers.find("t4");
+ if (entry != caller_registers.end()) {
+ frame->context_validity |= StackFrameRISCV64::CONTEXT_VALID_T4;
+ frame->context.t4 = entry->second;
+ }
+ entry = caller_registers.find("t5");
+ if (entry != caller_registers.end()) {
+ frame->context_validity |= StackFrameRISCV64::CONTEXT_VALID_T5;
+ frame->context.t5 = entry->second;
+ }
+ entry = caller_registers.find("t6");
+ if (entry != caller_registers.end()) {
+ frame->context_validity |= StackFrameRISCV64::CONTEXT_VALID_T6;
+ frame->context.t6 = entry->second;
+ }
+
+ // If we didn't recover the PC and the SP, then the frame isn't very useful.
+ static const uint64_t essentials = (StackFrameRISCV64::CONTEXT_VALID_SP
+ | StackFrameRISCV64::CONTEXT_VALID_PC);
+ if ((frame->context_validity & essentials) != essentials)
+ return NULL;
+
+ frame->trust = StackFrame::FRAME_TRUST_CFI;
+ return frame.release();
+}
+
+StackFrameRISCV64* StackwalkerRISCV64::GetCallerByStackScan(
+ const vector<StackFrame*>& frames) {
+ StackFrameRISCV64* last_frame =
+ static_cast<StackFrameRISCV64*>(frames.back());
+ uint64_t last_sp = last_frame->context.sp;
+ uint64_t caller_sp, caller_pc;
+
+ if (!ScanForReturnAddress(last_sp, &caller_sp, &caller_pc,
+ last_frame->trust == StackFrame::FRAME_TRUST_CONTEXT)) {
+ // No plausible return address was found.
+ return NULL;
+ }
+
+ // ScanForReturnAddress found a reasonable return address. Advance
+ // sp to the location above the one where the return address was
+ // found.
+ caller_sp += 8;
+
+ // Create a new stack frame (ownership will be transferred to the caller)
+ // and fill it in.
+ StackFrameRISCV64* frame = new StackFrameRISCV64();
+
+ frame->trust = StackFrame::FRAME_TRUST_SCAN;
+ frame->context = last_frame->context;
+ frame->context.pc = caller_pc;
+ frame->context.sp = caller_sp;
+ frame->context_validity = StackFrameRISCV64::CONTEXT_VALID_PC |
+ StackFrameRISCV64::CONTEXT_VALID_SP;
+
+ return frame;
+}
+
+StackFrameRISCV64* StackwalkerRISCV64::GetCallerByFramePointer(
+ const vector<StackFrame*>& frames) {
+ StackFrameRISCV64* last_frame =
+ static_cast<StackFrameRISCV64*>(frames.back());
+
+ uint64_t last_fp = last_frame->context.s0;
+
+ uint64_t caller_fp = 0;
+ if (last_fp && !memory_->GetMemoryAtAddress(last_fp, &caller_fp)) {
+ BPLOG(ERROR) << "Unable to read caller_fp from last_fp: 0x"
+ << std::hex << last_fp;
+ return NULL;
+ }
+
+ uint64_t caller_ra = 0;
+ if (last_fp && !memory_->GetMemoryAtAddress(last_fp + 8, &caller_ra)) {
+ BPLOG(ERROR) << "Unable to read caller_ra from last_fp + 8: 0x"
+ << std::hex << (last_fp + 8);
+ return NULL;
+ }
+
+ uint64_t caller_sp = last_fp ? last_fp + 16 : last_frame->context.s0;
+
+ // Create a new stack frame (ownership will be transferred to the caller)
+ // and fill it in.
+ StackFrameRISCV64* frame = new StackFrameRISCV64();
+
+ frame->trust = StackFrame::FRAME_TRUST_FP;
+ frame->context = last_frame->context;
+ frame->context.s0 = caller_fp;
+ frame->context.sp = caller_sp;
+ frame->context.pc = last_frame->context.ra;
+ frame->context.ra = caller_ra;
+ frame->context_validity = StackFrameRISCV64::CONTEXT_VALID_PC |
+ StackFrameRISCV64::CONTEXT_VALID_RA |
+ StackFrameRISCV64::CONTEXT_VALID_S0 |
+ StackFrameRISCV64::CONTEXT_VALID_SP;
+ return frame;
+}
+
+StackFrame* StackwalkerRISCV64::GetCallerFrame(const CallStack* stack,
+ bool stack_scan_allowed) {
+ if (!memory_ || !stack) {
+ BPLOG(ERROR) << "Can't get caller frame without memory or stack";
+ return NULL;
+ }
+
+ const vector<StackFrame*>& frames = *stack->frames();
+ StackFrameRISCV64* last_frame =
+ static_cast<StackFrameRISCV64*>(frames.back());
+ scoped_ptr<StackFrameRISCV64> frame;
+
+ // Try to recover caller information from CFI.
+ scoped_ptr<CFIFrameInfo> cfi_frame_info(
+ frame_symbolizer_->FindCFIFrameInfo(last_frame));
+ if (cfi_frame_info.get())
+ frame.reset(GetCallerByCFIFrameInfo(frames, cfi_frame_info.get()));
+
+ // If CFI failed, or there wasn't CFI available, fall back to frame pointer.
+ if (!frame.get())
+ frame.reset(GetCallerByFramePointer(frames));
+
+ // If everything failed, fall back to stack scanning.
+ if (stack_scan_allowed && !frame.get())
+ frame.reset(GetCallerByStackScan(frames));
+
+ // If nothing worked, tell the caller.
+ if (!frame.get())
+ return NULL;
+
+ // Should we terminate the stack walk? (end-of-stack or broken invariant)
+ if (TerminateWalk(frame->context.pc, frame->context.sp,
+ last_frame->context.sp,
+ last_frame->trust == StackFrame::FRAME_TRUST_CONTEXT)) {
+ return NULL;
+ }
+
+ // The new frame's context's PC is the return address, which is one
+ // instruction past the instruction that caused us to arrive at the callee.
+ // RISCV instructions have a uniform 4-byte encoding, so subtracting 4 off
+ // the return address gets back to the beginning of the call instruction.
+ // Callers that require the exact return address value may access
+ // frame->context.pc.
+ frame->instruction = frame->context.pc - 4;
+
+ return frame.release();
+}
+
+} // namespace google_breakpad
diff --git a/src/processor/stackwalker_riscv64.h b/src/processor/stackwalker_riscv64.h
new file mode 100644
index 00000000..89ab12ff
--- /dev/null
+++ b/src/processor/stackwalker_riscv64.h
@@ -0,0 +1,100 @@
+// Copyright 2013 Google LLC
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google LLC nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+/* stackwalker_riscv64.h: riscv64-specific stackwalker.
+ *
+ * Provides stack frames given riscv64 register context and a memory region
+ * corresponding to a riscv64 stack.
+ *
+ * Author: Iacopo Colonnelli
+ */
+
+#ifndef PROCESSOR_STACKWALKER_RISCV64_H__
+#define PROCESSOR_STACKWALKER_RISCV64_H__
+
+#include "google_breakpad/common/minidump_format.h"
+#include "google_breakpad/processor/stackwalker.h"
+
+namespace google_breakpad {
+
+class CodeModules;
+
+class StackwalkerRISCV64 : public Stackwalker {
+public:
+ // Context is a riscv context object that gives access to riscv-specific
+ // register state corresponding to the innermost called frame to be
+ // included in the stack. The other arguments are passed directly
+ // through to the base Stackwalker constructor.
+ StackwalkerRISCV64(const SystemInfo* system_info,
+ const MDRawContextRISCV64* context,
+ MemoryRegion* memory,
+ const CodeModules* modules,
+ StackFrameSymbolizer* frame_symbolizer);
+
+ // Change the context validity mask of the frame returned by
+ // GetContextFrame to VALID. This is only for use by unit tests; the
+ // default behavior is correct for all application code.
+ void SetContextFrameValidity(int valid) {
+ context_frame_validity_ = valid;
+ }
+
+private:
+ // Implementation of Stackwalker, using riscv context and stack conventions.
+ virtual StackFrame* GetContextFrame();
+ virtual StackFrame* GetCallerFrame(
+ const CallStack* stack, bool stack_scan_allowed);
+
+ // Use cfi_frame_info (derived from STACK CFI records) to construct
+ // the frame that called frames.back(). The caller takes ownership
+ // of the returned frame. Return NULL on failure.
+ StackFrameRISCV64* GetCallerByCFIFrameInfo(
+ const vector<StackFrame*>& frames, CFIFrameInfo* cfi_frame_info);
+
+ // Use the frame pointer. The caller takes ownership of the returned frame.
+ // Return NULL on failure.
+ StackFrameRISCV64* GetCallerByFramePointer(
+ const vector<StackFrame*>& frames);
+
+ // Scan the stack for plausible return addresses. The caller takes ownership
+ // of the returned frame. Return NULL on failure.
+ StackFrameRISCV64* GetCallerByStackScan(
+ const vector<StackFrame*>& frames);
+
+ // Stores the CPU context corresponding to the innermost stack frame to
+ // be returned by GetContextFrame.
+ const MDRawContextRISCV64* context_;
+
+ // Validity mask for youngest stack frame. This is always
+ // CONTEXT_VALID_ALL in real use; it is only changeable for the sake of
+ // unit tests.
+ int context_frame_validity_;
+};
+
+} // namespace google_breakpad
+
+#endif // PROCESSOR_STACKWALKER_RISCV64_H__
diff --git a/src/processor/stackwalker_riscv64_unittest.cc b/src/processor/stackwalker_riscv64_unittest.cc
new file mode 100644
index 00000000..73c06264
--- /dev/null
+++ b/src/processor/stackwalker_riscv64_unittest.cc
@@ -0,0 +1,883 @@
+// Copyright 2013 Google LLC
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google LLC nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+/* stackwalker_riscv64_unittest.cc: Unit tests for StackwalkerRISCV64 class.
+ *
+ * Author: Iacopo Colonnelli
+ */
+
+#include <string.h>
+#include <string>
+#include <vector>
+
+#include "breakpad_googletest_includes.h"
+#include "common/test_assembler.h"
+#include "common/using_std_string.h"
+#include "google_breakpad/common/minidump_format.h"
+#include "google_breakpad/processor/basic_source_line_resolver.h"
+#include "google_breakpad/processor/call_stack.h"
+#include "google_breakpad/processor/code_module.h"
+#include "google_breakpad/processor/source_line_resolver_interface.h"
+#include "google_breakpad/processor/stack_frame_cpu.h"
+#include "processor/stackwalker_unittest_utils.h"
+#include "processor/stackwalker_riscv64.h"
+#include "processor/windows_frame_info.h"
+
+using google_breakpad::BasicSourceLineResolver;
+using google_breakpad::CallStack;
+using google_breakpad::CodeModule;
+using google_breakpad::StackFrameSymbolizer;
+using google_breakpad::StackFrame;
+using google_breakpad::StackFrameRISCV64;
+using google_breakpad::Stackwalker;
+using google_breakpad::StackwalkerRISCV64;
+using google_breakpad::SystemInfo;
+using google_breakpad::WindowsFrameInfo;
+using google_breakpad::test_assembler::kLittleEndian;
+using google_breakpad::test_assembler::Label;
+using google_breakpad::test_assembler::Section;
+using std::vector;
+using testing::_;
+using testing::AnyNumber;
+using testing::DoAll;
+using testing::Return;
+using testing::SetArgumentPointee;
+using testing::Test;
+
+class StackwalkerRISCV64Fixture {
+public:
+ StackwalkerRISCV64Fixture()
+ : stack_section(kLittleEndian),
+ // Give the two modules reasonable standard locations and names
+ // for tests to play with.
+ module1(0x40000000, 0x10000, "module1", "version1"),
+ module2(0x50000000, 0x10000, "module2", "version2") {
+ // Identify the system as an iOS system.
+ system_info.os = "iOS";
+ system_info.os_short = "ios";
+ system_info.cpu = "riscv64";
+ system_info.cpu_info = "";
+
+ // Put distinctive values in the raw CPU context.
+ BrandContext(&raw_context);
+
+ // Create some modules with some stock debugging information.
+ modules.Add(&module1);
+ modules.Add(&module2);
+
+ // By default, none of the modules have symbol info; call
+ // SetModuleSymbols to override this.
+ EXPECT_CALL(supplier, GetCStringSymbolData(_, _, _, _, _))
+ .WillRepeatedly(Return(MockSymbolSupplier::NOT_FOUND));
+
+ // Avoid GMOCK WARNING "Uninteresting mock function call - returning
+ // directly" for FreeSymbolData().
+ EXPECT_CALL(supplier, FreeSymbolData(_)).Times(AnyNumber());
+
+ // Reset max_frames_scanned since it's static.
+ Stackwalker::set_max_frames_scanned(1024);
+ }
+
+ // Set the Breakpad symbol information that supplier should return for
+ // MODULE to INFO.
+ void SetModuleSymbols(MockCodeModule* module, const string& info) {
+ size_t buffer_size;
+ char *buffer = supplier.CopySymbolDataAndOwnTheCopy(info, &buffer_size);
+ EXPECT_CALL(supplier, GetCStringSymbolData(module, &system_info, _, _, _))
+ .WillRepeatedly(DoAll(SetArgumentPointee<3>(buffer),
+ SetArgumentPointee<4>(buffer_size),
+ Return(MockSymbolSupplier::FOUND)));
+ }
+
+ // Populate stack_region with the contents of stack_section. Use
+ // stack_section.start() as the region's starting address.
+ void RegionFromSection() {
+ string contents;
+ ASSERT_TRUE(stack_section.GetContents(&contents));
+ stack_region.Init(stack_section.start().Value(), contents);
+ }
+
+ // Fill RAW_CONTEXT with pseudo-random data, for round-trip checking.
+ void BrandContext(MDRawContextRISCV64 *raw_context) {
+ uint8_t x = 173;
+ for (size_t i = 0; i < sizeof(*raw_context); i++)
+ reinterpret_cast<uint8_t*>(raw_context)[i] = (x += 17);
+ }
+
+ SystemInfo system_info;
+ MDRawContextRISCV64 raw_context;
+ Section stack_section;
+ MockMemoryRegion stack_region;
+ MockCodeModule module1;
+ MockCodeModule module2;
+ MockCodeModules modules;
+ MockSymbolSupplier supplier;
+ BasicSourceLineResolver resolver;
+ CallStack call_stack;
+ const vector<StackFrame*>* frames;
+};
+
+class SanityCheck: public StackwalkerRISCV64Fixture, public Test { };
+
+TEST_F(SanityCheck, NoResolver) {
+ // Since the context's frame pointer is garbage, the stack walk will end after
+ // the first frame.
+ StackFrameSymbolizer frame_symbolizer(NULL, NULL);
+ StackwalkerRISCV64 walker(&system_info, &raw_context, &stack_region, &modules,
+ &frame_symbolizer);
+ // This should succeed even without a resolver or supplier.
+ vector<const CodeModule*> modules_without_symbols;
+ vector<const CodeModule*> modules_with_corrupt_symbols;
+ ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols,
+ &modules_with_corrupt_symbols));
+ ASSERT_EQ(0U, modules_without_symbols.size());
+ ASSERT_EQ(0U, modules_with_corrupt_symbols.size());
+ frames = call_stack.frames();
+ ASSERT_EQ(1U, frames->size());
+ StackFrameRISCV64 *frame = static_cast<StackFrameRISCV64*>(frames->at(0));
+ // Check that the values from the original raw context made it
+ // through to the context in the stack frame.
+ EXPECT_EQ(0, memcmp(&raw_context, &frame->context, sizeof(raw_context)));
+}
+
+class GetContextFrame: public StackwalkerRISCV64Fixture, public Test { };
+
+// The stackwalker should be able to produce the context frame even
+// without stack memory present.
+TEST_F(GetContextFrame, NoStackMemory) {
+ StackFrameSymbolizer frame_symbolizer(&supplier, &resolver);
+ StackwalkerRISCV64 walker(&system_info, &raw_context, NULL, &modules,
+ &frame_symbolizer);
+ vector<const CodeModule*> modules_without_symbols;
+ vector<const CodeModule*> modules_with_corrupt_symbols;
+ ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols,
+ &modules_with_corrupt_symbols));
+ ASSERT_EQ(0U, modules_without_symbols.size());
+ ASSERT_EQ(0U, modules_with_corrupt_symbols.size());
+ frames = call_stack.frames();
+ ASSERT_EQ(1U, frames->size());
+ StackFrameRISCV64 *frame = static_cast<StackFrameRISCV64*>(frames->at(0));
+ // Check that the values from the original raw context made it
+ // through to the context in the stack frame.
+ EXPECT_EQ(0, memcmp(&raw_context, &frame->context, sizeof(raw_context)));
+}
+
+class GetCallerFrame: public StackwalkerRISCV64Fixture, public Test { };
+
+TEST_F(GetCallerFrame, ScanWithoutSymbols) {
+ // When the stack walker resorts to scanning the stack,
+ // only addresses located within loaded modules are
+ // considered valid return addresses.
+ // Force scanning through three frames to ensure that the
+ // stack pointer is set properly in scan-recovered frames.
+ stack_section.start() = 0x80000000;
+ uint64_t return_address1 = 0x50000100;
+ uint64_t return_address2 = 0x50000900;
+ Label frame1_sp, frame2_sp;
+ stack_section
+ // frame 0
+ .Append(16, 0) // space
+
+ .D64(0x40090000) // junk that's not
+ .D64(0x60000000) // a return address
+
+ .D64(return_address1) // actual return address
+ // frame 1
+ .Mark(&frame1_sp)
+ .Append(16, 0) // space
+
+ .D64(0xF0000000) // more junk
+ .D64(0x0000000D)
+
+ .D64(return_address2) // actual return address
+ // frame 2
+ .Mark(&frame2_sp)
+ .Append(64, 0); // end of stack
+ RegionFromSection();
+
+ raw_context.pc = 0x40005510;
+ raw_context.sp = stack_section.start().Value();
+
+ StackFrameSymbolizer frame_symbolizer(&supplier, &resolver);
+ StackwalkerRISCV64 walker(&system_info, &raw_context, &stack_region, &modules,
+ &frame_symbolizer);
+ vector<const CodeModule*> modules_without_symbols;
+ vector<const CodeModule*> modules_with_corrupt_symbols;
+ ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols,
+ &modules_with_corrupt_symbols));
+ ASSERT_EQ(2U, modules_without_symbols.size());
+ ASSERT_EQ("module1", modules_without_symbols[0]->debug_file());
+ ASSERT_EQ("module2", modules_without_symbols[1]->debug_file());
+ ASSERT_EQ(0U, modules_with_corrupt_symbols.size());
+ frames = call_stack.frames();
+ ASSERT_EQ(3U, frames->size());
+
+ StackFrameRISCV64 *frame0 = static_cast<StackFrameRISCV64*>(frames->at(0));
+ EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust);
+ ASSERT_EQ(StackFrameRISCV64::CONTEXT_VALID_ALL,
+ frame0->context_validity);
+ EXPECT_EQ(0, memcmp(&raw_context, &frame0->context, sizeof(raw_context)));
+
+ StackFrameRISCV64 *frame1 = static_cast<StackFrameRISCV64*>(frames->at(1));
+ EXPECT_EQ(StackFrame::FRAME_TRUST_SCAN, frame1->trust);
+ ASSERT_EQ((StackFrameRISCV64::CONTEXT_VALID_PC |
+ StackFrameRISCV64::CONTEXT_VALID_SP),
+ frame1->context_validity);
+ EXPECT_EQ(return_address1, frame1->context.pc);
+ EXPECT_EQ(frame1_sp.Value(), frame1->context.sp);
+
+ StackFrameRISCV64 *frame2 = static_cast<StackFrameRISCV64*>(frames->at(2));
+ EXPECT_EQ(StackFrame::FRAME_TRUST_SCAN, frame2->trust);
+ ASSERT_EQ((StackFrameRISCV64::CONTEXT_VALID_PC |
+ StackFrameRISCV64::CONTEXT_VALID_SP),
+ frame2->context_validity);
+ EXPECT_EQ(return_address2, frame2->context.pc);
+ EXPECT_EQ(frame2_sp.Value(), frame2->context.sp);
+}
+
+TEST_F(GetCallerFrame, ScanWithFunctionSymbols) {
+ // During stack scanning, if a potential return address
+ // is located within a loaded module that has symbols,
+ // it is only considered a valid return address if it
+ // lies within a function's bounds.
+ stack_section.start() = 0x80000000;
+ uint64_t return_address = 0x50000200;
+ Label frame1_sp;
+
+ stack_section
+ // frame 0
+ .Append(16, 0) // space
+
+ .D64(0x40090000) // junk that's not
+ .D64(0x60000000) // a return address
+
+ .D64(0x40001000) // a couple of plausible addresses
+ .D64(0x5000F000) // that are not within functions
+
+ .D64(return_address) // actual return address
+ // frame 1
+ .Mark(&frame1_sp)
+ .Append(64, 0); // end of stack
+ RegionFromSection();
+
+ raw_context.pc = 0x40000200;
+ raw_context.sp = stack_section.start().Value();
+
+ SetModuleSymbols(&module1,
+ // The youngest frame's function.
+ "FUNC 100 400 10 monotreme\n");
+ SetModuleSymbols(&module2,
+ // The calling frame's function.
+ "FUNC 100 400 10 marsupial\n");
+
+ StackFrameSymbolizer frame_symbolizer(&supplier, &resolver);
+ StackwalkerRISCV64 walker(&system_info, &raw_context, &stack_region,
+ &modules, &frame_symbolizer);
+ vector<const CodeModule*> modules_without_symbols;
+ vector<const CodeModule*> modules_with_corrupt_symbols;
+ ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols,
+ &modules_with_corrupt_symbols));
+ ASSERT_EQ(0U, modules_without_symbols.size());
+ ASSERT_EQ(0U, modules_with_corrupt_symbols.size());
+ frames = call_stack.frames();
+ ASSERT_EQ(2U, frames->size());
+
+ StackFrameRISCV64 *frame0 = static_cast<StackFrameRISCV64*>(frames->at(0));
+ EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust);
+ ASSERT_EQ(StackFrameRISCV64::CONTEXT_VALID_ALL,
+ frame0->context_validity);
+ EXPECT_EQ(0, memcmp(&raw_context, &frame0->context, sizeof(raw_context)));
+ EXPECT_EQ("monotreme", frame0->function_name);
+ EXPECT_EQ(0x40000100ULL, frame0->function_base);
+
+ StackFrameRISCV64 *frame1 = static_cast<StackFrameRISCV64*>(frames->at(1));
+ EXPECT_EQ(StackFrame::FRAME_TRUST_SCAN, frame1->trust);
+ ASSERT_EQ((StackFrameRISCV64::CONTEXT_VALID_PC |
+ StackFrameRISCV64::CONTEXT_VALID_SP),
+ frame1->context_validity);
+ EXPECT_EQ(return_address, frame1->context.pc);
+ EXPECT_EQ(frame1_sp.Value(), frame1->context.sp);
+ EXPECT_EQ("marsupial", frame1->function_name);
+ EXPECT_EQ(0x50000100ULL, frame1->function_base);
+}
+
+TEST_F(GetCallerFrame, ScanFirstFrame) {
+ // If the stackwalker resorts to stack scanning, it will scan much
+ // farther to find the caller of the context frame.
+ stack_section.start() = 0x80000000;
+ uint64_t return_address1 = 0x50000100;
+ uint64_t return_address2 = 0x50000900;
+ Label frame1_sp, frame2_sp;
+ stack_section
+ // frame 0
+ .Append(32, 0) // space
+
+ .D64(0x40090000) // junk that's not
+ .D64(0x60000000) // a return address
+
+ .Append(96, 0) // more space
+
+ .D64(return_address1) // actual return address
+ // frame 1
+ .Mark(&frame1_sp)
+ .Append(32, 0) // space
+
+ .D64(0xF0000000) // more junk
+ .D64(0x0000000D)
+
+ .Append(336, 0) // more space
+
+ .D64(return_address2) // actual return address
+ // (won't be found)
+ // frame 2
+ .Mark(&frame2_sp)
+ .Append(64, 0); // end of stack
+ RegionFromSection();
+
+ raw_context.pc = 0x40005510;
+ raw_context.sp = stack_section.start().Value();
+
+ StackFrameSymbolizer frame_symbolizer(&supplier, &resolver);
+ StackwalkerRISCV64 walker(&system_info, &raw_context, &stack_region,
+ &modules, &frame_symbolizer);
+ vector<const CodeModule*> modules_without_symbols;
+ vector<const CodeModule*> modules_with_corrupt_symbols;
+ ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols,
+ &modules_with_corrupt_symbols));
+ ASSERT_EQ(2U, modules_without_symbols.size());
+ ASSERT_EQ("module1", modules_without_symbols[0]->debug_file());
+ ASSERT_EQ("module2", modules_without_symbols[1]->debug_file());
+ ASSERT_EQ(0U, modules_with_corrupt_symbols.size());
+ frames = call_stack.frames();
+ ASSERT_EQ(2U, frames->size());
+
+ StackFrameRISCV64 *frame0 = static_cast<StackFrameRISCV64*>(frames->at(0));
+ EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust);
+ ASSERT_EQ(StackFrameRISCV64::CONTEXT_VALID_ALL,
+ frame0->context_validity);
+ EXPECT_EQ(0, memcmp(&raw_context, &frame0->context, sizeof(raw_context)));
+
+ StackFrameRISCV64 *frame1 = static_cast<StackFrameRISCV64*>(frames->at(1));
+ EXPECT_EQ(StackFrame::FRAME_TRUST_SCAN, frame1->trust);
+ ASSERT_EQ((StackFrameRISCV64::CONTEXT_VALID_PC |
+ StackFrameRISCV64::CONTEXT_VALID_SP),
+ frame1->context_validity);
+ EXPECT_EQ(return_address1, frame1->context.pc);
+ EXPECT_EQ(frame1_sp.Value(), frame1->context.sp);
+}
+
+// Test that set_max_frames_scanned prevents using stack scanning
+// to find caller frames.
+TEST_F(GetCallerFrame, ScanningNotAllowed) {
+ // When the stack walker resorts to scanning the stack,
+ // only addresses located within loaded modules are
+ // considered valid return addresses.
+ stack_section.start() = 0x80000000;
+ uint64_t return_address1 = 0x50000100;
+ uint64_t return_address2 = 0x50000900;
+ Label frame1_sp, frame2_sp;
+ stack_section
+ // frame 0
+ .Append(16, 0) // space
+
+ .D64(0x40090000) // junk that's not
+ .D64(0x60000000) // a return address
+
+ .D64(return_address1) // actual return address
+ // frame 1
+ .Mark(&frame1_sp)
+ .Append(16, 0) // space
+
+ .D64(0xF0000000) // more junk
+ .D64(0x0000000D)
+
+ .D64(return_address2) // actual return address
+ // frame 2
+ .Mark(&frame2_sp)
+ .Append(64, 0); // end of stack
+ RegionFromSection();
+
+ raw_context.pc = 0x40005510;
+ raw_context.sp = stack_section.start().Value();
+
+ StackFrameSymbolizer frame_symbolizer(&supplier, &resolver);
+ StackwalkerRISCV64 walker(&system_info, &raw_context, &stack_region,
+ &modules, &frame_symbolizer);
+ Stackwalker::set_max_frames_scanned(0);
+
+ vector<const CodeModule*> modules_without_symbols;
+ vector<const CodeModule*> modules_with_corrupt_symbols;
+ ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols,
+ &modules_with_corrupt_symbols));
+ ASSERT_EQ(1U, modules_without_symbols.size());
+ ASSERT_EQ("module1", modules_without_symbols[0]->debug_file());
+ ASSERT_EQ(0U, modules_with_corrupt_symbols.size());
+ frames = call_stack.frames();
+ ASSERT_EQ(1U, frames->size());
+
+ StackFrameRISCV64 *frame0 = static_cast<StackFrameRISCV64*>(frames->at(0));
+ EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust);
+ ASSERT_EQ(StackFrameRISCV64::CONTEXT_VALID_ALL,
+ frame0->context_validity);
+ EXPECT_EQ(0, memcmp(&raw_context, &frame0->context, sizeof(raw_context)));
+}
+
+class GetFramesByFramePointer:
+ public StackwalkerRISCV64Fixture,
+ public Test { };
+
+TEST_F(GetFramesByFramePointer, OnlyFramePointer) {
+ stack_section.start() = 0x80000000;
+ uint64_t return_address1 = 0x50000100;
+ uint64_t return_address2 = 0x50000900;
+ Label frame1_sp, frame2_sp;
+ Label frame1_fp, frame2_fp;
+ stack_section
+ // frame 0
+ .Append(64, 0) // Whatever values on the stack.
+ .D64(0x0000000D) // junk that's not
+ .D64(0xF0000000) // a return address.
+
+ .Mark(&frame1_fp) // Next fp will point to the next value.
+ .D64(frame2_fp) // Save current frame pointer.
+ .D64(return_address2) // Save current link register.
+ .Mark(&frame1_sp)
+
+ // frame 1
+ .Append(64, 0) // Whatever values on the stack.
+ .D64(0x0000000D) // junk that's not
+ .D64(0xF0000000) // a return address.
+
+ .Mark(&frame2_fp)
+ .D64(0)
+ .D64(0)
+ .Mark(&frame2_sp)
+
+ // frame 2
+ .Append(64, 0) // Whatever values on the stack.
+ .D64(0x0000000D) // junk that's not
+ .D64(0xF0000000); // a return address.
+ RegionFromSection();
+
+
+ raw_context.pc = 0x40005510;
+ raw_context.ra = return_address1;
+ raw_context.s0 = frame1_fp.Value();
+ raw_context.sp = stack_section.start().Value();
+
+ StackFrameSymbolizer frame_symbolizer(&supplier, &resolver);
+ StackwalkerRISCV64 walker(&system_info, &raw_context,
+ &stack_region, &modules, &frame_symbolizer);
+
+ vector<const CodeModule*> modules_without_symbols;
+ vector<const CodeModule*> modules_with_corrupt_symbols;
+ ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols,
+ &modules_with_corrupt_symbols));
+ ASSERT_EQ(2U, modules_without_symbols.size());
+ ASSERT_EQ("module1", modules_without_symbols[0]->debug_file());
+ ASSERT_EQ("module2", modules_without_symbols[1]->debug_file());
+ ASSERT_EQ(0U, modules_with_corrupt_symbols.size());
+ frames = call_stack.frames();
+ ASSERT_EQ(3U, frames->size());
+
+ StackFrameRISCV64 *frame0 = static_cast<StackFrameRISCV64*>(frames->at(0));
+ EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust);
+ ASSERT_EQ(StackFrameRISCV64::CONTEXT_VALID_ALL,
+ frame0->context_validity);
+ EXPECT_EQ(0, memcmp(&raw_context, &frame0->context, sizeof(raw_context)));
+
+ StackFrameRISCV64 *frame1 = static_cast<StackFrameRISCV64*>(frames->at(1));
+ EXPECT_EQ(StackFrame::FRAME_TRUST_FP, frame1->trust);
+ ASSERT_EQ((StackFrameRISCV64::CONTEXT_VALID_PC |
+ StackFrameRISCV64::CONTEXT_VALID_RA |
+ StackFrameRISCV64::CONTEXT_VALID_S0 |
+ StackFrameRISCV64::CONTEXT_VALID_SP),
+ frame1->context_validity);
+ EXPECT_EQ(return_address1, frame1->context.pc);
+ EXPECT_EQ(return_address2, frame1->context.ra);
+ EXPECT_EQ(frame1_sp.Value(), frame1->context.sp);
+ EXPECT_EQ(frame2_fp.Value(), frame1->context.s0);
+
+ StackFrameRISCV64 *frame2 = static_cast<StackFrameRISCV64*>(frames->at(2));
+ EXPECT_EQ(StackFrame::FRAME_TRUST_FP, frame2->trust);
+ ASSERT_EQ((StackFrameRISCV64::CONTEXT_VALID_PC |
+ StackFrameRISCV64::CONTEXT_VALID_RA |
+ StackFrameRISCV64::CONTEXT_VALID_S0 |
+ StackFrameRISCV64::CONTEXT_VALID_SP),
+ frame2->context_validity);
+ EXPECT_EQ(return_address2, frame2->context.pc);
+ EXPECT_EQ(0U, frame2->context.ra);
+ EXPECT_EQ(frame2_sp.Value(), frame2->context.sp);
+ EXPECT_EQ(0U, frame2->context.s0);
+}
+
+struct CFIFixture: public StackwalkerRISCV64Fixture {
+ CFIFixture() {
+ // Provide a bunch of STACK CFI records; we'll walk to the caller
+ // from every point in this series, expecting to find the same set
+ // of register values.
+ SetModuleSymbols(&module1,
+ // The youngest frame's function.
+ "FUNC 4000 1000 10 enchiridion\n"
+ // Initially, nothing has been pushed on the stack,
+ // and the return address is still in the return
+ // address register (ra).
+ "STACK CFI INIT 4000 100 .cfa: sp 0 + .ra: ra\n"
+ // Push s1, s2, the frame pointer (s0) and the
+ // return address register.
+ "STACK CFI 4001 .cfa: sp 32 + .ra: .cfa -8 + ^"
+ " s1: .cfa -32 + ^ s2: .cfa -24 + ^ "
+ " s0: .cfa -16 + ^\n"
+ // Save s1..s4 in a1..a4: verify that we populate
+ // the youngest frame with all the values we have.
+ "STACK CFI 4002 s1: a1 s2: a2 s3: a3 s4: a4\n"
+ // Restore s1..s4. Save the non-callee-saves register a2.
+ "STACK CFI 4003 .cfa: sp 40 + a2: .cfa 40 - ^"
+ " s1: s1 s2: s2 s3: s3 s4: s4\n"
+ // Move the .cfa back eight bytes, to point at the return
+ // address, and restore the sp explicitly.
+ "STACK CFI 4005 .cfa: sp 32 + a2: .cfa 32 - ^"
+ " s0: .cfa 8 - ^ .ra: .cfa ^ sp: .cfa 8 +\n"
+ // Recover the PC explicitly from a new stack slot;
+ // provide garbage for the .ra.
+ "STACK CFI 4006 .cfa: sp 40 + pc: .cfa 40 - ^\n"
+
+ // The calling function.
+ "FUNC 5000 1000 10 epictetus\n"
+ // Mark it as end of stack.
+ "STACK CFI INIT 5000 1000 .cfa: 0 .ra: 0\n"
+
+ // A function whose CFI makes the stack pointer
+ // go backwards.
+ "FUNC 6000 1000 20 palinal\n"
+ "STACK CFI INIT 6000 1000 .cfa: sp 8 - .ra: ra\n"
+
+ // A function with CFI expressions that can't be
+ // evaluated.
+ "FUNC 7000 1000 20 rhetorical\n"
+ "STACK CFI INIT 7000 1000 .cfa: moot .ra: ambiguous\n");
+
+ // Provide some distinctive values for the caller's registers.
+ expected.pc = 0x0000000040005510L;
+ expected.sp = 0x0000000080000000L;
+ expected.s1 = 0x5e68b5d5b5d55e68L;
+ expected.s2 = 0x34f3ebd1ebd134f3L;
+ expected.s3 = 0x74bca31ea31e74bcL;
+ expected.s4 = 0x16b32dcb2dcb16b3L;
+ expected.s5 = 0x21372ada2ada2137L;
+ expected.s6 = 0x557dbbbbbbbb557dL;
+ expected.s7 = 0x8ca748bf48bf8ca7L;
+ expected.s8 = 0x21f0ab46ab4621f0L;
+ expected.s9 = 0x146732b732b71467L;
+ expected.s10 = 0xa673645fa673645fL;
+ expected.s11 = 0xa673645fa673645fL;
+ expected.s0 = 0xe11081128112e110L;
+
+ // Expect CFI to recover all callee-saves registers. Since CFI is the
+ // only stack frame construction technique we have, aside from the
+ // context frame itself, there's no way for us to have a set of valid
+ // registers smaller than this.
+ expected_validity = (StackFrameRISCV64::CONTEXT_VALID_PC |
+ StackFrameRISCV64::CONTEXT_VALID_SP |
+ StackFrameRISCV64::CONTEXT_VALID_S1 |
+ StackFrameRISCV64::CONTEXT_VALID_S2 |
+ StackFrameRISCV64::CONTEXT_VALID_S3 |
+ StackFrameRISCV64::CONTEXT_VALID_S4 |
+ StackFrameRISCV64::CONTEXT_VALID_S5 |
+ StackFrameRISCV64::CONTEXT_VALID_S6 |
+ StackFrameRISCV64::CONTEXT_VALID_S7 |
+ StackFrameRISCV64::CONTEXT_VALID_S8 |
+ StackFrameRISCV64::CONTEXT_VALID_S9 |
+ StackFrameRISCV64::CONTEXT_VALID_S10 |
+ StackFrameRISCV64::CONTEXT_VALID_S11 |
+ StackFrameRISCV64::CONTEXT_VALID_S0);
+
+ // By default, context frames provide all registers, as normal.
+ context_frame_validity = StackFrameRISCV64::CONTEXT_VALID_ALL;
+
+ // By default, registers are unchanged.
+ raw_context = expected;
+ }
+
+ // Walk the stack, using stack_section as the contents of the stack
+ // and raw_context as the current register values. (Set the stack
+ // pointer to the stack's starting address.) Expect two stack
+ // frames; in the older frame, expect the callee-saves registers to
+ // have values matching those in 'expected'.
+ void CheckWalk() {
+ RegionFromSection();
+ raw_context.sp = stack_section.start().Value();
+
+ StackFrameSymbolizer frame_symbolizer(&supplier, &resolver);
+ StackwalkerRISCV64 walker(&system_info, &raw_context, &stack_region,
+ &modules, &frame_symbolizer);
+ walker.SetContextFrameValidity(context_frame_validity);
+ vector<const CodeModule*> modules_without_symbols;
+ vector<const CodeModule*> modules_with_corrupt_symbols;
+ ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols,
+ &modules_with_corrupt_symbols));
+ ASSERT_EQ(0U, modules_without_symbols.size());
+ ASSERT_EQ(0U, modules_with_corrupt_symbols.size());
+ frames = call_stack.frames();
+ ASSERT_EQ(2U, frames->size());
+
+ StackFrameRISCV64 *frame0 = static_cast<StackFrameRISCV64*>(frames->at(0));
+ EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust);
+ ASSERT_EQ(context_frame_validity, frame0->context_validity);
+ EXPECT_EQ("enchiridion", frame0->function_name);
+ EXPECT_EQ(0x0000000040004000UL, frame0->function_base);
+
+ StackFrameRISCV64 *frame1 = static_cast<StackFrameRISCV64*>(frames->at(1));
+ EXPECT_EQ(StackFrame::FRAME_TRUST_CFI, frame1->trust);
+ ASSERT_EQ(expected_validity, frame1->context_validity);
+ if (expected_validity & StackFrameRISCV64::CONTEXT_VALID_A2)
+ EXPECT_EQ(expected.a2, frame1->context.a2);
+ if (expected_validity & StackFrameRISCV64::CONTEXT_VALID_S1)
+ EXPECT_EQ(expected.s1, frame1->context.s1);
+ if (expected_validity & StackFrameRISCV64::CONTEXT_VALID_S2)
+ EXPECT_EQ(expected.s2, frame1->context.s2);
+ if (expected_validity & StackFrameRISCV64::CONTEXT_VALID_S3)
+ EXPECT_EQ(expected.s3, frame1->context.s3);
+ if (expected_validity & StackFrameRISCV64::CONTEXT_VALID_S4)
+ EXPECT_EQ(expected.s4, frame1->context.s4);
+ if (expected_validity & StackFrameRISCV64::CONTEXT_VALID_S5)
+ EXPECT_EQ(expected.s5, frame1->context.s5);
+ if (expected_validity & StackFrameRISCV64::CONTEXT_VALID_S6)
+ EXPECT_EQ(expected.s6, frame1->context.s6);
+ if (expected_validity & StackFrameRISCV64::CONTEXT_VALID_S7)
+ EXPECT_EQ(expected.s7, frame1->context.s7);
+ if (expected_validity & StackFrameRISCV64::CONTEXT_VALID_S8)
+ EXPECT_EQ(expected.s8, frame1->context.s8);
+ if (expected_validity & StackFrameRISCV64::CONTEXT_VALID_S9)
+ EXPECT_EQ(expected.s9, frame1->context.s9);
+ if (expected_validity & StackFrameRISCV64::CONTEXT_VALID_S10)
+ EXPECT_EQ(expected.s10, frame1->context.s10);
+ if (expected_validity & StackFrameRISCV64::CONTEXT_VALID_S11)
+ EXPECT_EQ(expected.s11, frame1->context.s11);
+ if (expected_validity & StackFrameRISCV64::CONTEXT_VALID_S0)
+ EXPECT_EQ(expected.s0, frame1->context.s0);
+
+ // We would never have gotten a frame in the first place if the SP
+ // and PC weren't valid or ->instruction weren't set.
+ EXPECT_EQ(expected.sp, frame1->context.sp);
+ EXPECT_EQ(expected.pc, frame1->context.pc);
+ EXPECT_EQ(expected.pc, frame1->instruction + 4);
+ EXPECT_EQ("epictetus", frame1->function_name);
+ }
+
+ // The values we expect to find for the caller's registers.
+ MDRawContextRISCV64 expected;
+
+ // The validity mask for expected.
+ int expected_validity;
+
+ // The validity mask to impose on the context frame.
+ int context_frame_validity;
+};
+
+class CFI: public CFIFixture, public Test { };
+
+TEST_F(CFI, At4000) {
+ stack_section.start() = expected.sp;
+ raw_context.pc = 0x0000000040004000L;
+ raw_context.ra = 0x0000000040005510L;
+ CheckWalk();
+}
+
+TEST_F(CFI, At4001) {
+ Label frame1_sp = expected.sp;
+ stack_section
+ .D64(0x5e68b5d5b5d55e68L) // saved s1
+ .D64(0x34f3ebd1ebd134f3L) // saved s2
+ .D64(0xe11081128112e110L) // saved s0
+ .D64(0x0000000040005510L) // return address
+ .Mark(&frame1_sp); // This effectively sets stack_section.start().
+ raw_context.pc = 0x0000000040004001L;
+ // distinct callee s1, s2 and s0
+ raw_context.s1 = 0xadc9f635a635adc9L;
+ raw_context.s2 = 0x623135ac35ac6231L;
+ raw_context.s0 = 0x5fc4be14be145fc4L;
+ CheckWalk();
+}
+
+// As above, but unwind from a context that has only the PC and SP.
+TEST_F(CFI, At4001LimitedValidity) {
+ Label frame1_sp = expected.sp;
+ stack_section
+ .D64(0x5e68b5d5b5d55e68L) // saved s1
+ .D64(0x34f3ebd1ebd134f3L) // saved s2
+ .D64(0xe11081128112e110L) // saved s0
+ .D64(0x0000000040005510L) // return address
+ .Mark(&frame1_sp); // This effectively sets stack_section.start().
+ context_frame_validity = StackFrameRISCV64::CONTEXT_VALID_PC |
+ StackFrameRISCV64::CONTEXT_VALID_SP;
+ raw_context.pc = 0x0000000040004001L;
+ raw_context.s0 = 0x5fc4be14be145fc4L;
+
+ expected_validity = (StackFrameRISCV64::CONTEXT_VALID_PC |
+ StackFrameRISCV64::CONTEXT_VALID_SP |
+ StackFrameRISCV64::CONTEXT_VALID_S0 |
+ StackFrameRISCV64::CONTEXT_VALID_S1 |
+ StackFrameRISCV64::CONTEXT_VALID_S2);
+ CheckWalk();
+}
+
+TEST_F(CFI, At4002) {
+ Label frame1_sp = expected.sp;
+ stack_section
+ .D64(0xff3dfb81fb81ff3dL) // no longer saved s1
+ .D64(0x34f3ebd1ebd134f3L) // no longer saved s2
+ .D64(0xe11081128112e110L) // saved s0
+ .D64(0x0000000040005510L) // return address
+ .Mark(&frame1_sp); // This effectively sets stack_section.start().
+ raw_context.pc = 0x0000000040004002L;
+ raw_context.a1 = 0x5e68b5d5b5d55e68L; // saved s1
+ raw_context.a2 = 0x34f3ebd1ebd134f3L; // saved s2
+ raw_context.a3 = 0x74bca31ea31e74bcL; // saved s3
+ raw_context.a4 = 0x16b32dcb2dcb16b3L; // saved s4
+ raw_context.s1 = 0xadc9f635a635adc9L; // distinct callee s1
+ raw_context.s2 = 0x623135ac35ac6231L; // distinct callee s2
+ raw_context.s3 = 0xac4543564356ac45L; // distinct callee s3
+ raw_context.s4 = 0x2561562f562f2561L; // distinct callee s4
+ // distinct callee s0
+ raw_context.s0 = 0x5fc4be14be145fc4L;
+ CheckWalk();
+}
+
+TEST_F(CFI, At4003) {
+ Label frame1_sp = expected.sp;
+ stack_section
+ .D64(0xdd5a48c848c8dd5aL) // saved a2 (even though it's not callee-saves)
+ .D64(0xff3dfb81fb81ff3dL) // no longer saved s1
+ .D64(0x34f3ebd1ebd134f3L) // no longer saved s2
+ .D64(0xe11081128112e110L) // saved s0
+ .D64(0x0000000040005510L) // return address
+ .Mark(&frame1_sp); // This effectively sets stack_section.start().
+ raw_context.pc = 0x0000000040004003L;
+ // distinct callee a2 and fp
+ raw_context.a2 = 0xfb756319fb756319L;
+ raw_context.s0 = 0x5fc4be14be145fc4L;
+ // caller's a2
+ expected.a2 = 0xdd5a48c848c8dd5aL;
+ expected_validity |= StackFrameRISCV64::CONTEXT_VALID_A2;
+ CheckWalk();
+}
+
+// We have no new rule at module offset 0x4004, so the results here should
+// be the same as those at module offset 0x4003.
+TEST_F(CFI, At4004) {
+ Label frame1_sp = expected.sp;
+ stack_section
+ .D64(0xdd5a48c848c8dd5aL) // saved a2 (even though it's not callee-saves)
+ .D64(0xff3dfb81fb81ff3dL) // no longer saved s1
+ .D64(0x34f3ebd1ebd134f3L) // no longer saved s2
+ .D64(0xe11081128112e110L) // saved s0
+ .D64(0x0000000040005510L) // return address
+ .Mark(&frame1_sp); // This effectively sets stack_section.start().
+ raw_context.pc = 0x0000000040004004L;
+ // distinct callee a2 and s0
+ raw_context.a2 = 0xfb756319fb756319L;
+ raw_context.s0 = 0x5fc4be14be145fc4L;
+ // caller's a2
+ expected.a2 = 0xdd5a48c848c8dd5aL;
+ expected_validity |= StackFrameRISCV64::CONTEXT_VALID_A2;
+ CheckWalk();
+}
+
+// Here we move the .cfa, but provide an explicit rule to recover the SP,
+// so again there should be no change in the registers recovered.
+TEST_F(CFI, At4005) {
+ Label frame1_sp = expected.sp;
+ stack_section
+ .D64(0xdd5a48c848c8dd5aL) // saved a2 (even though it's not callee-saves)
+ .D64(0xff3dfb81fb81ff3dL) // no longer saved s1
+ .D64(0x34f3ebd1ebd134f3L) // no longer saved s2
+ .D64(0xe11081128112e110L) // saved s0
+ .D64(0x0000000040005510L) // return address
+ .Mark(&frame1_sp); // This effectively sets stack_section.start().
+ raw_context.pc = 0x0000000040004005L;
+ raw_context.a2 = 0xfb756319fb756319L; // distinct callee a2
+ expected.a2 = 0xdd5a48c848c8dd5aL; // caller's a2
+ expected_validity |= StackFrameRISCV64::CONTEXT_VALID_A2;
+ CheckWalk();
+}
+
+// Here we provide an explicit rule for the PC, and have the saved .ra be
+// bogus.
+TEST_F(CFI, At4006) {
+ Label frame1_sp = expected.sp;
+ stack_section
+ .D64(0x0000000040005510L) // saved pc
+ .D64(0xdd5a48c848c8dd5aL) // saved a2 (even though it's not callee-saves)
+ .D64(0xff3dfb81fb81ff3dL) // no longer saved s1
+ .D64(0x34f3ebd1ebd134f3L) // no longer saved s2
+ .D64(0xe11081128112e110L) // saved s0
+ .D64(0xf8d157835783f8d1L) // .ra rule recovers this, which is garbage
+ .Mark(&frame1_sp); // This effectively sets stack_section.start().
+ raw_context.pc = 0x0000000040004006L;
+ raw_context.a2 = 0xfb756319fb756319L; // distinct callee a2
+ expected.a2 = 0xdd5a48c848c8dd5aL; // caller's a2
+ expected_validity |= StackFrameRISCV64::CONTEXT_VALID_A2;
+ CheckWalk();
+}
+
+// Check that we reject rules that would cause the stack pointer to
+// move in the wrong direction.
+TEST_F(CFI, RejectBackwards) {
+ raw_context.pc = 0x0000000040006000L;
+ raw_context.sp = 0x0000000080000000L;
+ raw_context.ra = 0x0000000040005510L;
+ StackFrameSymbolizer frame_symbolizer(&supplier, &resolver);
+ StackwalkerRISCV64 walker(&system_info, &raw_context, &stack_region,
+ &modules, &frame_symbolizer);
+ vector<const CodeModule*> modules_without_symbols;
+ vector<const CodeModule*> modules_with_corrupt_symbols;
+ ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols,
+ &modules_with_corrupt_symbols));
+ ASSERT_EQ(0U, modules_without_symbols.size());
+ ASSERT_EQ(0U, modules_with_corrupt_symbols.size());
+ frames = call_stack.frames();
+ ASSERT_EQ(1U, frames->size());
+}
+
+// Check that we reject rules whose expressions' evaluation fails.
+TEST_F(CFI, RejectBadExpressions) {
+ raw_context.pc = 0x0000000040007000L;
+ raw_context.sp = 0x0000000080000000L;
+ StackFrameSymbolizer frame_symbolizer(&supplier, &resolver);
+ StackwalkerRISCV64 walker(&system_info, &raw_context, &stack_region,
+ &modules, &frame_symbolizer);
+ vector<const CodeModule*> modules_without_symbols;
+ vector<const CodeModule*> modules_with_corrupt_symbols;
+ ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols,
+ &modules_with_corrupt_symbols));
+ ASSERT_EQ(0U, modules_without_symbols.size());
+ ASSERT_EQ(0U, modules_with_corrupt_symbols.size());
+ frames = call_stack.frames();
+ ASSERT_EQ(1U, frames->size());
+}
diff --git a/src/processor/stackwalker_riscv_unittest.cc b/src/processor/stackwalker_riscv_unittest.cc
new file mode 100644
index 00000000..f4a6b79c
--- /dev/null
+++ b/src/processor/stackwalker_riscv_unittest.cc
@@ -0,0 +1,883 @@
+// Copyright 2013 Google LLC
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google LLC nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+/* stackwalker_riscv_unittest.cc: Unit tests for StackwalkerRISCV class.
+ *
+ * Author: Iacopo Colonnelli
+ */
+
+#include <string.h>
+#include <string>
+#include <vector>
+
+#include "breakpad_googletest_includes.h"
+#include "common/test_assembler.h"
+#include "common/using_std_string.h"
+#include "google_breakpad/common/minidump_format.h"
+#include "google_breakpad/processor/basic_source_line_resolver.h"
+#include "google_breakpad/processor/call_stack.h"
+#include "google_breakpad/processor/code_module.h"
+#include "google_breakpad/processor/source_line_resolver_interface.h"
+#include "google_breakpad/processor/stack_frame_cpu.h"
+#include "processor/stackwalker_unittest_utils.h"
+#include "processor/stackwalker_riscv.h"
+#include "processor/windows_frame_info.h"
+
+using google_breakpad::BasicSourceLineResolver;
+using google_breakpad::CallStack;
+using google_breakpad::CodeModule;
+using google_breakpad::StackFrameSymbolizer;
+using google_breakpad::StackFrame;
+using google_breakpad::StackFrameRISCV;
+using google_breakpad::Stackwalker;
+using google_breakpad::StackwalkerRISCV;
+using google_breakpad::SystemInfo;
+using google_breakpad::WindowsFrameInfo;
+using google_breakpad::test_assembler::kLittleEndian;
+using google_breakpad::test_assembler::Label;
+using google_breakpad::test_assembler::Section;
+using std::vector;
+using testing::_;
+using testing::AnyNumber;
+using testing::DoAll;
+using testing::Return;
+using testing::SetArgumentPointee;
+using testing::Test;
+
+class StackwalkerRISCVFixture {
+public:
+ StackwalkerRISCVFixture()
+ : stack_section(kLittleEndian),
+ // Give the two modules reasonable standard locations and names
+ // for tests to play with.
+ module1(0x40000000, 0x10000, "module1", "version1"),
+ module2(0x50000000, 0x10000, "module2", "version2") {
+ // Identify the system as an iOS system.
+ system_info.os = "iOS";
+ system_info.os_short = "ios";
+ system_info.cpu = "riscv";
+ system_info.cpu_info = "";
+
+ // Put distinctive values in the raw CPU context.
+ BrandContext(&raw_context);
+
+ // Create some modules with some stock debugging information.
+ modules.Add(&module1);
+ modules.Add(&module2);
+
+ // By default, none of the modules have symbol info; call
+ // SetModuleSymbols to override this.
+ EXPECT_CALL(supplier, GetCStringSymbolData(_, _, _, _, _))
+ .WillRepeatedly(Return(MockSymbolSupplier::NOT_FOUND));
+
+ // Avoid GMOCK WARNING "Uninteresting mock function call - returning
+ // directly" for FreeSymbolData().
+ EXPECT_CALL(supplier, FreeSymbolData(_)).Times(AnyNumber());
+
+ // Reset max_frames_scanned since it's static.
+ Stackwalker::set_max_frames_scanned(1024);
+ }
+
+ // Set the Breakpad symbol information that supplier should return for
+ // MODULE to INFO.
+ void SetModuleSymbols(MockCodeModule* module, const string& info) {
+ size_t buffer_size;
+ char *buffer = supplier.CopySymbolDataAndOwnTheCopy(info, &buffer_size);
+ EXPECT_CALL(supplier, GetCStringSymbolData(module, &system_info, _, _, _))
+ .WillRepeatedly(DoAll(SetArgumentPointee<3>(buffer),
+ SetArgumentPointee<4>(buffer_size),
+ Return(MockSymbolSupplier::FOUND)));
+ }
+
+ // Populate stack_region with the contents of stack_section. Use
+ // stack_section.start() as the region's starting address.
+ void RegionFromSection() {
+ string contents;
+ ASSERT_TRUE(stack_section.GetContents(&contents));
+ stack_region.Init(stack_section.start().Value(), contents);
+ }
+
+ // Fill RAW_CONTEXT with pseudo-random data, for round-trip checking.
+ void BrandContext(MDRawContextRISCV *raw_context) {
+ uint8_t x = 173;
+ for (size_t i = 0; i < sizeof(*raw_context); i++)
+ reinterpret_cast<uint8_t*>(raw_context)[i] = (x += 17);
+ }
+
+ SystemInfo system_info;
+ MDRawContextRISCV raw_context;
+ Section stack_section;
+ MockMemoryRegion stack_region;
+ MockCodeModule module1;
+ MockCodeModule module2;
+ MockCodeModules modules;
+ MockSymbolSupplier supplier;
+ BasicSourceLineResolver resolver;
+ CallStack call_stack;
+ const vector<StackFrame*>* frames;
+};
+
+class SanityCheck: public StackwalkerRISCVFixture, public Test { };
+
+TEST_F(SanityCheck, NoResolver) {
+ // Since the context's frame pointer is garbage, the stack walk will end after
+ // the first frame.
+ StackFrameSymbolizer frame_symbolizer(NULL, NULL);
+ StackwalkerRISCV walker(&system_info, &raw_context, &stack_region,
+ &modules, &frame_symbolizer);
+ // This should succeed even without a resolver or supplier.
+ vector<const CodeModule*> modules_without_symbols;
+ vector<const CodeModule*> modules_with_corrupt_symbols;
+ ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols,
+ &modules_with_corrupt_symbols));
+ ASSERT_EQ(0U, modules_without_symbols.size());
+ ASSERT_EQ(0U, modules_with_corrupt_symbols.size());
+ frames = call_stack.frames();
+ ASSERT_EQ(1U, frames->size());
+ StackFrameRISCV *frame = static_cast<StackFrameRISCV*>(frames->at(0));
+ // Check that the values from the original raw context made it
+ // through to the context in the stack frame.
+ EXPECT_EQ(0, memcmp(&raw_context, &frame->context, sizeof(raw_context)));
+}
+
+class GetContextFrame: public StackwalkerRISCVFixture, public Test { };
+
+// The stackwalker should be able to produce the context frame even
+// without stack memory present.
+TEST_F(GetContextFrame, NoStackMemory) {
+ StackFrameSymbolizer frame_symbolizer(&supplier, &resolver);
+ StackwalkerRISCV walker(&system_info, &raw_context, NULL, &modules,
+ &frame_symbolizer);
+ vector<const CodeModule*> modules_without_symbols;
+ vector<const CodeModule*> modules_with_corrupt_symbols;
+ ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols,
+ &modules_with_corrupt_symbols));
+ ASSERT_EQ(0U, modules_without_symbols.size());
+ ASSERT_EQ(0U, modules_with_corrupt_symbols.size());
+ frames = call_stack.frames();
+ ASSERT_EQ(1U, frames->size());
+ StackFrameRISCV *frame = static_cast<StackFrameRISCV*>(frames->at(0));
+ // Check that the values from the original raw context made it
+ // through to the context in the stack frame.
+ EXPECT_EQ(0, memcmp(&raw_context, &frame->context, sizeof(raw_context)));
+}
+
+class GetCallerFrame: public StackwalkerRISCVFixture, public Test { };
+
+TEST_F(GetCallerFrame, ScanWithoutSymbols) {
+ // When the stack walker resorts to scanning the stack,
+ // only addresses located within loaded modules are
+ // considered valid return addresses.
+ // Force scanning through three frames to ensure that the
+ // stack pointer is set properly in scan-recovered frames.
+ stack_section.start() = 0x80000000;
+ uint64_t return_address1 = 0x50000100;
+ uint64_t return_address2 = 0x50000900;
+ Label frame1_sp, frame2_sp;
+ stack_section
+ // frame 0
+ .Append(8, 0) // space
+
+ .D32(0x40090000) // junk that's not
+ .D32(0x60000000) // a return address
+
+ .D32(return_address1) // actual return address
+ // frame 1
+ .Mark(&frame1_sp)
+ .Append(8, 0) // space
+
+ .D32(0xF0000000) // more junk
+ .D32(0x0000000D)
+
+ .D32(return_address2) // actual return address
+ // frame 2
+ .Mark(&frame2_sp)
+ .Append(32, 0); // end of stack
+ RegionFromSection();
+
+ raw_context.pc = 0x40005510;
+ raw_context.sp = stack_section.start().Value();
+
+ StackFrameSymbolizer frame_symbolizer(&supplier, &resolver);
+ StackwalkerRISCV walker(&system_info, &raw_context, &stack_region,
+ &modules, &frame_symbolizer);
+ vector<const CodeModule*> modules_without_symbols;
+ vector<const CodeModule*> modules_with_corrupt_symbols;
+ ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols,
+ &modules_with_corrupt_symbols));
+ ASSERT_EQ(2U, modules_without_symbols.size());
+ ASSERT_EQ("module1", modules_without_symbols[0]->debug_file());
+ ASSERT_EQ("module2", modules_without_symbols[1]->debug_file());
+ ASSERT_EQ(0U, modules_with_corrupt_symbols.size());
+ frames = call_stack.frames();
+ ASSERT_EQ(3U, frames->size());
+
+ StackFrameRISCV *frame0 = static_cast<StackFrameRISCV*>(frames->at(0));
+ EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust);
+ ASSERT_EQ(StackFrameRISCV::CONTEXT_VALID_ALL,
+ frame0->context_validity);
+ EXPECT_EQ(0, memcmp(&raw_context, &frame0->context, sizeof(raw_context)));
+
+ StackFrameRISCV *frame1 = static_cast<StackFrameRISCV*>(frames->at(1));
+ EXPECT_EQ(StackFrame::FRAME_TRUST_SCAN, frame1->trust);
+ ASSERT_EQ((StackFrameRISCV::CONTEXT_VALID_PC |
+ StackFrameRISCV::CONTEXT_VALID_SP),
+ frame1->context_validity);
+ EXPECT_EQ(return_address1, frame1->context.pc);
+ EXPECT_EQ(frame1_sp.Value(), frame1->context.sp);
+
+ StackFrameRISCV *frame2 = static_cast<StackFrameRISCV*>(frames->at(2));
+ EXPECT_EQ(StackFrame::FRAME_TRUST_SCAN, frame2->trust);
+ ASSERT_EQ((StackFrameRISCV::CONTEXT_VALID_PC |
+ StackFrameRISCV::CONTEXT_VALID_SP),
+ frame2->context_validity);
+ EXPECT_EQ(return_address2, frame2->context.pc);
+ EXPECT_EQ(frame2_sp.Value(), frame2->context.sp);
+}
+
+TEST_F(GetCallerFrame, ScanWithFunctionSymbols) {
+ // During stack scanning, if a potential return address
+ // is located within a loaded module that has symbols,
+ // it is only considered a valid return address if it
+ // lies within a function's bounds.
+ stack_section.start() = 0x80000000;
+ uint64_t return_address = 0x50000200;
+ Label frame1_sp;
+
+ stack_section
+ // frame 0
+ .Append(8, 0) // space
+
+ .D32(0x40090000) // junk that's not
+ .D32(0x60000000) // a return address
+
+ .D32(0x40001000) // a couple of plausible addresses
+ .D32(0x5000F000) // that are not within functions
+
+ .D32(return_address) // actual return address
+ // frame 1
+ .Mark(&frame1_sp)
+ .Append(32, 0); // end of stack
+ RegionFromSection();
+
+ raw_context.pc = 0x40000200;
+ raw_context.sp = stack_section.start().Value();
+
+ SetModuleSymbols(&module1,
+ // The youngest frame's function.
+ "FUNC 100 400 10 monotreme\n");
+ SetModuleSymbols(&module2,
+ // The calling frame's function.
+ "FUNC 100 400 10 marsupial\n");
+
+ StackFrameSymbolizer frame_symbolizer(&supplier, &resolver);
+ StackwalkerRISCV walker(&system_info, &raw_context, &stack_region,
+ &modules, &frame_symbolizer);
+ vector<const CodeModule*> modules_without_symbols;
+ vector<const CodeModule*> modules_with_corrupt_symbols;
+ ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols,
+ &modules_with_corrupt_symbols));
+ ASSERT_EQ(0U, modules_without_symbols.size());
+ ASSERT_EQ(0U, modules_with_corrupt_symbols.size());
+ frames = call_stack.frames();
+ ASSERT_EQ(2U, frames->size());
+
+ StackFrameRISCV *frame0 = static_cast<StackFrameRISCV*>(frames->at(0));
+ EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust);
+ ASSERT_EQ(StackFrameRISCV::CONTEXT_VALID_ALL,
+ frame0->context_validity);
+ EXPECT_EQ(0, memcmp(&raw_context, &frame0->context, sizeof(raw_context)));
+ EXPECT_EQ("monotreme", frame0->function_name);
+ EXPECT_EQ(0x40000100UL, frame0->function_base);
+
+ StackFrameRISCV *frame1 = static_cast<StackFrameRISCV*>(frames->at(1));
+ EXPECT_EQ(StackFrame::FRAME_TRUST_SCAN, frame1->trust);
+ ASSERT_EQ((StackFrameRISCV::CONTEXT_VALID_PC |
+ StackFrameRISCV::CONTEXT_VALID_SP),
+ frame1->context_validity);
+ EXPECT_EQ(return_address, frame1->context.pc);
+ EXPECT_EQ(frame1_sp.Value(), frame1->context.sp);
+ EXPECT_EQ("marsupial", frame1->function_name);
+ EXPECT_EQ(0x50000100UL, frame1->function_base);
+}
+
+TEST_F(GetCallerFrame, ScanFirstFrame) {
+ // If the stackwalker resorts to stack scanning, it will scan much
+ // farther to find the caller of the context frame.
+ stack_section.start() = 0x80000000;
+ uint64_t return_address1 = 0x50000100;
+ uint64_t return_address2 = 0x50000900;
+ Label frame1_sp, frame2_sp;
+ stack_section
+ // frame 0
+ .Append(16, 0) // space
+
+ .D32(0x40090000) // junk that's not
+ .D32(0x60000000) // a return address
+
+ .Append(48, 0) // more space
+
+ .D32(return_address1) // actual return address
+ // frame 1
+ .Mark(&frame1_sp)
+ .Append(16, 0) // space
+
+ .D32(0xF0000000) // more junk
+ .D32(0x0000000D)
+
+ .Append(168, 0) // more space
+
+ .D32(return_address2) // actual return address
+ // (won't be found)
+ // frame 2
+ .Mark(&frame2_sp)
+ .Append(32, 0); // end of stack
+ RegionFromSection();
+
+ raw_context.pc = 0x40005510;
+ raw_context.sp = stack_section.start().Value();
+
+ StackFrameSymbolizer frame_symbolizer(&supplier, &resolver);
+ StackwalkerRISCV walker(&system_info, &raw_context, &stack_region,
+ &modules, &frame_symbolizer);
+ vector<const CodeModule*> modules_without_symbols;
+ vector<const CodeModule*> modules_with_corrupt_symbols;
+ ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols,
+ &modules_with_corrupt_symbols));
+ ASSERT_EQ(2U, modules_without_symbols.size());
+ ASSERT_EQ("module1", modules_without_symbols[0]->debug_file());
+ ASSERT_EQ("module2", modules_without_symbols[1]->debug_file());
+ ASSERT_EQ(0U, modules_with_corrupt_symbols.size());
+ frames = call_stack.frames();
+ ASSERT_EQ(2U, frames->size());
+
+ StackFrameRISCV *frame0 = static_cast<StackFrameRISCV*>(frames->at(0));
+ EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust);
+ ASSERT_EQ(StackFrameRISCV::CONTEXT_VALID_ALL,
+ frame0->context_validity);
+ EXPECT_EQ(0, memcmp(&raw_context, &frame0->context, sizeof(raw_context)));
+
+ StackFrameRISCV *frame1 = static_cast<StackFrameRISCV*>(frames->at(1));
+ EXPECT_EQ(StackFrame::FRAME_TRUST_SCAN, frame1->trust);
+ ASSERT_EQ((StackFrameRISCV::CONTEXT_VALID_PC |
+ StackFrameRISCV::CONTEXT_VALID_SP),
+ frame1->context_validity);
+ EXPECT_EQ(return_address1, frame1->context.pc);
+ EXPECT_EQ(frame1_sp.Value(), frame1->context.sp);
+}
+
+// Test that set_max_frames_scanned prevents using stack scanning
+// to find caller frames.
+TEST_F(GetCallerFrame, ScanningNotAllowed) {
+ // When the stack walker resorts to scanning the stack,
+ // only addresses located within loaded modules are
+ // considered valid return addresses.
+ stack_section.start() = 0x80000000;
+ uint64_t return_address1 = 0x50000100;
+ uint64_t return_address2 = 0x50000900;
+ Label frame1_sp, frame2_sp;
+ stack_section
+ // frame 0
+ .Append(8, 0) // space
+
+ .D32(0x40090000) // junk that's not
+ .D32(0x60000000) // a return address
+
+ .D32(return_address1) // actual return address
+ // frame 1
+ .Mark(&frame1_sp)
+ .Append(8, 0) // space
+
+ .D32(0xF0000000) // more junk
+ .D32(0x0000000D)
+
+ .D32(return_address2) // actual return address
+ // frame 2
+ .Mark(&frame2_sp)
+ .Append(32, 0); // end of stack
+ RegionFromSection();
+
+ raw_context.pc = 0x40005510;
+ raw_context.sp = stack_section.start().Value();
+
+ StackFrameSymbolizer frame_symbolizer(&supplier, &resolver);
+ StackwalkerRISCV walker(&system_info, &raw_context, &stack_region,
+ &modules, &frame_symbolizer);
+ Stackwalker::set_max_frames_scanned(0);
+
+ vector<const CodeModule*> modules_without_symbols;
+ vector<const CodeModule*> modules_with_corrupt_symbols;
+ ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols,
+ &modules_with_corrupt_symbols));
+ ASSERT_EQ(1U, modules_without_symbols.size());
+ ASSERT_EQ("module1", modules_without_symbols[0]->debug_file());
+ ASSERT_EQ(0U, modules_with_corrupt_symbols.size());
+ frames = call_stack.frames();
+ ASSERT_EQ(1U, frames->size());
+
+ StackFrameRISCV *frame0 = static_cast<StackFrameRISCV*>(frames->at(0));
+ EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust);
+ ASSERT_EQ(StackFrameRISCV::CONTEXT_VALID_ALL,
+ frame0->context_validity);
+ EXPECT_EQ(0, memcmp(&raw_context, &frame0->context, sizeof(raw_context)));
+}
+
+class GetFramesByFramePointer:
+ public StackwalkerRISCVFixture,
+ public Test { };
+
+TEST_F(GetFramesByFramePointer, OnlyFramePointer) {
+ stack_section.start() = 0x80000000;
+ uint64_t return_address1 = 0x50000100;
+ uint64_t return_address2 = 0x50000900;
+ Label frame1_sp, frame2_sp;
+ Label frame1_fp, frame2_fp;
+ stack_section
+ // frame 0
+ .Append(32, 0) // Whatever values on the stack.
+ .D32(0x0000000D) // junk that's not
+ .D32(0xF0000000) // a return address.
+
+ .Mark(&frame1_fp) // Next fp will point to the next value.
+ .D32(frame2_fp) // Save current frame pointer.
+ .D32(return_address2) // Save current link register.
+ .Mark(&frame1_sp)
+
+ // frame 1
+ .Append(32, 0) // Whatever values on the stack.
+ .D32(0x0000000D) // junk that's not
+ .D32(0xF0000000) // a return address.
+
+ .Mark(&frame2_fp)
+ .D32(0)
+ .D32(0)
+ .Mark(&frame2_sp)
+
+ // frame 2
+ .Append(32, 0) // Whatever values on the stack.
+ .D32(0x0000000D) // junk that's not
+ .D32(0xF0000000); // a return address.
+ RegionFromSection();
+
+
+ raw_context.pc = 0x40005510;
+ raw_context.ra = return_address1;
+ raw_context.s0 = frame1_fp.Value();
+ raw_context.sp = stack_section.start().Value();
+
+ StackFrameSymbolizer frame_symbolizer(&supplier, &resolver);
+ StackwalkerRISCV walker(&system_info, &raw_context,
+ &stack_region, &modules, &frame_symbolizer);
+
+ vector<const CodeModule*> modules_without_symbols;
+ vector<const CodeModule*> modules_with_corrupt_symbols;
+ ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols,
+ &modules_with_corrupt_symbols));
+ ASSERT_EQ(2U, modules_without_symbols.size());
+ ASSERT_EQ("module1", modules_without_symbols[0]->debug_file());
+ ASSERT_EQ("module2", modules_without_symbols[1]->debug_file());
+ ASSERT_EQ(0U, modules_with_corrupt_symbols.size());
+ frames = call_stack.frames();
+ ASSERT_EQ(3U, frames->size());
+
+ StackFrameRISCV *frame0 = static_cast<StackFrameRISCV*>(frames->at(0));
+ EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust);
+ ASSERT_EQ(StackFrameRISCV::CONTEXT_VALID_ALL,
+ frame0->context_validity);
+ EXPECT_EQ(0, memcmp(&raw_context, &frame0->context, sizeof(raw_context)));
+
+ StackFrameRISCV *frame1 = static_cast<StackFrameRISCV*>(frames->at(1));
+ EXPECT_EQ(StackFrame::FRAME_TRUST_FP, frame1->trust);
+ ASSERT_EQ((StackFrameRISCV::CONTEXT_VALID_PC |
+ StackFrameRISCV::CONTEXT_VALID_RA |
+ StackFrameRISCV::CONTEXT_VALID_S0 |
+ StackFrameRISCV::CONTEXT_VALID_SP),
+ frame1->context_validity);
+ EXPECT_EQ(return_address1, frame1->context.pc);
+ EXPECT_EQ(return_address2, frame1->context.ra);
+ EXPECT_EQ(frame1_sp.Value(), frame1->context.sp);
+ EXPECT_EQ(frame2_fp.Value(), frame1->context.s0);
+
+ StackFrameRISCV *frame2 = static_cast<StackFrameRISCV*>(frames->at(2));
+ EXPECT_EQ(StackFrame::FRAME_TRUST_FP, frame2->trust);
+ ASSERT_EQ((StackFrameRISCV::CONTEXT_VALID_PC |
+ StackFrameRISCV::CONTEXT_VALID_RA |
+ StackFrameRISCV::CONTEXT_VALID_S0 |
+ StackFrameRISCV::CONTEXT_VALID_SP),
+ frame2->context_validity);
+ EXPECT_EQ(return_address2, frame2->context.pc);
+ EXPECT_EQ(0U, frame2->context.ra);
+ EXPECT_EQ(frame2_sp.Value(), frame2->context.sp);
+ EXPECT_EQ(0U, frame2->context.s0);
+}
+
+struct CFIFixture: public StackwalkerRISCVFixture {
+ CFIFixture() {
+ // Provide a bunch of STACK CFI records; we'll walk to the caller
+ // from every point in this series, expecting to find the same set
+ // of register values.
+ SetModuleSymbols(&module1,
+ // The youngest frame's function.
+ "FUNC 4000 1000 10 enchiridion\n"
+ // Initially, nothing has been pushed on the stack,
+ // and the return address is still in the return
+ // address register (ra).
+ "STACK CFI INIT 4000 100 .cfa: sp 0 + .ra: ra\n"
+ // Push s1, s2, the frame pointer (s0) and the
+ // return address register.
+ "STACK CFI 4001 .cfa: sp 16 + .ra: .cfa -4 + ^"
+ " s1: .cfa -16 + ^ s2: .cfa -12 + ^ "
+ " s0: .cfa -8 + ^\n"
+ // Save s1..s4 in a1..a4: verify that we populate
+ // the youngest frame with all the values we have.
+ "STACK CFI 4002 s1: a1 s2: a2 s3: a3 s4: a4\n"
+ // Restore s1..s4. Save the non-callee-saves register a2.
+ "STACK CFI 4003 .cfa: sp 20 + a2: .cfa 20 - ^"
+ " s1: s1 s2: s2 s3: s3 s4: s4\n"
+ // Move the .cfa back eight bytes, to point at the return
+ // address, and restore the sp explicitly.
+ "STACK CFI 4005 .cfa: sp 16 + a2: .cfa 16 - ^"
+ " s0: .cfa 4 - ^ .ra: .cfa ^ sp: .cfa 4 +\n"
+ // Recover the PC explicitly from a new stack slot;
+ // provide garbage for the .ra.
+ "STACK CFI 4006 .cfa: sp 20 + pc: .cfa 20 - ^\n"
+
+ // The calling function.
+ "FUNC 5000 1000 10 epictetus\n"
+ // Mark it as end of stack.
+ "STACK CFI INIT 5000 1000 .cfa: 0 .ra: 0\n"
+
+ // A function whose CFI makes the stack pointer
+ // go backwards.
+ "FUNC 6000 1000 20 palinal\n"
+ "STACK CFI INIT 6000 1000 .cfa: sp 4 - .ra: ra\n"
+
+ // A function with CFI expressions that can't be
+ // evaluated.
+ "FUNC 7000 1000 20 rhetorical\n"
+ "STACK CFI INIT 7000 1000 .cfa: moot .ra: ambiguous\n");
+
+ // Provide some distinctive values for the caller's registers.
+ expected.pc = 0x40005510;
+ expected.sp = 0x80000000;
+ expected.s1 = 0xb5d55e68;
+ expected.s2 = 0xebd134f3;
+ expected.s3 = 0xa31e74bc;
+ expected.s4 = 0x2dcb16b3;
+ expected.s5 = 0x2ada2137;
+ expected.s6 = 0xbbbb557d;
+ expected.s7 = 0x48bf8ca7;
+ expected.s8 = 0xab4621f0;
+ expected.s9 = 0x32b71467;
+ expected.s10 = 0xa673645f;
+ expected.s11 = 0xa673645f;
+ expected.s0 = 0x8112e110;
+
+ // Expect CFI to recover all callee-saves registers. Since CFI is the
+ // only stack frame construction technique we have, aside from the
+ // context frame itself, there's no way for us to have a set of valid
+ // registers smaller than this.
+ expected_validity = (StackFrameRISCV::CONTEXT_VALID_PC |
+ StackFrameRISCV::CONTEXT_VALID_SP |
+ StackFrameRISCV::CONTEXT_VALID_S1 |
+ StackFrameRISCV::CONTEXT_VALID_S2 |
+ StackFrameRISCV::CONTEXT_VALID_S3 |
+ StackFrameRISCV::CONTEXT_VALID_S4 |
+ StackFrameRISCV::CONTEXT_VALID_S5 |
+ StackFrameRISCV::CONTEXT_VALID_S6 |
+ StackFrameRISCV::CONTEXT_VALID_S7 |
+ StackFrameRISCV::CONTEXT_VALID_S8 |
+ StackFrameRISCV::CONTEXT_VALID_S9 |
+ StackFrameRISCV::CONTEXT_VALID_S10 |
+ StackFrameRISCV::CONTEXT_VALID_S11 |
+ StackFrameRISCV::CONTEXT_VALID_S0);
+
+ // By default, context frames provide all registers, as normal.
+ context_frame_validity = StackFrameRISCV::CONTEXT_VALID_ALL;
+
+ // By default, registers are unchanged.
+ raw_context = expected;
+ }
+
+ // Walk the stack, using stack_section as the contents of the stack
+ // and raw_context as the current register values. (Set the stack
+ // pointer to the stack's starting address.) Expect two stack
+ // frames; in the older frame, expect the callee-saves registers to
+ // have values matching those in 'expected'.
+ void CheckWalk() {
+ RegionFromSection();
+ raw_context.sp = stack_section.start().Value();
+
+ StackFrameSymbolizer frame_symbolizer(&supplier, &resolver);
+ StackwalkerRISCV walker(&system_info, &raw_context, &stack_region,
+ &modules, &frame_symbolizer);
+ walker.SetContextFrameValidity(context_frame_validity);
+ vector<const CodeModule*> modules_without_symbols;
+ vector<const CodeModule*> modules_with_corrupt_symbols;
+ ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols,
+ &modules_with_corrupt_symbols));
+ ASSERT_EQ(0U, modules_without_symbols.size());
+ ASSERT_EQ(0U, modules_with_corrupt_symbols.size());
+ frames = call_stack.frames();
+ ASSERT_EQ(2U, frames->size());
+
+ StackFrameRISCV *frame0 = static_cast<StackFrameRISCV*>(frames->at(0));
+ EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust);
+ ASSERT_EQ(context_frame_validity, frame0->context_validity);
+ EXPECT_EQ("enchiridion", frame0->function_name);
+ EXPECT_EQ(0x40004000U, frame0->function_base);
+
+ StackFrameRISCV *frame1 = static_cast<StackFrameRISCV*>(frames->at(1));
+ EXPECT_EQ(StackFrame::FRAME_TRUST_CFI, frame1->trust);
+ ASSERT_EQ(expected_validity, frame1->context_validity);
+ if (expected_validity & StackFrameRISCV::CONTEXT_VALID_A2)
+ EXPECT_EQ(expected.a2, frame1->context.a2);
+ if (expected_validity & StackFrameRISCV::CONTEXT_VALID_S1)
+ EXPECT_EQ(expected.s1, frame1->context.s1);
+ if (expected_validity & StackFrameRISCV::CONTEXT_VALID_S2)
+ EXPECT_EQ(expected.s2, frame1->context.s2);
+ if (expected_validity & StackFrameRISCV::CONTEXT_VALID_S3)
+ EXPECT_EQ(expected.s3, frame1->context.s3);
+ if (expected_validity & StackFrameRISCV::CONTEXT_VALID_S4)
+ EXPECT_EQ(expected.s4, frame1->context.s4);
+ if (expected_validity & StackFrameRISCV::CONTEXT_VALID_S5)
+ EXPECT_EQ(expected.s5, frame1->context.s5);
+ if (expected_validity & StackFrameRISCV::CONTEXT_VALID_S6)
+ EXPECT_EQ(expected.s6, frame1->context.s6);
+ if (expected_validity & StackFrameRISCV::CONTEXT_VALID_S7)
+ EXPECT_EQ(expected.s7, frame1->context.s7);
+ if (expected_validity & StackFrameRISCV::CONTEXT_VALID_S8)
+ EXPECT_EQ(expected.s8, frame1->context.s8);
+ if (expected_validity & StackFrameRISCV::CONTEXT_VALID_S9)
+ EXPECT_EQ(expected.s9, frame1->context.s9);
+ if (expected_validity & StackFrameRISCV::CONTEXT_VALID_S10)
+ EXPECT_EQ(expected.s10, frame1->context.s10);
+ if (expected_validity & StackFrameRISCV::CONTEXT_VALID_S11)
+ EXPECT_EQ(expected.s11, frame1->context.s11);
+ if (expected_validity & StackFrameRISCV::CONTEXT_VALID_S0)
+ EXPECT_EQ(expected.s0, frame1->context.s0);
+
+ // We would never have gotten a frame in the first place if the SP
+ // and PC weren't valid or ->instruction weren't set.
+ EXPECT_EQ(expected.sp, frame1->context.sp);
+ EXPECT_EQ(expected.pc, frame1->context.pc);
+ EXPECT_EQ(expected.pc, frame1->instruction + 4);
+ EXPECT_EQ("epictetus", frame1->function_name);
+ }
+
+ // The values we expect to find for the caller's registers.
+ MDRawContextRISCV expected;
+
+ // The validity mask for expected.
+ int expected_validity;
+
+ // The validity mask to impose on the context frame.
+ int context_frame_validity;
+};
+
+class CFI: public CFIFixture, public Test { };
+
+TEST_F(CFI, At4000) {
+ stack_section.start() = expected.sp;
+ raw_context.pc = 0x40004000;
+ raw_context.ra = 0x40005510;
+ CheckWalk();
+}
+
+TEST_F(CFI, At4001) {
+ Label frame1_sp = expected.sp;
+ stack_section
+ .D32(0xb5d55e68) // saved s1
+ .D32(0xebd134f3) // saved s2
+ .D32(0x8112e110) // saved s0
+ .D32(0x40005510) // return address
+ .Mark(&frame1_sp); // This effectively sets stack_section.start().
+ raw_context.pc = 0x40004001;
+ // distinct callee s1, s2 and s0
+ raw_context.s1 = 0xa635adc9;
+ raw_context.s2 = 0x35ac6231;
+ raw_context.s0 = 0xbe145fc4;
+ CheckWalk();
+}
+
+// As above, but unwind from a context that has only the PC and SP.
+TEST_F(CFI, At4001LimitedValidity) {
+ Label frame1_sp = expected.sp;
+ stack_section
+ .D32(0xb5d55e68) // saved s1
+ .D32(0xebd134f3) // saved s2
+ .D32(0x8112e110) // saved s0
+ .D32(0x40005510) // return address
+ .Mark(&frame1_sp); // This effectively sets stack_section.start().
+ context_frame_validity = StackFrameRISCV::CONTEXT_VALID_PC |
+ StackFrameRISCV::CONTEXT_VALID_SP;
+ raw_context.pc = 0x40004001;
+ raw_context.s0 = 0xbe145fc4;
+
+ expected_validity = (StackFrameRISCV::CONTEXT_VALID_PC |
+ StackFrameRISCV::CONTEXT_VALID_SP |
+ StackFrameRISCV::CONTEXT_VALID_S0 |
+ StackFrameRISCV::CONTEXT_VALID_S1 |
+ StackFrameRISCV::CONTEXT_VALID_S2);
+ CheckWalk();
+}
+
+TEST_F(CFI, At4002) {
+ Label frame1_sp = expected.sp;
+ stack_section
+ .D32(0xfb81ff3d) // no longer saved s1
+ .D32(0xebd134f3) // no longer saved s2
+ .D32(0x8112e110) // saved s0
+ .D32(0x40005510) // return address
+ .Mark(&frame1_sp); // This effectively sets stack_section.start().
+ raw_context.pc = 0x40004002;
+ raw_context.a1 = 0xb5d55e68; // saved a1
+ raw_context.a2 = 0xebd134f3; // saved a2
+ raw_context.a3 = 0xa31e74bc; // saved a3
+ raw_context.a4 = 0x2dcb16b3; // saved a4
+ raw_context.s1 = 0xa635adc9; // distinct callee s1
+ raw_context.s2 = 0x35ac6231; // distinct callee s2
+ raw_context.s3 = 0x4356ac45; // distinct callee s3
+ raw_context.s4 = 0x562f2561; // distinct callee s4
+ // distinct callee s0
+ raw_context.s0 = 0xbe145fc4;
+ CheckWalk();
+}
+
+TEST_F(CFI, At4003) {
+ Label frame1_sp = expected.sp;
+ stack_section
+ .D32(0x48c8dd5a) // saved a2 (even though it's not callee-saves)
+ .D32(0xfb81ff3d) // no longer saved s1
+ .D32(0xebd134f3) // no longer saved s2
+ .D32(0x8112e110) // saved s0
+ .D32(0x40005510) // return address
+ .Mark(&frame1_sp); // This effectively sets stack_section.start().
+ raw_context.pc = 0x40004003;
+ // distinct callee a2 and fp
+ raw_context.a2 = 0xfb756319;
+ raw_context.s0 = 0xbe145fc4;
+ // caller's a2
+ expected.a2 = 0x48c8dd5a;
+ expected_validity |= StackFrameRISCV::CONTEXT_VALID_A2;
+ CheckWalk();
+}
+
+// We have no new rule at module offset 0x4004, so the results here should
+// be the same as those at module offset 0x4003.
+TEST_F(CFI, At4004) {
+ Label frame1_sp = expected.sp;
+ stack_section
+ .D32(0x48c8dd5a) // saved a2 (even though it's not callee-saves)
+ .D32(0xfb81ff3d) // no longer saved s1
+ .D32(0xebd134f3) // no longer saved s2
+ .D32(0x8112e110) // saved s0
+ .D32(0x40005510) // return address
+ .Mark(&frame1_sp); // This effectively sets stack_section.start().
+ raw_context.pc = 0x40004004;
+ // distinct callee a2 and s0
+ raw_context.a2 = 0xfb756319;
+ raw_context.s0 = 0xbe145fc4;
+ // caller's a2
+ expected.a2 = 0x48c8dd5a;
+ expected_validity |= StackFrameRISCV::CONTEXT_VALID_A2;
+ CheckWalk();
+}
+
+// Here we move the .cfa, but provide an explicit rule to recover the SP,
+// so again there should be no change in the registers recovered.
+TEST_F(CFI, At4005) {
+ Label frame1_sp = expected.sp;
+ stack_section
+ .D32(0x48c8dd5a) // saved a2 (even though it's not callee-saves)
+ .D32(0xfb81ff3d) // no longer saved s1
+ .D32(0xebd134f3) // no longer saved s2
+ .D32(0x8112e110) // saved s0
+ .D32(0x40005510) // return address
+ .Mark(&frame1_sp); // This effectively sets stack_section.start().
+ raw_context.pc = 0x40004005;
+ raw_context.a2 = 0xfb756319; // distinct callee a2
+ expected.a2 = 0x48c8dd5a; // caller's a2
+ expected_validity |= StackFrameRISCV::CONTEXT_VALID_A2;
+ CheckWalk();
+}
+
+// Here we provide an explicit rule for the PC, and have the saved .ra be
+// bogus.
+TEST_F(CFI, At4006) {
+ Label frame1_sp = expected.sp;
+ stack_section
+ .D32(0x40005510) // saved pc
+ .D32(0x48c8dd5a) // saved a2 (even though it's not callee-saves)
+ .D32(0xfb81ff3d) // no longer saved s1
+ .D32(0xebd134f3) // no longer saved s2
+ .D32(0x8112e110) // saved s0
+ .D32(0x5783f8d1) // .ra rule recovers this, which is garbage
+ .Mark(&frame1_sp); // This effectively sets stack_section.start().
+ raw_context.pc = 0x40004006;
+ raw_context.a2 = 0xfb756319; // distinct callee a2
+ expected.a2 = 0x48c8dd5a; // caller's a2
+ expected_validity |= StackFrameRISCV::CONTEXT_VALID_A2;
+ CheckWalk();
+}
+
+// Check that we reject rules that would cause the stack pointer to
+// move in the wrong direction.
+TEST_F(CFI, RejectBackwards) {
+ raw_context.pc = 0x40006000;
+ raw_context.sp = 0x80000000;
+ raw_context.ra = 0x40005510;
+ StackFrameSymbolizer frame_symbolizer(&supplier, &resolver);
+ StackwalkerRISCV walker(&system_info, &raw_context, &stack_region,
+ &modules, &frame_symbolizer);
+ vector<const CodeModule*> modules_without_symbols;
+ vector<const CodeModule*> modules_with_corrupt_symbols;
+ ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols,
+ &modules_with_corrupt_symbols));
+ ASSERT_EQ(0U, modules_without_symbols.size());
+ ASSERT_EQ(0U, modules_with_corrupt_symbols.size());
+ frames = call_stack.frames();
+ ASSERT_EQ(1U, frames->size());
+}
+
+// Check that we reject rules whose expressions' evaluation fails.
+TEST_F(CFI, RejectBadExpressions) {
+ raw_context.pc = 0x40007000;
+ raw_context.sp = 0x80000000;
+ StackFrameSymbolizer frame_symbolizer(&supplier, &resolver);
+ StackwalkerRISCV walker(&system_info, &raw_context, &stack_region,
+ &modules, &frame_symbolizer);
+ vector<const CodeModule*> modules_without_symbols;
+ vector<const CodeModule*> modules_with_corrupt_symbols;
+ ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols,
+ &modules_with_corrupt_symbols));
+ ASSERT_EQ(0U, modules_without_symbols.size());
+ ASSERT_EQ(0U, modules_with_corrupt_symbols.size());
+ frames = call_stack.frames();
+ ASSERT_EQ(1U, frames->size());
+}
diff --git a/src/processor/stackwalker_selftest.cc b/src/processor/stackwalker_selftest.cc
index f692d4c4..2737f64d 100644
--- a/src/processor/stackwalker_selftest.cc
+++ b/src/processor/stackwalker_selftest.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2006, Google Inc.
-// All rights reserved.
+// Copyright 2006 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -420,7 +419,7 @@ int main(int argc, char** argv) {
// Not i386 or ppc or sparc? We can only test stacks we know how to walk.
-int main(int argc, char **argv) {
+int main(int argc, char** argv) {
BPLOG_INIT(&argc, &argv);
// "make check" interprets an exit status of 77 to mean that the test is
diff --git a/src/processor/stackwalker_selftest_sol.s b/src/processor/stackwalker_selftest_sol.s
index 648b0499..11d1698f 100644
--- a/src/processor/stackwalker_selftest_sol.s
+++ b/src/processor/stackwalker_selftest_sol.s
@@ -1,5 +1,4 @@
-/* Copyright (c) 2007, Google Inc.
- * All rights reserved.
+/* Copyright 2007 Google LLC
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
- * * Neither the name of Google Inc. nor the names of its
+ * * Neither the name of Google LLC nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
diff --git a/src/processor/stackwalker_sparc.cc b/src/processor/stackwalker_sparc.cc
index 4de838af..fb76744c 100644
--- a/src/processor/stackwalker_sparc.cc
+++ b/src/processor/stackwalker_sparc.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2010 Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -112,10 +111,9 @@ StackFrame* StackwalkerSPARC::GetCallerFrame(const CallStack* stack,
}
// Should we terminate the stack walk? (end-of-stack or broken invariant)
- if (TerminateWalk(instruction,
- stack_pointer,
- last_frame->context.g_r[14],
- stack->frames()->size() == 1)) {
+ if (TerminateWalk(instruction, stack_pointer, last_frame->context.g_r[14],
+ /*is_context_frame=*/last_frame->trust ==
+ StackFrame::FRAME_TRUST_CONTEXT)) {
return NULL;
}
diff --git a/src/processor/stackwalker_sparc.h b/src/processor/stackwalker_sparc.h
index e8f2a388..b7ba507e 100644
--- a/src/processor/stackwalker_sparc.h
+++ b/src/processor/stackwalker_sparc.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2010 Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/processor/stackwalker_unittest_utils.h b/src/processor/stackwalker_unittest_utils.h
index 3a92a5ea..3d651b2c 100644
--- a/src/processor/stackwalker_unittest_utils.h
+++ b/src/processor/stackwalker_unittest_utils.h
@@ -1,7 +1,6 @@
// -*- mode: C++ -*-
-// Copyright (c) 2010, Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -13,7 +12,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -57,7 +56,7 @@ class MockMemoryRegion: public google_breakpad::MemoryRegion {
// Set this region's address and contents. If we have placed an
// instance of this class in a test fixture class, individual tests
// can use this to provide the region's contents.
- void Init(uint64_t base_address, const string &contents) {
+ void Init(uint64_t base_address, const string& contents) {
base_address_ = base_address;
contents_ = contents;
}
@@ -65,16 +64,16 @@ class MockMemoryRegion: public google_breakpad::MemoryRegion {
uint64_t GetBase() const { return base_address_; }
uint32_t GetSize() const { return contents_.size(); }
- bool GetMemoryAtAddress(uint64_t address, uint8_t *value) const {
+ bool GetMemoryAtAddress(uint64_t address, uint8_t* value) const {
return GetMemoryLittleEndian(address, value);
}
- bool GetMemoryAtAddress(uint64_t address, uint16_t *value) const {
+ bool GetMemoryAtAddress(uint64_t address, uint16_t* value) const {
return GetMemoryLittleEndian(address, value);
}
- bool GetMemoryAtAddress(uint64_t address, uint32_t *value) const {
+ bool GetMemoryAtAddress(uint64_t address, uint32_t* value) const {
return GetMemoryLittleEndian(address, value);
}
- bool GetMemoryAtAddress(uint64_t address, uint64_t *value) const {
+ bool GetMemoryAtAddress(uint64_t address, uint64_t* value) const {
return GetMemoryLittleEndian(address, value);
}
void Print() const {
@@ -85,7 +84,7 @@ class MockMemoryRegion: public google_breakpad::MemoryRegion {
// Fetch a little-endian value from ADDRESS in contents_ whose size
// is BYTES, and store it in *VALUE. Return true on success.
template<typename ValueType>
- bool GetMemoryLittleEndian(uint64_t address, ValueType *value) const {
+ bool GetMemoryLittleEndian(uint64_t address, ValueType* value) const {
if (address < base_address_ ||
address - base_address_ + sizeof(ValueType) > contents_.size())
return false;
@@ -105,7 +104,7 @@ class MockMemoryRegion: public google_breakpad::MemoryRegion {
class MockCodeModule: public google_breakpad::CodeModule {
public:
MockCodeModule(uint64_t base_address, uint64_t size,
- const string &code_file, const string &version)
+ const string& code_file, const string& version)
: base_address_(base_address), size_(size), code_file_(code_file) { }
uint64_t base_address() const { return base_address_; }
@@ -115,7 +114,7 @@ class MockCodeModule: public google_breakpad::CodeModule {
string debug_file() const { return code_file_; }
string debug_identifier() const { return code_file_; }
string version() const { return version_; }
- google_breakpad::CodeModule *Copy() const {
+ google_breakpad::CodeModule* Copy() const {
abort(); // Tests won't use this.
}
virtual bool is_unloaded() const { return false; }
@@ -134,16 +133,16 @@ class MockCodeModules: public google_breakpad::CodeModules {
typedef google_breakpad::CodeModule CodeModule;
typedef google_breakpad::CodeModules CodeModules;
- void Add(const MockCodeModule *module) {
+ void Add(const MockCodeModule* module) {
modules_.push_back(module);
}
unsigned int module_count() const { return modules_.size(); }
- const CodeModule *GetModuleForAddress(uint64_t address) const {
+ const CodeModule* GetModuleForAddress(uint64_t address) const {
for (ModuleVector::const_iterator i = modules_.begin();
i != modules_.end(); i++) {
- const MockCodeModule *module = *i;
+ const MockCodeModule* module = *i;
if (module->base_address() <= address &&
address - module->base_address() < module->size())
return module;
@@ -151,17 +150,17 @@ class MockCodeModules: public google_breakpad::CodeModules {
return NULL;
};
- const CodeModule *GetMainModule() const { return modules_[0]; }
+ const CodeModule* GetMainModule() const { return modules_[0]; }
- const CodeModule *GetModuleAtSequence(unsigned int sequence) const {
+ const CodeModule* GetModuleAtSequence(unsigned int sequence) const {
return modules_.at(sequence);
}
- const CodeModule *GetModuleAtIndex(unsigned int index) const {
+ const CodeModule* GetModuleAtIndex(unsigned int index) const {
return modules_.at(index);
}
- CodeModules *Copy() const { abort(); } // Tests won't use this
+ CodeModules* Copy() const { abort(); } // Tests won't use this
virtual std::vector<google_breakpad::linked_ptr<const CodeModule> >
GetShrunkRangeModules() const {
@@ -169,7 +168,7 @@ class MockCodeModules: public google_breakpad::CodeModules {
}
private:
- typedef std::vector<const MockCodeModule *> ModuleVector;
+ typedef std::vector<const MockCodeModule*> ModuleVector;
ModuleVector modules_;
};
@@ -177,26 +176,26 @@ class MockSymbolSupplier: public google_breakpad::SymbolSupplier {
public:
typedef google_breakpad::CodeModule CodeModule;
typedef google_breakpad::SystemInfo SystemInfo;
- MOCK_METHOD3(GetSymbolFile, SymbolResult(const CodeModule *module,
- const SystemInfo *system_info,
- string *symbol_file));
- MOCK_METHOD4(GetSymbolFile, SymbolResult(const CodeModule *module,
- const SystemInfo *system_info,
- string *symbol_file,
- string *symbol_data));
- MOCK_METHOD5(GetCStringSymbolData, SymbolResult(const CodeModule *module,
- const SystemInfo *system_info,
- string *symbol_file,
- char **symbol_data,
- size_t *symbol_data_size));
- MOCK_METHOD1(FreeSymbolData, void(const CodeModule *module));
+ MOCK_METHOD3(GetSymbolFile, SymbolResult(const CodeModule* module,
+ const SystemInfo* system_info,
+ string* symbol_file));
+ MOCK_METHOD4(GetSymbolFile, SymbolResult(const CodeModule* module,
+ const SystemInfo* system_info,
+ string* symbol_file,
+ string* symbol_data));
+ MOCK_METHOD5(GetCStringSymbolData, SymbolResult(const CodeModule* module,
+ const SystemInfo* system_info,
+ string* symbol_file,
+ char** symbol_data,
+ size_t* symbol_data_size));
+ MOCK_METHOD1(FreeSymbolData, void(const CodeModule* module));
// Copies the passed string contents into a newly allocated buffer.
// The newly allocated buffer will be freed during destruction.
- char* CopySymbolDataAndOwnTheCopy(const string &info,
- size_t *symbol_data_size) {
+ char* CopySymbolDataAndOwnTheCopy(const string& info,
+ size_t* symbol_data_size) {
*symbol_data_size = info.size() + 1;
- char *symbol_data = new char[*symbol_data_size];
+ char* symbol_data = new char[*symbol_data_size];
memcpy(symbol_data, info.c_str(), info.size());
symbol_data[info.size()] = '\0';
symbol_data_to_free_.push_back(symbol_data);
diff --git a/src/processor/stackwalker_x86.cc b/src/processor/stackwalker_x86.cc
index ed2b383d..b598c5bd 100644
--- a/src/processor/stackwalker_x86.cc
+++ b/src/processor/stackwalker_x86.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2010 Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -136,11 +135,14 @@ StackFrame* StackwalkerX86::GetContextFrame() {
}
StackFrameX86* StackwalkerX86::GetCallerByWindowsFrameInfo(
- const vector<StackFrame*> &frames,
+ const vector<StackFrame*>& frames,
WindowsFrameInfo* last_frame_info,
bool stack_scan_allowed) {
StackFrame::FrameTrust trust = StackFrame::FRAME_TRUST_NONE;
+ // The last frame can never be inline. A sequence of inline frames always
+ // finishes with a conventional frame.
+ assert(frames.back()->trust != StackFrame::FRAME_TRUST_INLINE);
StackFrameX86* last_frame = static_cast<StackFrameX86*>(frames.back());
// Save the stack walking info we found, in case we need it later to
@@ -187,9 +189,15 @@ StackFrameX86* StackwalkerX86::GetCallerByWindowsFrameInfo(
uint32_t last_frame_callee_parameter_size = 0;
int frames_already_walked = frames.size();
- if (frames_already_walked >= 2) {
+ for (int last_frame_callee_id = frames_already_walked - 2;
+ last_frame_callee_id >= 0; last_frame_callee_id--) {
+ // Searching for a real callee frame. Skipping inline frames since they
+ // cannot be downcasted to StackFrameX86.
+ if (frames[last_frame_callee_id]->trust == StackFrame::FRAME_TRUST_INLINE) {
+ continue;
+ }
const StackFrameX86* last_frame_callee
- = static_cast<StackFrameX86*>(frames[frames_already_walked - 2]);
+ = static_cast<StackFrameX86*>(frames[last_frame_callee_id]);
WindowsFrameInfo* last_frame_callee_info
= last_frame_callee->windows_frame_info;
if (last_frame_callee_info &&
@@ -385,9 +393,10 @@ StackFrameX86* StackwalkerX86::GetCallerByWindowsFrameInfo(
// frame pointer.
uint32_t location_start = last_frame->context.esp;
uint32_t location, eip;
- if (!stack_scan_allowed
- || !ScanForReturnAddress(location_start, &location, &eip,
- frames.size() == 1 /* is_context_frame */)) {
+ if (!stack_scan_allowed ||
+ !ScanForReturnAddress(location_start, &location, &eip,
+ /*is_context_frame=*/last_frame->trust ==
+ StackFrame::FRAME_TRUST_CONTEXT)) {
// if we can't find an instruction pointer even with stack scanning,
// give up.
return NULL;
@@ -429,9 +438,10 @@ StackFrameX86* StackwalkerX86::GetCallerByWindowsFrameInfo(
// looking one 32-bit word above that location.
uint32_t location_start = dictionary[".raSearchStart"] + 4;
uint32_t location;
- if (stack_scan_allowed
- && ScanForReturnAddress(location_start, &location, &eip,
- frames.size() == 1 /* is_context_frame */)) {
+ if (stack_scan_allowed &&
+ ScanForReturnAddress(location_start, &location, &eip,
+ /*is_context_frame=*/last_frame->trust ==
+ StackFrame::FRAME_TRUST_CONTEXT)) {
// This is a better return address that what program string
// evaluation found. Use it, and set %esp to the location above the
// one where the return address was found.
@@ -514,8 +524,11 @@ StackFrameX86* StackwalkerX86::GetCallerByWindowsFrameInfo(
}
StackFrameX86* StackwalkerX86::GetCallerByCFIFrameInfo(
- const vector<StackFrame*> &frames,
+ const vector<StackFrame*>& frames,
CFIFrameInfo* cfi_frame_info) {
+ // The last frame can never be inline. A sequence of inline frames always
+ // finishes with a conventional frame.
+ assert(frames.back()->trust != StackFrame::FRAME_TRUST_INLINE);
StackFrameX86* last_frame = static_cast<StackFrameX86*>(frames.back());
last_frame->cfi_frame_info = cfi_frame_info;
@@ -539,9 +552,12 @@ StackFrameX86* StackwalkerX86::GetCallerByCFIFrameInfo(
}
StackFrameX86* StackwalkerX86::GetCallerByEBPAtBase(
- const vector<StackFrame*> &frames,
+ const vector<StackFrame*>& frames,
bool stack_scan_allowed) {
StackFrame::FrameTrust trust;
+ // The last frame can never be inline. A sequence of inline frames always
+ // finishes with a conventional frame.
+ assert(frames.back()->trust != StackFrame::FRAME_TRUST_INLINE);
StackFrameX86* last_frame = static_cast<StackFrameX86*>(frames.back());
uint32_t last_esp = last_frame->context.esp;
uint32_t last_ebp = last_frame->context.ebp;
@@ -581,9 +597,10 @@ StackFrameX86* StackwalkerX86::GetCallerByEBPAtBase(
// return address. This can happen if last_frame is executing code
// for a module for which we don't have symbols, and that module
// is compiled without a frame pointer.
- if (!stack_scan_allowed
- || !ScanForReturnAddress(last_esp, &caller_esp, &caller_eip,
- frames.size() == 1 /* is_context_frame */)) {
+ if (!stack_scan_allowed ||
+ !ScanForReturnAddress(last_esp, &caller_esp, &caller_eip,
+ /*is_context_frame=*/last_frame->trust ==
+ StackFrame::FRAME_TRUST_CONTEXT)) {
// if we can't find an instruction pointer even with stack scanning,
// give up.
return NULL;
@@ -632,8 +649,11 @@ StackFrame* StackwalkerX86::GetCallerFrame(const CallStack* stack,
return NULL;
}
- const vector<StackFrame*> &frames = *stack->frames();
+ const vector<StackFrame*>& frames = *stack->frames();
StackFrameX86* last_frame = static_cast<StackFrameX86*>(frames.back());
+ // The last frame can never be inline. A sequence of inline frames always
+ // finishes with a conventional frame.
+ assert(last_frame->trust != StackFrame::FRAME_TRUST_INLINE);
scoped_ptr<StackFrameX86> new_frame;
// If the resolver has Windows stack walking information, use that.
@@ -660,10 +680,10 @@ StackFrame* StackwalkerX86::GetCallerFrame(const CallStack* stack,
return NULL;
// Should we terminate the stack walk? (end-of-stack or broken invariant)
- if (TerminateWalk(new_frame->context.eip,
- new_frame->context.esp,
+ if (TerminateWalk(new_frame->context.eip, new_frame->context.esp,
last_frame->context.esp,
- frames.size() == 1)) {
+ /*first_unwind=*/last_frame->trust ==
+ StackFrame::FRAME_TRUST_CONTEXT)) {
return NULL;
}
diff --git a/src/processor/stackwalker_x86.h b/src/processor/stackwalker_x86.h
index 0659a13b..1867a689 100644
--- a/src/processor/stackwalker_x86.h
+++ b/src/processor/stackwalker_x86.h
@@ -1,7 +1,6 @@
// -*- mode: c++ -*-
-// Copyright (c) 2010 Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -13,7 +12,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -81,14 +80,14 @@ class StackwalkerX86 : public Stackwalker {
// to construct the frame that called frames.back(). The caller
// takes ownership of the returned frame. Return NULL on failure.
StackFrameX86* GetCallerByWindowsFrameInfo(
- const vector<StackFrame*> &frames,
+ const vector<StackFrame*>& frames,
WindowsFrameInfo* windows_frame_info,
bool stack_scan_allowed);
// Use cfi_frame_info (derived from STACK CFI records) to construct
// the frame that called frames.back(). The caller takes ownership
// of the returned frame. Return NULL on failure.
- StackFrameX86* GetCallerByCFIFrameInfo(const vector<StackFrame*> &frames,
+ StackFrameX86* GetCallerByCFIFrameInfo(const vector<StackFrame*>& frames,
CFIFrameInfo* cfi_frame_info);
// Assuming a traditional frame layout --- where the caller's %ebp
@@ -96,7 +95,7 @@ class StackwalkerX86 : public Stackwalker {
// %ebp points to the saved %ebp --- construct the frame that called
// frames.back(). The caller takes ownership of the returned frame.
// Return NULL on failure.
- StackFrameX86* GetCallerByEBPAtBase(const vector<StackFrame*> &frames,
+ StackFrameX86* GetCallerByEBPAtBase(const vector<StackFrame*>& frames,
bool stack_scan_allowed);
// Stores the CPU context corresponding to the innermost stack frame to
diff --git a/src/processor/stackwalker_x86_unittest.cc b/src/processor/stackwalker_x86_unittest.cc
index 359f1c86..3d786b8e 100644
--- a/src/processor/stackwalker_x86_unittest.cc
+++ b/src/processor/stackwalker_x86_unittest.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2010, Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -113,7 +112,7 @@ class StackwalkerX86Fixture {
// Set the Breakpad symbol information that supplier should return for
// MODULE to INFO.
- void SetModuleSymbols(MockCodeModule *module, const string &info) {
+ void SetModuleSymbols(MockCodeModule* module, const string& info) {
size_t buffer_size;
char *buffer = supplier.CopySymbolDataAndOwnTheCopy(info, &buffer_size);
EXPECT_CALL(supplier, GetCStringSymbolData(module, &system_info, _, _, _))
@@ -134,7 +133,7 @@ class StackwalkerX86Fixture {
void BrandContext(MDRawContextX86 *raw_context) {
uint8_t x = 173;
for (size_t i = 0; i < sizeof(*raw_context); i++)
- reinterpret_cast<uint8_t *>(raw_context)[i] = (x += 17);
+ reinterpret_cast<uint8_t*>(raw_context)[i] = (x += 17);
}
SystemInfo system_info;
@@ -151,7 +150,7 @@ class StackwalkerX86Fixture {
MockSymbolSupplier supplier;
BasicSourceLineResolver resolver;
CallStack call_stack;
- const vector<StackFrame *> *frames;
+ const vector<StackFrame*>* frames;
};
class SanityCheck: public StackwalkerX86Fixture, public Test { };
@@ -175,7 +174,7 @@ TEST_F(SanityCheck, NoResolver) {
ASSERT_EQ("module1", modules_without_symbols[0]->debug_file());
ASSERT_EQ(0U, modules_with_corrupt_symbols.size());
frames = call_stack.frames();
- StackFrameX86 *frame = static_cast<StackFrameX86 *>(frames->at(0));
+ StackFrameX86 *frame = static_cast<StackFrameX86*>(frames->at(0));
// Check that the values from the original raw context made it
// through to the context in the stack frame.
EXPECT_EQ(0, memcmp(&raw_context, &frame->context, sizeof(raw_context)));
@@ -201,7 +200,7 @@ TEST_F(GetContextFrame, Simple) {
ASSERT_EQ("module1", modules_without_symbols[0]->debug_file());
ASSERT_EQ(0U, modules_with_corrupt_symbols.size());
frames = call_stack.frames();
- StackFrameX86 *frame = static_cast<StackFrameX86 *>(frames->at(0));
+ StackFrameX86 *frame = static_cast<StackFrameX86*>(frames->at(0));
// Check that the values from the original raw context made it
// through to the context in the stack frame.
EXPECT_EQ(0, memcmp(&raw_context, &frame->context, sizeof(raw_context)));
@@ -224,7 +223,7 @@ TEST_F(GetContextFrame, NoStackMemory) {
ASSERT_EQ("module1", modules_without_symbols[0]->debug_file());
ASSERT_EQ(0U, modules_with_corrupt_symbols.size());
frames = call_stack.frames();
- StackFrameX86 *frame = static_cast<StackFrameX86 *>(frames->at(0));
+ StackFrameX86 *frame = static_cast<StackFrameX86*>(frames->at(0));
// Check that the values from the original raw context made it
// through to the context in the stack frame.
EXPECT_EQ(0, memcmp(&raw_context, &frame->context, sizeof(raw_context)));
@@ -269,7 +268,7 @@ TEST_F(GetCallerFrame, Traditional) {
ASSERT_EQ(2U, frames->size());
{ // To avoid reusing locals by mistake
- StackFrameX86 *frame0 = static_cast<StackFrameX86 *>(frames->at(0));
+ StackFrameX86 *frame0 = static_cast<StackFrameX86*>(frames->at(0));
EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust);
EXPECT_EQ(StackFrameX86::CONTEXT_VALID_ALL, frame0->context_validity);
EXPECT_EQ(0x4000c7a5U, frame0->instruction);
@@ -279,7 +278,7 @@ TEST_F(GetCallerFrame, Traditional) {
}
{ // To avoid reusing locals by mistake
- StackFrameX86 *frame1 = static_cast<StackFrameX86 *>(frames->at(1));
+ StackFrameX86 *frame1 = static_cast<StackFrameX86*>(frames->at(1));
EXPECT_EQ(StackFrame::FRAME_TRUST_FP, frame1->trust);
ASSERT_EQ((StackFrameX86::CONTEXT_VALID_EIP
| StackFrameX86::CONTEXT_VALID_ESP
@@ -333,7 +332,7 @@ TEST_F(GetCallerFrame, TraditionalScan) {
ASSERT_EQ(2U, frames->size());
{ // To avoid reusing locals by mistake
- StackFrameX86 *frame0 = static_cast<StackFrameX86 *>(frames->at(0));
+ StackFrameX86 *frame0 = static_cast<StackFrameX86*>(frames->at(0));
EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust);
ASSERT_EQ(StackFrameX86::CONTEXT_VALID_ALL, frame0->context_validity);
EXPECT_EQ(0x4000f49dU, frame0->instruction);
@@ -344,7 +343,7 @@ TEST_F(GetCallerFrame, TraditionalScan) {
}
{ // To avoid reusing locals by mistake
- StackFrameX86 *frame1 = static_cast<StackFrameX86 *>(frames->at(1));
+ StackFrameX86 *frame1 = static_cast<StackFrameX86*>(frames->at(1));
EXPECT_EQ(StackFrame::FRAME_TRUST_SCAN, frame1->trust);
ASSERT_EQ((StackFrameX86::CONTEXT_VALID_EIP
| StackFrameX86::CONTEXT_VALID_ESP
@@ -399,7 +398,7 @@ TEST_F(GetCallerFrame, TraditionalScanLongWay) {
ASSERT_EQ(2U, frames->size());
{ // To avoid reusing locals by mistake
- StackFrameX86 *frame0 = static_cast<StackFrameX86 *>(frames->at(0));
+ StackFrameX86 *frame0 = static_cast<StackFrameX86*>(frames->at(0));
EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust);
ASSERT_EQ(StackFrameX86::CONTEXT_VALID_ALL, frame0->context_validity);
EXPECT_EQ(0x4000f49dU, frame0->instruction);
@@ -410,7 +409,7 @@ TEST_F(GetCallerFrame, TraditionalScanLongWay) {
}
{ // To avoid reusing locals by mistake
- StackFrameX86 *frame1 = static_cast<StackFrameX86 *>(frames->at(1));
+ StackFrameX86 *frame1 = static_cast<StackFrameX86*>(frames->at(1));
EXPECT_EQ(StackFrame::FRAME_TRUST_SCAN, frame1->trust);
ASSERT_EQ((StackFrameX86::CONTEXT_VALID_EIP
| StackFrameX86::CONTEXT_VALID_ESP
@@ -465,7 +464,7 @@ TEST_F(GetCallerFrame, ScanningNotAllowed) {
ASSERT_EQ(1U, frames->size());
{ // To avoid reusing locals by mistake
- StackFrameX86 *frame0 = static_cast<StackFrameX86 *>(frames->at(0));
+ StackFrameX86 *frame0 = static_cast<StackFrameX86*>(frames->at(0));
EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust);
ASSERT_EQ(StackFrameX86::CONTEXT_VALID_ALL, frame0->context_validity);
EXPECT_EQ(0x4000f49dU, frame0->instruction);
@@ -524,7 +523,7 @@ TEST_F(GetCallerFrame, WindowsFrameData) {
ASSERT_EQ(2U, frames->size());
{ // To avoid reusing locals by mistake
- StackFrameX86 *frame0 = static_cast<StackFrameX86 *>(frames->at(0));
+ StackFrameX86 *frame0 = static_cast<StackFrameX86*>(frames->at(0));
EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust);
ASSERT_EQ(StackFrameX86::CONTEXT_VALID_ALL, frame0->context_validity);
EXPECT_EQ(0x4000aa85U, frame0->instruction);
@@ -535,7 +534,7 @@ TEST_F(GetCallerFrame, WindowsFrameData) {
}
{ // To avoid reusing locals by mistake
- StackFrameX86 *frame1 = static_cast<StackFrameX86 *>(frames->at(1));
+ StackFrameX86 *frame1 = static_cast<StackFrameX86*>(frames->at(1));
EXPECT_EQ(StackFrame::FRAME_TRUST_CFI, frame1->trust);
ASSERT_EQ((StackFrameX86::CONTEXT_VALID_EIP
| StackFrameX86::CONTEXT_VALID_ESP
@@ -605,7 +604,7 @@ TEST_F(GetCallerFrame, WindowsFrameDataAligned) {
ASSERT_EQ(2U, frames->size());
{ // To avoid reusing locals by mistake
- StackFrameX86 *frame0 = static_cast<StackFrameX86 *>(frames->at(0));
+ StackFrameX86 *frame0 = static_cast<StackFrameX86*>(frames->at(0));
EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust);
ASSERT_EQ(StackFrameX86::CONTEXT_VALID_ALL, frame0->context_validity);
EXPECT_EQ(0x4000aa85U, frame0->instruction);
@@ -616,7 +615,7 @@ TEST_F(GetCallerFrame, WindowsFrameDataAligned) {
}
{ // To avoid reusing locals by mistake
- StackFrameX86 *frame1 = static_cast<StackFrameX86 *>(frames->at(1));
+ StackFrameX86 *frame1 = static_cast<StackFrameX86*>(frames->at(1));
EXPECT_EQ(StackFrame::FRAME_TRUST_CFI, frame1->trust);
ASSERT_EQ((StackFrameX86::CONTEXT_VALID_EIP
| StackFrameX86::CONTEXT_VALID_ESP
@@ -693,7 +692,7 @@ TEST_F(GetCallerFrame, WindowsFrameDataParameterSize) {
ASSERT_EQ(3U, frames->size());
{ // To avoid reusing locals by mistake
- StackFrameX86 *frame0 = static_cast<StackFrameX86 *>(frames->at(0));
+ StackFrameX86 *frame0 = static_cast<StackFrameX86*>(frames->at(0));
EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust);
ASSERT_EQ(StackFrameX86::CONTEXT_VALID_ALL, frame0->context_validity);
EXPECT_EQ(0x40001004U, frame0->instruction);
@@ -714,7 +713,7 @@ TEST_F(GetCallerFrame, WindowsFrameDataParameterSize) {
}
{ // To avoid reusing locals by mistake
- StackFrameX86 *frame1 = static_cast<StackFrameX86 *>(frames->at(1));
+ StackFrameX86 *frame1 = static_cast<StackFrameX86*>(frames->at(1));
EXPECT_EQ(StackFrame::FRAME_TRUST_FP, frame1->trust);
ASSERT_EQ((StackFrameX86::CONTEXT_VALID_EIP
| StackFrameX86::CONTEXT_VALID_ESP
@@ -737,7 +736,7 @@ TEST_F(GetCallerFrame, WindowsFrameDataParameterSize) {
}
{ // To avoid reusing locals by mistake
- StackFrameX86 *frame2 = static_cast<StackFrameX86 *>(frames->at(2));
+ StackFrameX86 *frame2 = static_cast<StackFrameX86*>(frames->at(2));
EXPECT_EQ(StackFrame::FRAME_TRUST_CFI, frame2->trust);
ASSERT_EQ((StackFrameX86::CONTEXT_VALID_EIP
| StackFrameX86::CONTEXT_VALID_ESP
@@ -793,7 +792,7 @@ TEST_F(GetCallerFrame, WindowsFrameDataScan) {
ASSERT_EQ(2U, frames->size());
{ // To avoid reusing locals by mistake
- StackFrameX86 *frame0 = static_cast<StackFrameX86 *>(frames->at(0));
+ StackFrameX86 *frame0 = static_cast<StackFrameX86*>(frames->at(0));
EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust);
ASSERT_EQ(StackFrameX86::CONTEXT_VALID_ALL, frame0->context_validity);
EXPECT_EQ(0x40000c9cU, frame0->instruction);
@@ -804,7 +803,7 @@ TEST_F(GetCallerFrame, WindowsFrameDataScan) {
}
{ // To avoid reusing locals by mistake
- StackFrameX86 *frame1 = static_cast<StackFrameX86 *>(frames->at(1));
+ StackFrameX86 *frame1 = static_cast<StackFrameX86*>(frames->at(1));
EXPECT_EQ(StackFrame::FRAME_TRUST_SCAN, frame1->trust);
// I'd argue that CONTEXT_VALID_EBP shouldn't be here, since the walker
// does not actually fetch the EBP after a scan (forcing the next frame
@@ -882,7 +881,7 @@ TEST_F(GetCallerFrame, WindowsFrameDataBadEIPScan) {
ASSERT_EQ(2U, frames->size());
{ // To avoid reusing locals by mistake
- StackFrameX86 *frame0 = static_cast<StackFrameX86 *>(frames->at(0));
+ StackFrameX86 *frame0 = static_cast<StackFrameX86*>(frames->at(0));
EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust);
ASSERT_EQ(StackFrameX86::CONTEXT_VALID_ALL, frame0->context_validity);
EXPECT_EQ(0x40000700U, frame0->instruction);
@@ -893,7 +892,7 @@ TEST_F(GetCallerFrame, WindowsFrameDataBadEIPScan) {
}
{ // To avoid reusing locals by mistake
- StackFrameX86 *frame1 = static_cast<StackFrameX86 *>(frames->at(1));
+ StackFrameX86 *frame1 = static_cast<StackFrameX86*>(frames->at(1));
EXPECT_EQ(StackFrame::FRAME_TRUST_CFI_SCAN, frame1->trust);
// I'd argue that CONTEXT_VALID_EBP shouldn't be here, since the
// walker does not actually fetch the EBP after a scan (forcing the
@@ -955,7 +954,7 @@ TEST_F(GetCallerFrame, WindowsFPOUnchangedEBP) {
ASSERT_EQ(2U, frames->size());
{ // To avoid reusing locals by mistake
- StackFrameX86 *frame0 = static_cast<StackFrameX86 *>(frames->at(0));
+ StackFrameX86 *frame0 = static_cast<StackFrameX86*>(frames->at(0));
EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust);
ASSERT_EQ(StackFrameX86::CONTEXT_VALID_ALL, frame0->context_validity);
EXPECT_EQ(0x4000e8b8U, frame0->instruction);
@@ -976,7 +975,7 @@ TEST_F(GetCallerFrame, WindowsFPOUnchangedEBP) {
}
{ // To avoid reusing locals by mistake
- StackFrameX86 *frame1 = static_cast<StackFrameX86 *>(frames->at(1));
+ StackFrameX86 *frame1 = static_cast<StackFrameX86*>(frames->at(1));
EXPECT_EQ(StackFrame::FRAME_TRUST_CFI, frame1->trust);
ASSERT_EQ((StackFrameX86::CONTEXT_VALID_EIP
| StackFrameX86::CONTEXT_VALID_ESP
@@ -1039,7 +1038,7 @@ TEST_F(GetCallerFrame, WindowsFPOUsedEBP) {
ASSERT_EQ(2U, frames->size());
{ // To avoid reusing locals by mistake
- StackFrameX86 *frame0 = static_cast<StackFrameX86 *>(frames->at(0));
+ StackFrameX86 *frame0 = static_cast<StackFrameX86*>(frames->at(0));
EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust);
ASSERT_EQ(StackFrameX86::CONTEXT_VALID_ALL, frame0->context_validity);
EXPECT_EQ(0x40009ab8U, frame0->instruction);
@@ -1060,7 +1059,7 @@ TEST_F(GetCallerFrame, WindowsFPOUsedEBP) {
}
{ // To avoid reusing locals by mistake
- StackFrameX86 *frame1 = static_cast<StackFrameX86 *>(frames->at(1));
+ StackFrameX86 *frame1 = static_cast<StackFrameX86*>(frames->at(1));
EXPECT_EQ(StackFrame::FRAME_TRUST_CFI, frame1->trust);
ASSERT_EQ((StackFrameX86::CONTEXT_VALID_EIP
| StackFrameX86::CONTEXT_VALID_ESP
@@ -1170,8 +1169,8 @@ TEST_F(GetCallerFrame, WindowsFPOReferencesEBX) {
StackFrameSymbolizer frame_symbolizer(&supplier, &resolver);
StackwalkerX86 walker(&system_info, &raw_context, &stack_region, &modules,
&frame_symbolizer);
- vector<const CodeModule *> modules_without_symbols;
- vector<const CodeModule *> modules_with_corrupt_symbols;
+ vector<const CodeModule*> modules_without_symbols;
+ vector<const CodeModule*> modules_with_corrupt_symbols;
ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols,
&modules_with_corrupt_symbols));
ASSERT_EQ(0U, modules_without_symbols.size());
@@ -1180,31 +1179,31 @@ TEST_F(GetCallerFrame, WindowsFPOReferencesEBX) {
ASSERT_EQ(5U, frames->size());
{
- const StackFrameX86 &frame = *static_cast<StackFrameX86 *>(frames->at(0));
+ const StackFrameX86& frame = *static_cast<StackFrameX86*>(frames->at(0));
EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame.trust);
EXPECT_EQ(0x77726bf4U, frame.context.eip);
EXPECT_EQ("KiFastSystemCallRet", frame.function_name);
}
{
- const StackFrameX86 &frame = *static_cast<StackFrameX86 *>(frames->at(1));
+ const StackFrameX86& frame = *static_cast<StackFrameX86*>(frames->at(1));
EXPECT_EQ(StackFrame::FRAME_TRUST_CFI, frame.trust);
EXPECT_EQ(0x7772655cU, frame.context.eip);
EXPECT_EQ("NtWaitForKeyedEvent", frame.function_name);
}
{
- const StackFrameX86 &frame = *static_cast<StackFrameX86 *>(frames->at(2));
+ const StackFrameX86& frame = *static_cast<StackFrameX86*>(frames->at(2));
EXPECT_EQ(StackFrame::FRAME_TRUST_CFI, frame.trust);
EXPECT_EQ(0x776e4a3fU, frame.context.eip);
EXPECT_EQ("RtlSleepConditionVariableSRW", frame.function_name);
}
{
- const StackFrameX86 &frame = *static_cast<StackFrameX86 *>(frames->at(3));
+ const StackFrameX86& frame = *static_cast<StackFrameX86*>(frames->at(3));
EXPECT_EQ(StackFrame::FRAME_TRUST_CFI, frame.trust);
EXPECT_EQ(0x7728219eU, frame.context.eip);
EXPECT_EQ("SleepConditionVariableSRW", frame.function_name);
}
{
- const StackFrameX86 &frame = *static_cast<StackFrameX86 *>(frames->at(4));
+ const StackFrameX86& frame = *static_cast<StackFrameX86*>(frames->at(4));
EXPECT_EQ(StackFrame::FRAME_TRUST_CFI, frame.trust);
EXPECT_EQ(0x5ac0486cU, frame.context.eip);
EXPECT_EQ("base::ConditionVariable::TimedWait", frame.function_name);
@@ -1318,7 +1317,7 @@ TEST_F(GetCallerFrame, WindowsFPOSystemCall) {
ASSERT_EQ(4U, frames->size());
{ // To avoid reusing locals by mistake
- StackFrameX86 *frame0 = static_cast<StackFrameX86 *>(frames->at(0));
+ StackFrameX86 *frame0 = static_cast<StackFrameX86*>(frames->at(0));
EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust);
ASSERT_EQ(StackFrameX86::CONTEXT_VALID_ALL, frame0->context_validity);
EXPECT_EQ(0x771ef8c1U, frame0->instruction);
@@ -1338,7 +1337,7 @@ TEST_F(GetCallerFrame, WindowsFPOSystemCall) {
}
{ // To avoid reusing locals by mistake
- StackFrameX86 *frame1 = static_cast<StackFrameX86 *>(frames->at(1));
+ StackFrameX86 *frame1 = static_cast<StackFrameX86*>(frames->at(1));
EXPECT_EQ(StackFrame::FRAME_TRUST_CFI, frame1->trust);
ASSERT_EQ((StackFrameX86::CONTEXT_VALID_EIP
| StackFrameX86::CONTEXT_VALID_ESP
@@ -1532,7 +1531,7 @@ TEST_F(GetCallerFrame, ReturnAddressIsNotInKnownModule) {
ASSERT_EQ(3U, frames->size());
{ // To avoid reusing locals by mistake
- StackFrameX86 *frame0 = static_cast<StackFrameX86 *>(frames->at(0));
+ StackFrameX86 *frame0 = static_cast<StackFrameX86*>(frames->at(0));
EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust);
ASSERT_EQ(StackFrameX86::CONTEXT_VALID_ALL, frame0->context_validity);
EXPECT_EQ(0x77c181cdU, frame0->instruction);
@@ -1554,7 +1553,7 @@ TEST_F(GetCallerFrame, ReturnAddressIsNotInKnownModule) {
}
{ // To avoid reusing locals by mistake
- StackFrameX86 *frame1 = static_cast<StackFrameX86 *>(frames->at(1));
+ StackFrameX86 *frame1 = static_cast<StackFrameX86*>(frames->at(1));
EXPECT_EQ(StackFrame::FRAME_TRUST_CFI_SCAN, frame1->trust);
ASSERT_EQ((StackFrameX86::CONTEXT_VALID_EIP |
StackFrameX86::CONTEXT_VALID_ESP |
@@ -1578,7 +1577,7 @@ TEST_F(GetCallerFrame, ReturnAddressIsNotInKnownModule) {
}
{ // To avoid reusing locals by mistake
- StackFrameX86 *frame2 = static_cast<StackFrameX86 *>(frames->at(2));
+ StackFrameX86 *frame2 = static_cast<StackFrameX86*>(frames->at(2));
EXPECT_EQ(StackFrame::FRAME_TRUST_CFI, frame2->trust);
ASSERT_EQ((StackFrameX86::CONTEXT_VALID_EIP |
StackFrameX86::CONTEXT_VALID_ESP |
@@ -1610,7 +1609,7 @@ TEST_F(GetCallerFrame, HandleAlignmentInProgramString) {
MockCodeModule chrome_dll(0x59630000, 0x19e3000, "chrome.dll", "version1");
SetModuleSymbols(&chrome_dll, // chrome.dll
"FUNC 56422 50c 8 base::MessageLoop::RunTask"
- "(base::PendingTask const &)\n"
+ "(base::PendingTask const&)\n"
"56422 e 458 4589\n"
"STACK WIN 4 56422 50c 11 0 8 c ac 0 1 $T1 .raSearch = $T0 "
"$T1 4 - 8 @ = $ebp $T1 4 - ^ = $eip $T1 ^ = $esp $T1 4 + = "
@@ -1627,7 +1626,7 @@ TEST_F(GetCallerFrame, HandleAlignmentInProgramString) {
"$T1 4 - 64 @ = $ebp $T1 4 - ^ = $eip $T1 ^ = $esp $T1 4 + "
"= $20 $T0 56 - ^ = $23 $T0 60 - ^ = $24 $T0 64 - ^ =\n"
"FUNC 55bf0 49 4 base::MessagePumpWin::Run(base::"
- "MessagePump::Delegate *)\n"
+ "MessagePump::Delegate*)\n"
"55bf0 49 48 4724\n"
"STACK WIN 4 55bf0 49 c 0 4 0 10 0 1 $T0 $ebp = $eip $T0 4 "
"+ ^ = $ebp $T0 ^ = $esp $T0 8 + =\n"
@@ -1735,7 +1734,7 @@ TEST_F(GetCallerFrame, HandleAlignmentInProgramString) {
ASSERT_EQ(3U, frames->size());
{ // To avoid reusing locals by mistake
- StackFrameX86 *frame = static_cast<StackFrameX86 *>(frames->at(0));
+ StackFrameX86 *frame = static_cast<StackFrameX86*>(frames->at(0));
EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame->trust);
ASSERT_EQ(StackFrameX86::CONTEXT_VALID_ALL, frame->context_validity);
EXPECT_EQ("base::MessagePumpForIO::DoRunLoop()", frame->function_name);
@@ -1756,13 +1755,13 @@ TEST_F(GetCallerFrame, HandleAlignmentInProgramString) {
}
{ // To avoid reusing locals by mistake
- StackFrameX86 *frame = static_cast<StackFrameX86 *>(frames->at(1));
+ StackFrameX86 *frame = static_cast<StackFrameX86*>(frames->at(1));
EXPECT_EQ(StackFrame::FRAME_TRUST_CFI, frame->trust);
ASSERT_EQ((StackFrameX86::CONTEXT_VALID_EIP |
StackFrameX86::CONTEXT_VALID_ESP |
StackFrameX86::CONTEXT_VALID_EBP),
frame->context_validity);
- EXPECT_EQ("base::MessagePumpWin::Run(base::MessagePump::Delegate *)",
+ EXPECT_EQ("base::MessagePumpWin::Run(base::MessagePump::Delegate*)",
frame->function_name);
EXPECT_EQ(1500011566U, frame->instruction + 1);
EXPECT_EQ(1500011566U, frame->context.eip);
@@ -1779,7 +1778,7 @@ TEST_F(GetCallerFrame, HandleAlignmentInProgramString) {
}
{ // To avoid reusing locals by mistake
- StackFrameX86 *frame = static_cast<StackFrameX86 *>(frames->at(2));
+ StackFrameX86 *frame = static_cast<StackFrameX86*>(frames->at(2));
EXPECT_EQ(StackFrame::FRAME_TRUST_CFI, frame->trust);
ASSERT_EQ((StackFrameX86::CONTEXT_VALID_EIP |
StackFrameX86::CONTEXT_VALID_ESP |
@@ -1984,7 +1983,7 @@ void GetCallerFrame::IPAddressIsNotInKnownModuleTestImpl(
ASSERT_EQ(4U, frames->size());
{ // To avoid reusing locals by mistake
- StackFrameX86 *frame0 = static_cast<StackFrameX86 *>(frames->at(0));
+ StackFrameX86 *frame0 = static_cast<StackFrameX86*>(frames->at(0));
EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust);
ASSERT_EQ(StackFrameX86::CONTEXT_VALID_ALL, frame0->context_validity);
EXPECT_EQ(raw_context.eip, frame0->context.eip);
@@ -1996,7 +1995,7 @@ void GetCallerFrame::IPAddressIsNotInKnownModuleTestImpl(
}
{ // To avoid reusing locals by mistake
- StackFrameX86 *frame1 = static_cast<StackFrameX86 *>(frames->at(1));
+ StackFrameX86 *frame1 = static_cast<StackFrameX86*>(frames->at(1));
EXPECT_EQ(StackFrame::FRAME_TRUST_SCAN, frame1->trust);
ASSERT_EQ((StackFrameX86::CONTEXT_VALID_EIP |
StackFrameX86::CONTEXT_VALID_ESP |
@@ -2016,7 +2015,7 @@ void GetCallerFrame::IPAddressIsNotInKnownModuleTestImpl(
}
{ // To avoid reusing locals by mistake
- StackFrameX86 *frame2 = static_cast<StackFrameX86 *>(frames->at(2));
+ StackFrameX86 *frame2 = static_cast<StackFrameX86*>(frames->at(2));
EXPECT_EQ(StackFrame::FRAME_TRUST_CFI, frame2->trust);
ASSERT_EQ((StackFrameX86::CONTEXT_VALID_EIP |
StackFrameX86::CONTEXT_VALID_ESP |
@@ -2036,7 +2035,7 @@ void GetCallerFrame::IPAddressIsNotInKnownModuleTestImpl(
}
{ // To avoid reusing locals by mistake
- StackFrameX86 *frame3 = static_cast<StackFrameX86 *>(frames->at(3));
+ StackFrameX86 *frame3 = static_cast<StackFrameX86*>(frames->at(3));
EXPECT_EQ(StackFrame::FRAME_TRUST_CFI, frame3->trust);
ASSERT_EQ((StackFrameX86::CONTEXT_VALID_EIP |
StackFrameX86::CONTEXT_VALID_ESP |
@@ -2126,7 +2125,7 @@ struct CFIFixture: public StackwalkerX86Fixture {
ASSERT_EQ(2U, frames->size());
{ // To avoid reusing locals by mistake
- StackFrameX86 *frame0 = static_cast<StackFrameX86 *>(frames->at(0));
+ StackFrameX86 *frame0 = static_cast<StackFrameX86*>(frames->at(0));
EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust);
ASSERT_EQ(StackFrameX86::CONTEXT_VALID_ALL, frame0->context_validity);
EXPECT_EQ("enchiridion", frame0->function_name);
@@ -2138,7 +2137,7 @@ struct CFIFixture: public StackwalkerX86Fixture {
}
{ // To avoid reusing locals by mistake
- StackFrameX86 *frame1 = static_cast<StackFrameX86 *>(frames->at(1));
+ StackFrameX86 *frame1 = static_cast<StackFrameX86*>(frames->at(1));
EXPECT_EQ(StackFrame::FRAME_TRUST_CFI, frame1->trust);
ASSERT_EQ((StackFrameX86::CONTEXT_VALID_EIP |
StackFrameX86::CONTEXT_VALID_ESP |
diff --git a/src/processor/static_address_map-inl.h b/src/processor/static_address_map-inl.h
index 67e07976..0dd13f84 100644
--- a/src/processor/static_address_map-inl.h
+++ b/src/processor/static_address_map-inl.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2010, Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -44,8 +43,8 @@ namespace google_breakpad {
template<typename AddressType, typename EntryType>
bool StaticAddressMap<AddressType, EntryType>::Retrieve(
- const AddressType &address,
- const EntryType *&entry, AddressType *entry_address) const {
+ const AddressType& address,
+ const EntryType*& entry, AddressType* entry_address) const {
// upper_bound gives the first element whose key is greater than address,
// but we want the first element whose key is less than or equal to address.
diff --git a/src/processor/static_address_map.h b/src/processor/static_address_map.h
index 6bafc667..156ecd63 100644
--- a/src/processor/static_address_map.h
+++ b/src/processor/static_address_map.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2010, Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -52,15 +51,15 @@ template<typename AddressType, typename EntryType>
class StaticAddressMap {
public:
StaticAddressMap(): map_() { }
- explicit StaticAddressMap(const char *map_data): map_(map_data) { }
+ explicit StaticAddressMap(const char* map_data): map_(map_data) { }
// Locates the entry stored at the highest address less than or equal to
// the address argument. If there is no such range, returns false. The
// entry is returned in entry, which is a required argument. If
// entry_address is not NULL, it will be set to the address that the entry
// was stored at.
- bool Retrieve(const AddressType &address,
- const EntryType *&entry, AddressType *entry_address) const;
+ bool Retrieve(const AddressType& address,
+ const EntryType*& entry, AddressType* entry_address) const;
private:
friend class ModuleComparer;
diff --git a/src/processor/static_address_map_unittest.cc b/src/processor/static_address_map_unittest.cc
index 12c735cf..2e206a09 100644
--- a/src/processor/static_address_map_unittest.cc
+++ b/src/processor/static_address_map_unittest.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2010, Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -95,7 +94,7 @@ class TestStaticAddressMap : public ::testing::Test {
int address_test;
string entry;
string entry_test;
- const char *entry_cstring = NULL;
+ const char* entry_cstring = NULL;
bool found;
bool found_test;
@@ -143,11 +142,11 @@ class TestStaticAddressMap : public ::testing::Test {
// Test data sets:
static const int kNumberTestCases = 4;
static const int testsize[];
- int *testdata[kNumberTestCases];
+ int* testdata[kNumberTestCases];
AddrMap addr_map[kNumberTestCases];
TestMap test_map[kNumberTestCases];
- char *map_data[kNumberTestCases];
+ char* map_data[kNumberTestCases];
google_breakpad::AddressMapSerializer<int, string> serializer;
};
@@ -229,7 +228,7 @@ TEST_F(TestStaticAddressMap, Test1000RandomElementsMap) {
}
}
-int main(int argc, char *argv[]) {
+int main(int argc, char* argv[]) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
diff --git a/src/processor/static_contained_range_map-inl.h b/src/processor/static_contained_range_map-inl.h
index 777c7621..60606ddc 100644
--- a/src/processor/static_contained_range_map-inl.h
+++ b/src/processor/static_contained_range_map-inl.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2010, Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -47,7 +46,7 @@ StaticContainedRangeMap<AddressType, EntryType>::StaticContainedRangeMap(
const char *base)
: base_(*(reinterpret_cast<const AddressType*>(base))),
entry_size_(*(reinterpret_cast<const uint32_t*>(base + sizeof(base_)))),
- entry_ptr_(reinterpret_cast<const EntryType *>(
+ entry_ptr_(reinterpret_cast<const EntryType*>(
base + sizeof(base_) + sizeof(entry_size_))),
map_(base + sizeof(base_) + sizeof(entry_size_) + entry_size_) {
if (entry_size_ == 0)
@@ -57,7 +56,7 @@ StaticContainedRangeMap<AddressType, EntryType>::StaticContainedRangeMap(
template<typename AddressType, typename EntryType>
bool StaticContainedRangeMap<AddressType, EntryType>::RetrieveRange(
- const AddressType &address, const EntryType *&entry) const {
+ const AddressType& address, const EntryType*& entry) const {
// Get an iterator to the child range whose high address is equal to or
// greater than the supplied address. If the supplied address is higher
@@ -87,6 +86,23 @@ bool StaticContainedRangeMap<AddressType, EntryType>::RetrieveRange(
return true;
}
+template <typename AddressType, typename EntryType>
+bool StaticContainedRangeMap<AddressType, EntryType>::RetrieveRanges(
+ const AddressType& address,
+ std::vector<const EntryType*>& entries) const {
+ MapConstIterator iterator = map_.lower_bound(address);
+ if (iterator == map_.end())
+ return false;
+ const char* memory_child =
+ reinterpret_cast<const char*>(iterator.GetValuePtr());
+ StaticContainedRangeMap child_map(memory_child);
+ if (address < child_map.base_)
+ return false;
+ child_map.RetrieveRanges(address, entries);
+ entries.push_back(child_map.entry_ptr_);
+ return true;
+}
+
} // namespace google_breakpad
#endif // PROCESSOR_STATIC_CONTAINED_RANGE_MAP_INL_H__
diff --git a/src/processor/static_contained_range_map.h b/src/processor/static_contained_range_map.h
index 6a9b8b7b..86e54666 100644
--- a/src/processor/static_contained_range_map.h
+++ b/src/processor/static_contained_range_map.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2010, Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -42,6 +41,7 @@
#ifndef PROCESSOR_STATIC_CONTAINED_RANGE_MAP_H__
#define PROCESSOR_STATIC_CONTAINED_RANGE_MAP_H__
+#include <vector>
#include "processor/static_map-inl.h"
namespace google_breakpad {
@@ -57,7 +57,12 @@ class StaticContainedRangeMap {
// child ranges, and not the entry contained by |this|. This is necessary
// to support a sparsely-populated root range. If no descendant range
// encompasses the address, returns false.
- bool RetrieveRange(const AddressType &address, const EntryType *&entry) const;
+ bool RetrieveRange(const AddressType& address, const EntryType*& entry) const;
+
+ // Retrieves the vector of entries encompassing the specified address from the
+ // innermost entry to the outermost entry.
+ bool RetrieveRanges(const AddressType& address,
+ std::vector<const EntryType*>& entry) const;
private:
friend class ModuleComparer;
diff --git a/src/processor/static_contained_range_map_unittest.cc b/src/processor/static_contained_range_map_unittest.cc
index 4ee47578..cdc11c1d 100644
--- a/src/processor/static_contained_range_map_unittest.cc
+++ b/src/processor/static_contained_range_map_unittest.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2010, Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -273,6 +272,25 @@ TEST_F(TestStaticCRMMap, TestSingleElementMap) {
ASSERT_EQ(*entry_test, entry);
}
+TEST_F(TestStaticCRMMap, TestRetrieveRangeEntries) {
+ CRMMap crm_map;
+
+ crm_map.StoreRange(2, 5, 0);
+ crm_map.StoreRange(2, 6, 1);
+ crm_map.StoreRange(2, 7, 2);
+
+ unsigned int size;
+ scoped_array<char> serialized_data;
+ serialized_data.reset(serializer_.Serialize(&crm_map, &size));
+ scoped_ptr<TestMap> test_map(new TestMap(serialized_data.get()));
+
+ std::vector<const int*> entry_tests;
+ ASSERT_TRUE(test_map->RetrieveRanges(3, entry_tests));
+ ASSERT_EQ(*entry_tests[0], 0);
+ ASSERT_EQ(*entry_tests[1], 1);
+ ASSERT_EQ(*entry_tests[2], 2);
+}
+
TEST_F(TestStaticCRMMap, RunTestData) {
unsigned int test_high = sizeof(test_data) / sizeof(test_data[0]);
diff --git a/src/processor/static_map-inl.h b/src/processor/static_map-inl.h
index e6aac6ab..f9929efe 100644
--- a/src/processor/static_map-inl.h
+++ b/src/processor/static_map-inl.h
@@ -1,4 +1,4 @@
-// Copyright 2010 Google Inc. All Rights Reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -10,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -59,7 +59,7 @@ StaticMap<Key, Value, Compare>::StaticMap(const char* raw_data)
// find(), lower_bound() and upper_bound() implement binary search algorithm.
template<typename Key, typename Value, typename Compare>
StaticMapIterator<Key, Value, Compare>
-StaticMap<Key, Value, Compare>::find(const Key &key) const {
+StaticMap<Key, Value, Compare>::find(const Key& key) const {
int begin = 0;
int end = num_nodes_;
int middle;
@@ -80,7 +80,7 @@ StaticMap<Key, Value, Compare>::find(const Key &key) const {
template<typename Key, typename Value, typename Compare>
StaticMapIterator<Key, Value, Compare>
-StaticMap<Key, Value, Compare>::lower_bound(const Key &key) const {
+StaticMap<Key, Value, Compare>::lower_bound(const Key& key) const {
int begin = 0;
int end = num_nodes_;
int middle;
@@ -101,7 +101,7 @@ StaticMap<Key, Value, Compare>::lower_bound(const Key &key) const {
template<typename Key, typename Value, typename Compare>
StaticMapIterator<Key, Value, Compare>
-StaticMap<Key, Value, Compare>::upper_bound(const Key &key) const {
+StaticMap<Key, Value, Compare>::upper_bound(const Key& key) const {
int begin = 0;
int end = num_nodes_;
int middle;
diff --git a/src/processor/static_map.h b/src/processor/static_map.h
index 9723ab2a..a8f49582 100644
--- a/src/processor/static_map.h
+++ b/src/processor/static_map.h
@@ -1,4 +1,4 @@
-// Copyright 2010 Google Inc. All Rights Reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -10,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -72,7 +72,7 @@ namespace google_breakpad {
template<typename Key>
class DefaultCompare {
public:
- int operator()(const Key &k1, const Key &k2) const {
+ int operator()(const Key& k1, const Key& k2) const {
if (k1 < k2) return -1;
if (k1 == k2) return 0;
return 1;
@@ -104,15 +104,15 @@ class StaticMap {
}
// Lookup operations.
- iterator find(const Key &k) const;
+ iterator find(const Key& k) const;
// lower_bound(k) searches in a sorted range for the first element that has a
// key not less than the argument k.
- iterator lower_bound(const Key &k) const;
+ iterator lower_bound(const Key& k) const;
// upper_bound(k) searches in a sorted range for the first element that has a
// key greater than the argument k.
- iterator upper_bound(const Key &k) const;
+ iterator upper_bound(const Key& k) const;
// Checks if the underlying memory data conforms to the predefined pattern:
// first check the number of nodes is non-negative,
diff --git a/src/processor/static_map_iterator-inl.h b/src/processor/static_map_iterator-inl.h
index 7a7db5ad..01a1b7f7 100644
--- a/src/processor/static_map_iterator-inl.h
+++ b/src/processor/static_map_iterator-inl.h
@@ -1,4 +1,4 @@
-// Copyright 2010 Google Inc. All Rights Reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -10,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -43,7 +43,7 @@ namespace google_breakpad {
template<typename Key, typename Value, typename Compare>
StaticMapIterator<Key, Value, Compare>::StaticMapIterator(const char* base,
- const int &index):
+ const int& index):
index_(index), base_(base) {
// See static_map.h for documentation on
// bytes format of serialized StaticMap data.
diff --git a/src/processor/static_map_iterator.h b/src/processor/static_map_iterator.h
index 1af8fff4..6c190e97 100644
--- a/src/processor/static_map_iterator.h
+++ b/src/processor/static_map_iterator.h
@@ -1,4 +1,4 @@
-// Copyright 2010 Google Inc. All Rights Reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -10,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -87,7 +87,7 @@ class StaticMapIterator {
friend class StaticMap<Key, Value, Compare>;
// Only StaticMap can call this constructor.
- explicit StaticMapIterator(const char* base, const int32_t &index);
+ explicit StaticMapIterator(const char* base, const int32_t& index);
// Index of node that the iterator is pointing to.
int32_t index_;
diff --git a/src/processor/static_map_unittest.cc b/src/processor/static_map_unittest.cc
index 393d43d5..4360e8c6 100644
--- a/src/processor/static_map_unittest.cc
+++ b/src/processor/static_map_unittest.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2010 Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -46,7 +45,7 @@ typedef std::map< KeyType, ValueType > StdMap;
template<typename Key, typename Value>
class SimpleMapSerializer {
public:
- static char* Serialize(const std::map<Key, Value> &stdmap,
+ static char* Serialize(const std::map<Key, Value>& stdmap,
unsigned int* size = NULL) {
unsigned int size_per_node =
sizeof(uint32_t) + sizeof(Key) + sizeof(Value);
@@ -237,19 +236,19 @@ class TestValidMap : public ::testing::Test {
}
}
- void FindTester(int test_case, const KeyType &key) {
+ void FindTester(int test_case, const KeyType& key) {
iter_test = test_map[test_case].find(key);
iter_std = std_map[test_case].find(key);
CompareLookupResult(test_case);
}
- void LowerBoundTester(int test_case, const KeyType &key) {
+ void LowerBoundTester(int test_case, const KeyType& key) {
iter_test = test_map[test_case].lower_bound(key);
iter_std = std_map[test_case].lower_bound(key);
CompareLookupResult(test_case);
}
- void UpperBoundTester(int test_case, const KeyType &key) {
+ void UpperBoundTester(int test_case, const KeyType& key) {
iter_test = test_map[test_case].upper_bound(key);
iter_std = std_map[test_case].upper_bound(key);
CompareLookupResult(test_case);
diff --git a/src/processor/static_range_map-inl.h b/src/processor/static_range_map-inl.h
index f6cef1a9..b0a32747 100644
--- a/src/processor/static_range_map-inl.h
+++ b/src/processor/static_range_map-inl.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2010 Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -43,8 +42,8 @@ namespace google_breakpad {
template<typename AddressType, typename EntryType>
bool StaticRangeMap<AddressType, EntryType>::RetrieveRange(
- const AddressType &address, const EntryType *&entry,
- AddressType *entry_base, AddressType *entry_size) const {
+ const AddressType& address, const EntryType*& entry,
+ AddressType* entry_base, AddressType* entry_size) const {
MapConstIterator iterator = map_.lower_bound(address);
if (iterator == map_.end())
return false;
@@ -55,7 +54,7 @@ bool StaticRangeMap<AddressType, EntryType>::RetrieveRange(
// be below the range's low address, though. When that happens, address
// references something not within any range, so return false.
- const Range *range = iterator.GetValuePtr();
+ const Range* range = iterator.GetValuePtr();
// Make sure AddressType and EntryType are copyable basic types
// e.g.: integer types, pointers etc
@@ -74,8 +73,8 @@ bool StaticRangeMap<AddressType, EntryType>::RetrieveRange(
template<typename AddressType, typename EntryType>
bool StaticRangeMap<AddressType, EntryType>::RetrieveNearestRange(
- const AddressType &address, const EntryType *&entry,
- AddressType *entry_base, AddressType *entry_size) const {
+ const AddressType& address, const EntryType*& entry,
+ AddressType* entry_base, AddressType* entry_size) const {
// If address is within a range, RetrieveRange can handle it.
if (RetrieveRange(address, entry, entry_base, entry_size))
return true;
@@ -91,7 +90,7 @@ bool StaticRangeMap<AddressType, EntryType>::RetrieveNearestRange(
return false;
--iterator;
- const Range *range = iterator.GetValuePtr();
+ const Range* range = iterator.GetValuePtr();
entry = range->entryptr();
if (entry_base)
*entry_base = range->base();
@@ -103,8 +102,8 @@ bool StaticRangeMap<AddressType, EntryType>::RetrieveNearestRange(
template<typename AddressType, typename EntryType>
bool StaticRangeMap<AddressType, EntryType>::RetrieveRangeAtIndex(
- int index, const EntryType *&entry,
- AddressType *entry_base, AddressType *entry_size) const {
+ int index, const EntryType*& entry,
+ AddressType* entry_base, AddressType* entry_size) const {
if (index >= GetCount()) {
BPLOG(ERROR) << "Index out of range: " << index << "/" << GetCount();
@@ -113,7 +112,7 @@ bool StaticRangeMap<AddressType, EntryType>::RetrieveRangeAtIndex(
MapConstIterator iterator = map_.IteratorAtIndex(index);
- const Range *range = iterator.GetValuePtr();
+ const Range* range = iterator.GetValuePtr();
entry = range->entryptr();
if (entry_base)
diff --git a/src/processor/static_range_map.h b/src/processor/static_range_map.h
index 91aabb03..319085db 100644
--- a/src/processor/static_range_map.h
+++ b/src/processor/static_range_map.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2010, Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -50,21 +49,21 @@ template<typename AddressType, typename EntryType>
class StaticRangeMap {
public:
StaticRangeMap(): map_() { }
- explicit StaticRangeMap(const char *memory): map_(memory) { }
+ explicit StaticRangeMap(const char* memory): map_(memory) { }
// Locates the range encompassing the supplied address. If there is
// no such range, returns false. entry_base and entry_size, if non-NULL,
// are set to the base and size of the entry's range.
- bool RetrieveRange(const AddressType &address, const EntryType *&entry,
- AddressType *entry_base, AddressType *entry_size) const;
+ bool RetrieveRange(const AddressType& address, const EntryType*& entry,
+ AddressType* entry_base, AddressType* entry_size) const;
// Locates the range encompassing the supplied address, if one exists.
// If no range encompasses the supplied address, locates the nearest range
// to the supplied address that is lower than the address. Returns false
// if no range meets these criteria. entry_base and entry_size, if
// non-NULL, are set to the base and size of the entry's range.
- bool RetrieveNearestRange(const AddressType &address, const EntryType *&entry,
- AddressType *entry_base, AddressType *entry_size)
+ bool RetrieveNearestRange(const AddressType& address, const EntryType*& entry,
+ AddressType* entry_base, AddressType* entry_size)
const;
// Treating all ranges as a list ordered by the address spaces that they
@@ -74,8 +73,8 @@ class StaticRangeMap {
// range.
//
// RetrieveRangeAtIndex is not optimized for speedy operation.
- bool RetrieveRangeAtIndex(int index, const EntryType *&entry,
- AddressType *entry_base, AddressType *entry_size)
+ bool RetrieveRangeAtIndex(int index, const EntryType*& entry,
+ AddressType* entry_base, AddressType* entry_size)
const;
// Returns the number of ranges stored in the RangeMap.
diff --git a/src/processor/static_range_map_unittest.cc b/src/processor/static_range_map_unittest.cc
index 28217362..3903e948 100644
--- a/src/processor/static_range_map_unittest.cc
+++ b/src/processor/static_range_map_unittest.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2010 Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -228,10 +227,10 @@ void TestStaticRangeMap::RetrieveTest(TestMap* range_map,
}
for (AddressType offset = low_offset; offset <= high_offset; ++offset) {
- AddressType address =
- offset +
- (!side ? range_test->address :
- range_test->address + range_test->size - 1);
+ AddressType address = AddIgnoringOverflow(
+ offset, (!side ? range_test->address
+ : AddIgnoringOverflow(range_test->address,
+ range_test->size - 1)));
bool expected_result = false; // This is correct for tests not stored.
if (range_test->expect_storable) {
@@ -414,7 +413,7 @@ TEST_F(TestStaticRangeMap, RunTestCase0Again) {
} // namespace google_breakpad
-int main(int argc, char *argv[]) {
+int main(int argc, char* argv[]) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
diff --git a/src/processor/symbolic_constants_win.cc b/src/processor/symbolic_constants_win.cc
index 8cf283f6..0c57b686 100644
--- a/src/processor/symbolic_constants_win.cc
+++ b/src/processor/symbolic_constants_win.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2015 Google Inc.
-// All rights reserved.
+// Copyright 2015 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/processor/symbolic_constants_win.h b/src/processor/symbolic_constants_win.h
index 3f4d38eb..bc9ff350 100644
--- a/src/processor/symbolic_constants_win.h
+++ b/src/processor/symbolic_constants_win.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2015 Google Inc.
-// All rights reserved.
+// Copyright 2015 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/processor/synth_minidump.cc b/src/processor/synth_minidump.cc
index aa86d248..9dacb395 100644
--- a/src/processor/synth_minidump.cc
+++ b/src/processor/synth_minidump.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2010, Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -37,7 +36,7 @@ namespace google_breakpad {
namespace SynthMinidump {
-Section::Section(const Dump &dump)
+Section::Section(const Dump& dump)
: test_assembler::Section(dump.endianness()) { }
void Section::CiteLocationIn(test_assembler::Section *section) const {
@@ -49,9 +48,9 @@ void Stream::CiteStreamIn(test_assembler::Section *section) const {
CiteLocationIn(section);
}
-SystemInfo::SystemInfo(const Dump &dump,
- const MDRawSystemInfo &system_info,
- const String &csd_version)
+SystemInfo::SystemInfo(const Dump& dump,
+ const MDRawSystemInfo& system_info,
+ const String& csd_version)
: Stream(dump, MD_SYSTEM_INFO_STREAM) {
D16(system_info.processor_architecture);
D16(system_info.processor_level);
@@ -108,7 +107,7 @@ const MDRawSystemInfo SystemInfo::windows_x86 = {
const string SystemInfo::windows_x86_csd_version = "Service Pack 2";
-String::String(const Dump &dump, const string &contents) : Section(dump) {
+String::String(const Dump& dump, const string& contents) : Section(dump) {
D32(contents.size() * 2);
for (string::const_iterator i = contents.begin(); i != contents.end(); i++)
D16(*i);
@@ -123,7 +122,7 @@ void Memory::CiteMemoryIn(test_assembler::Section *section) const {
CiteLocationIn(section);
}
-Context::Context(const Dump &dump, const MDRawContextX86 &context)
+Context::Context(const Dump& dump, const MDRawContextX86& context)
: Section(dump) {
// The caller should have properly set the CPU type flag.
// The high 24 bits identify the CPU. Note that context records with no CPU
@@ -173,7 +172,7 @@ Context::Context(const Dump &dump, const MDRawContextX86 &context)
assert(Size() == sizeof(MDRawContextX86));
}
-Context::Context(const Dump &dump, const MDRawContextARM &context)
+Context::Context(const Dump& dump, const MDRawContextARM& context)
: Section(dump) {
// The caller should have properly set the CPU type flag.
assert((context.context_flags & MD_CONTEXT_ARM) ||
@@ -192,7 +191,7 @@ Context::Context(const Dump &dump, const MDRawContextARM &context)
assert(Size() == sizeof(MDRawContextARM));
}
-Context::Context(const Dump &dump, const MDRawContextMIPS &context)
+Context::Context(const Dump& dump, const MDRawContextMIPS& context)
: Section(dump) {
// The caller should have properly set the CPU type flag.
assert(context.context_flags & MD_CONTEXT_MIPS);
@@ -228,8 +227,8 @@ Context::Context(const Dump &dump, const MDRawContextMIPS &context)
assert(Size() == sizeof(MDRawContextMIPS));
}
-Thread::Thread(const Dump &dump,
- uint32_t thread_id, const Memory &stack, const Context &context,
+Thread::Thread(const Dump& dump,
+ uint32_t thread_id, const Memory& stack, const Context& context,
uint32_t suspend_count, uint32_t priority_class,
uint32_t priority, uint64_t teb) : Section(dump) {
D32(thread_id);
@@ -242,13 +241,13 @@ Thread::Thread(const Dump &dump,
assert(Size() == sizeof(MDRawThread));
}
-Module::Module(const Dump &dump,
+Module::Module(const Dump& dump,
uint64_t base_of_image,
uint32_t size_of_image,
- const String &name,
+ const String& name,
uint32_t time_date_stamp,
uint32_t checksum,
- const MDVSFixedFileInfo &version_info,
+ const MDVSFixedFileInfo& version_info,
const Section *cv_record,
const Section *misc_record) : Section(dump) {
D64(base_of_image);
@@ -297,10 +296,10 @@ const MDVSFixedFileInfo Module::stock_version_info = {
0 // file_date_lo
};
-UnloadedModule::UnloadedModule(const Dump &dump,
+UnloadedModule::UnloadedModule(const Dump& dump,
uint64_t base_of_image,
uint32_t size_of_image,
- const String &name,
+ const String& name,
uint32_t checksum,
uint32_t time_date_stamp) : Section(dump) {
D64(base_of_image);
@@ -310,15 +309,15 @@ UnloadedModule::UnloadedModule(const Dump &dump,
name.CiteStringIn(this);
}
-UnloadedModuleList::UnloadedModuleList(const Dump &dump, uint32_t type)
+UnloadedModuleList::UnloadedModuleList(const Dump& dump, uint32_t type)
: List<UnloadedModule>(dump, type, false) {
D32(sizeof(MDRawUnloadedModuleList));
D32(sizeof(MDRawUnloadedModule));
D32(count_label_);
}
-Exception::Exception(const Dump &dump,
- const Context &context,
+Exception::Exception(const Dump& dump,
+ const Context& context,
uint32_t thread_id,
uint32_t exception_code,
uint32_t exception_flags,
@@ -332,7 +331,7 @@ Exception::Exception(const Dump &dump,
D64(exception_address);
D32(0); // number_parameters
D32(0); // __align
- for (int i = 0; i < MD_EXCEPTION_MAXIMUM_PARAMETERS; ++i)
+ for (size_t i = 0; i < MD_EXCEPTION_MAXIMUM_PARAMETERS; ++i)
D64(0); // exception_information
context.CiteLocationIn(this);
assert(Size() == sizeof(MDRawExceptionStream));
@@ -361,22 +360,22 @@ Dump::Dump(uint64_t flags,
assert(Size() == sizeof(MDRawHeader));
}
-Dump &Dump::Add(SynthMinidump::Section *section) {
+Dump& Dump::Add(SynthMinidump::Section *section) {
section->Finish(file_start_ + Size());
Append(*section);
return *this;
}
-Dump &Dump::Add(Stream *stream) {
- Add(static_cast<SynthMinidump::Section *>(stream));
+Dump& Dump::Add(Stream *stream) {
+ Add(static_cast<SynthMinidump::Section*>(stream));
stream->CiteStreamIn(&stream_directory_);
stream_count_++;
return *this;
}
-Dump &Dump::Add(Memory *memory) {
+Dump& Dump::Add(Memory *memory) {
// Add the memory contents themselves to the file.
- Add(static_cast<SynthMinidump::Section *>(memory));
+ Add(static_cast<SynthMinidump::Section*>(memory));
// The memory list is a list of MDMemoryDescriptors, not of actual
// memory elements. Produce a descriptor, and add that to the list.
@@ -386,17 +385,17 @@ Dump &Dump::Add(Memory *memory) {
return *this;
}
-Dump &Dump::Add(Thread *thread) {
+Dump& Dump::Add(Thread *thread) {
thread_list_.Add(thread);
return *this;
}
-Dump &Dump::Add(Module *module) {
+Dump& Dump::Add(Module *module) {
module_list_.Add(module);
return *this;
}
-Dump &Dump::Add(UnloadedModule *unloaded_module) {
+Dump& Dump::Add(UnloadedModule *unloaded_module) {
unloaded_module_list_.Add(unloaded_module);
return *this;
}
@@ -413,7 +412,7 @@ void Dump::Finish() {
// has the stream count and MDRVA.
stream_count_label_ = stream_count_;
stream_directory_rva_ = file_start_ + Size();
- Append(static_cast<test_assembler::Section &>(stream_directory_));
+ Append(static_cast<test_assembler::Section& >(stream_directory_));
}
} // namespace SynthMinidump
diff --git a/src/processor/synth_minidump.h b/src/processor/synth_minidump.h
index 8f49cfff..a52be03b 100644
--- a/src/processor/synth_minidump.h
+++ b/src/processor/synth_minidump.h
@@ -1,7 +1,6 @@
// -*- mode: C++ -*-
-// Copyright (c) 2010, Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -13,7 +12,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -135,7 +134,7 @@ class String;
// A test_assembler::Section which will be appended to a minidump.
class Section: public test_assembler::Section {
public:
- explicit Section(const Dump &dump);
+ explicit Section(const Dump& dump);
// Append an MDLocationDescriptor referring to this section to SECTION.
// If 'this' is NULL, append a descriptor with a zero length and MDRVA.
@@ -145,13 +144,13 @@ class Section: public test_assembler::Section {
// bad, if such language exists. Having this function handle NULL
// 'this' is convenient, but if it causes trouble, it's not hard to
// do differently.)
- void CiteLocationIn(test_assembler::Section *section) const;
+ void CiteLocationIn(test_assembler::Section* section) const;
// Note that this section's contents are complete, and that it has
// been placed in the minidump file at OFFSET. The 'Add' member
// functions call the Finish member function of the object being
// added for you; if you are 'Add'ing this section, you needn't Finish it.
- virtual void Finish(const Label &offset) {
+ virtual void Finish(const Label& offset) {
file_offset_ = offset; size_ = Size();
}
@@ -166,10 +165,10 @@ class Stream: public Section {
public:
// Create a stream of type TYPE. You can append whatever contents
// you like to this stream using the test_assembler::Section methods.
- Stream(const Dump &dump, uint32_t type) : Section(dump), type_(type) { }
+ Stream(const Dump& dump, uint32_t type) : Section(dump), type_(type) { }
// Append an MDRawDirectory referring to this stream to SECTION.
- void CiteStreamIn(test_assembler::Section *section) const;
+ void CiteStreamIn(test_assembler::Section* section) const;
private:
// The type of this stream.
@@ -186,9 +185,9 @@ class SystemInfo: public Stream {
//
// Remember that you are still responsible for 'Add'ing CSD_VERSION
// to the dump yourself.
- SystemInfo(const Dump &dump,
- const MDRawSystemInfo &system_info,
- const String &csd_version);
+ SystemInfo(const Dump& dump,
+ const MDRawSystemInfo& system_info,
+ const String& csd_version);
// Stock MDRawSystemInfo information and associated strings, for
// writing tests.
@@ -199,10 +198,10 @@ class SystemInfo: public Stream {
// An MDString: a string preceded by a 32-bit length.
class String: public Section {
public:
- String(const Dump &dump, const string &value);
+ String(const Dump& dump, const string& value);
// Append an MDRVA referring to this string to SECTION.
- void CiteStringIn(test_assembler::Section *section) const;
+ void CiteStringIn(test_assembler::Section* section) const;
};
// A range of memory contents. 'Add'ing a memory range to a minidump
@@ -211,11 +210,11 @@ class String: public Section {
// to memory addresses.
class Memory: public Section {
public:
- Memory(const Dump &dump, uint64_t address)
+ Memory(const Dump& dump, uint64_t address)
: Section(dump), address_(address) { start() = address; }
// Append an MDMemoryDescriptor referring to this memory range to SECTION.
- void CiteMemoryIn(test_assembler::Section *section) const;
+ void CiteMemoryIn(test_assembler::Section* section) const;
private:
// The process address from which these memory contents were taken.
@@ -226,11 +225,11 @@ class Memory: public Section {
class Context: public Section {
public:
// Create a context belonging to DUMP whose contents are a copy of CONTEXT.
- Context(const Dump &dump, const MDRawContextX86 &context);
- Context(const Dump &dump, const MDRawContextARM &context);
- Context(const Dump &dump, const MDRawContextMIPS &context);
+ Context(const Dump& dump, const MDRawContextX86& context);
+ Context(const Dump& dump, const MDRawContextARM& context);
+ Context(const Dump& dump, const MDRawContextMIPS& context);
// Add an empty context to the dump.
- Context(const Dump &dump) : Section(dump) {}
+ Context(const Dump& dump) : Section(dump) {}
// Add constructors for other architectures here. Remember to byteswap.
};
@@ -238,10 +237,10 @@ class Thread: public Section {
public:
// Create a thread belonging to DUMP with the given values, citing
// STACK and CONTEXT (which you must Add to the dump separately).
- Thread(const Dump &dump,
+ Thread(const Dump& dump,
uint32_t thread_id,
- const Memory &stack,
- const Context &context,
+ const Memory& stack,
+ const Context& context,
uint32_t suspend_count = 0,
uint32_t priority_class = 0,
uint32_t priority = 0,
@@ -253,15 +252,15 @@ class Module: public Section {
// Create a module with the given values. Note that CV_RECORD and
// MISC_RECORD can be NULL, in which case the corresponding location
// descriptior in the minidump will have a length of zero.
- Module(const Dump &dump,
+ Module(const Dump& dump,
uint64_t base_of_image,
uint32_t size_of_image,
- const String &name,
+ const String& name,
uint32_t time_date_stamp = 1262805309,
uint32_t checksum = 0,
- const MDVSFixedFileInfo &version_info = Module::stock_version_info,
- const Section *cv_record = NULL,
- const Section *misc_record = NULL);
+ const MDVSFixedFileInfo& version_info = Module::stock_version_info,
+ const Section* cv_record = NULL,
+ const Section* misc_record = NULL);
private:
// A standard MDVSFixedFileInfo structure to use as a default for
@@ -272,18 +271,18 @@ class Module: public Section {
class UnloadedModule: public Section {
public:
- UnloadedModule(const Dump &dump,
+ UnloadedModule(const Dump& dump,
uint64_t base_of_image,
uint32_t size_of_image,
- const String &name,
+ const String& name,
uint32_t checksum = 0,
uint32_t time_date_stamp = 1262805309);
};
class Exception : public Stream {
public:
- Exception(const Dump &dump,
- const Context &context,
+ Exception(const Dump& dump,
+ const Context& context,
uint32_t thread_id = 0,
uint32_t exception_code = 0,
uint32_t exception_flags = 0,
@@ -295,12 +294,12 @@ public:
template<typename Element>
class List: public Stream {
public:
- List(const Dump &dump, uint32_t type) : Stream(dump, type), count_(0) {
+ List(const Dump& dump, uint32_t type) : Stream(dump, type), count_(0) {
D32(count_label_);
}
// Add ELEMENT to this list.
- void Add(Element *element) {
+ void Add(Element* element) {
element->Finish(file_offset_ + Size());
Append(*element);
count_++;
@@ -311,7 +310,7 @@ class List: public Stream {
// Finish up the contents of this section, mark it as having been
// placed at OFFSET.
- virtual void Finish(const Label &offset) {
+ virtual void Finish(const Label& offset) {
Stream::Finish(offset);
count_label_ = count_;
}
@@ -322,14 +321,14 @@ class List: public Stream {
protected:
// This constructor allows derived lists to specify their own layout
// rather than starting with count as specified in the public constructor.
- List(const Dump &dump, uint32_t type, bool) : Stream(dump, type), count_(0) {}
+ List(const Dump& dump, uint32_t type, bool) : Stream(dump, type), count_(0) {}
Label count_label_;
};
class UnloadedModuleList : public List<UnloadedModule> {
public:
- UnloadedModuleList(const Dump &dump, uint32_t type);
+ UnloadedModuleList(const Dump& dump, uint32_t type);
};
class Dump: public test_assembler::Section {
@@ -349,12 +348,12 @@ class Dump: public test_assembler::Section {
// whatever directory or list is appropriate for its type. The
// stream directory, memory list, thread list, and module list are
// accumulated this way.
- Dump &Add(SynthMinidump::Section *object); // simply append data
- Dump &Add(Stream *object); // append, record in stream directory
- Dump &Add(Memory *object); // append, record in memory list
- Dump &Add(Thread *object); // append, record in thread list
- Dump &Add(Module *object); // append, record in module list
- Dump &Add(UnloadedModule *object); // append, record in unloaded module list
+ Dump& Add(SynthMinidump::Section* object); // simply append data
+ Dump& Add(Stream* object); // append, record in stream directory
+ Dump& Add(Memory* object); // append, record in memory list
+ Dump& Add(Thread* object); // append, record in thread list
+ Dump& Add(Module* object); // append, record in module list
+ Dump& Add(UnloadedModule* object); // append, record in unloaded module list
// Complete the construction of the minidump, given the Add calls
// we've seen up to this point. After this call, this Dump's
@@ -367,26 +366,26 @@ class Dump: public test_assembler::Section {
Label file_start_;
// The stream directory. We construct this incrementally from
- // Add(Stream *) calls.
+ // Add(Stream*) calls.
SynthMinidump::Section stream_directory_; // The directory's contents.
size_t stream_count_; // The number of streams so far.
Label stream_count_label_; // Cited in file header.
Label stream_directory_rva_; // The directory's file offset.
// This minidump's thread list. We construct this incrementally from
- // Add(Thread *) calls.
+ // Add(Thread*) calls.
List<Thread> thread_list_;
// This minidump's module list. We construct this incrementally from
- // Add(Module *) calls.
+ // Add(Module*) calls.
List<Module> module_list_;
// This minidump's unloaded module list. We construct this incrementally from
- // Add(UnloadedModule *) calls.
+ // Add(UnloadedModule*) calls.
UnloadedModuleList unloaded_module_list_;
// This minidump's memory list. We construct this incrementally from
- // Add(Memory *) calls. This is actually a list of MDMemoryDescriptors,
+ // Add(Memory*) calls. This is actually a list of MDMemoryDescriptors,
// not memory ranges --- thus the odd type.
List<SynthMinidump::Section> memory_list_;
};
diff --git a/src/processor/synth_minidump_unittest.cc b/src/processor/synth_minidump_unittest.cc
index 8835b449..4bc46747 100644
--- a/src/processor/synth_minidump_unittest.cc
+++ b/src/processor/synth_minidump_unittest.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2010, Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/processor/testdata/linux_inline.dmp b/src/processor/testdata/linux_inline.dmp
new file mode 100644
index 00000000..5b216f8b
--- /dev/null
+++ b/src/processor/testdata/linux_inline.dmp
Binary files differ
diff --git a/src/processor/testdata/linux_test_app.cc b/src/processor/testdata/linux_test_app.cc
index 18f0f62f..4ff4f707 100644
--- a/src/processor/testdata/linux_test_app.cc
+++ b/src/processor/testdata/linux_test_app.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2009, Google Inc.
-// All rights reserved.
+// Copyright 2009 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -51,8 +50,8 @@
namespace {
// google_breakpad::MinidumpCallback to invoke after minidump generation.
-static bool callback(const char *dump_path, const char *id,
- void *context,
+static bool callback(const char* dump_path, const char* id,
+ void* context,
bool succeeded) {
if (succeeded) {
printf("dump guid is %s\n", id);
@@ -65,13 +64,13 @@ static bool callback(const char *dump_path, const char *id,
}
static void CrashFunction() {
- int *i = reinterpret_cast<int*>(0x45);
+ int* i = reinterpret_cast<int*>(0x45);
*i = 5; // crash!
}
} // namespace
-int main(int argc, char **argv) {
+int main(int argc, char** argv) {
google_breakpad::ExceptionHandler eh(".", NULL, callback, NULL, true);
if (!eh.WriteMinidump()) {
printf("Failed to generate on-demand minidump\n");
diff --git a/src/processor/testdata/minidump2.dump.out b/src/processor/testdata/minidump2.dump.out
index 8585c89b..bad1b80f 100644
--- a/src/processor/testdata/minidump2.dump.out
+++ b/src/processor/testdata/minidump2.dump.out
@@ -670,7 +670,7 @@ MDRawContextX86
extended_registers[512] = 0x7f0200000000220000000000000000000000000000000000801f0000ffff00000000000018b72200000100000000000018b72200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004509917c4e09917c38b622002400020024b42200020000009041917c0070fd7f0510907cccb22200000000009cb3220018ee907c7009917cc0e4977c6f3e917c623e917c08020000dcb62200b4b622001e000000000000000000000000000000000000002eb42200000000000f000000020000001e00200000fcfd7f2f63796764726976652f632f444f43554d457e312f4d4d454e544f7e312f4c4f43414c537e312f54656d7000000000000000000130b422000000004300000000000000001efcfd7f4509917c4e09917c5ad9000008b32200b4b62200
MDRawSystemInfo
- processor_architecture = 0x0
+ processor_architecture = 0x0 (x86)
processor_level = 6
processor_revision = 0xd08
number_of_processors = 1
@@ -678,7 +678,7 @@ MDRawSystemInfo
major_version = 5
minor_version = 1
build_number = 2600
- platform_id = 0x2
+ platform_id = 0x2 (windows)
csd_version_rva = 0x768
suite_mask = 0x100
cpu.x86_cpu_info (valid):
diff --git a/src/processor/testdata/minidump_crashpad_annotation.dmp b/src/processor/testdata/minidump_crashpad_annotation.dmp
new file mode 100644
index 00000000..00cfc5a3
--- /dev/null
+++ b/src/processor/testdata/minidump_crashpad_annotation.dmp
Binary files differ
diff --git a/src/processor/testdata/module1.out b/src/processor/testdata/module1.out
index cd6e18d1..6774e4f1 100644
--- a/src/processor/testdata/module1.out
+++ b/src/processor/testdata/module1.out
@@ -3,7 +3,7 @@ INFO CODE_ID FFFFFFFF module1.exe
FILE 1 file1_1.cc
FILE 2 file1_2.cc
FILE 3 file1_3.cc
-FUNC 1000 c 0 Function1_1
+FUNC m 1000 c 0 Function1_1
1000 4 44 1
1004 4 45 1
1008 4 46 1
@@ -14,7 +14,7 @@ FUNC 1200 100 8 Function1_3
FUNC 1300 100 c Function1_4
FUNC 2000 0 0 Test_Zero_Size_Function_Is_Ignored
2000 4 88 2
-PUBLIC 2800 0 PublicSymbol
+PUBLIC m 2800 0 PublicSymbol
FUNC 3000 7000 42 LargeFunction
3000 7000 4098359 3
STACK WIN 4 1000 c 1 0 0 0 0 0 1 $eip 4 + ^ = $esp $ebp 8 + = $ebp $ebp ^ =
diff --git a/src/processor/testdata/symbols/linux_inline/BBA6FA10B8AAB33D00000000000000000/linux_inline.new.sym b/src/processor/testdata/symbols/linux_inline/BBA6FA10B8AAB33D00000000000000000/linux_inline.new.sym
new file mode 100644
index 00000000..5cd83209
--- /dev/null
+++ b/src/processor/testdata/symbols/linux_inline/BBA6FA10B8AAB33D00000000000000000/linux_inline.new.sym
@@ -0,0 +1,71 @@
+MODULE Linux x86_64 BBA6FA10B8AAB33D00000000000000000 linux_inline
+INFO CODE_ID 10FAA6BBAAB83DB3
+FILE 0 linux_inline.cpp
+FILE 1 a.cpp
+FILE 2 b.cpp
+FILE 3 c.cpp
+INLINE_ORIGIN 0 bar()
+INLINE_ORIGIN 1 foo()
+INLINE_ORIGIN 2 func()
+FUNC 15b30 6cf 0 main
+INLINE 0 42 1 1 15b45 6b1
+INLINE 1 39 2 0 15b72 684
+INLINE 2 32 3 2 15b83 673
+15b30 15 41 0
+15b45 11 36 0
+15b56 a 37 0
+15b60 6 37 0
+15b66 5 38 0
+15b6b 7 0 0
+15b72 11 31 0
+15b83 a 9 0
+15b8d 4 9 0
+15b91 6 9 0
+15b97 7 0 0
+15b9e 11 10 0
+15baf 7 0 0
+15bb6 2e 12 0
+15be4 7 0 0
+15beb 5 12 0
+15bf0 1d 13 0
+15c0d 1d 14 0
+15c2a e 0 0
+15c38 1c 15 0
+15c54 a 16 0
+15c5e 7 0 0
+15c65 2c 16 0
+15c91 15 0 0
+15ca6 a 16 0
+15cb0 87 15 0
+15d37 7 0 0
+15d3e 33 15 0
+15d71 7 0 0
+15d78 24 15 0
+15d9c a 17 0
+15da6 e 0 0
+15db4 a 18 0
+15dbe e 0 0
+15dcc a 19 0
+15dd6 7 0 0
+15ddd a 20 0
+15de7 7 0 0
+15dee 2c 21 0
+15e1a 3c 22 0
+15e56 28 23 0
+15e7e 5a 18 0
+15ed8 d 28 0
+15ee5 11 12 0
+15ef6 67 28 0
+15f5d 2b 15 0
+15f88 7 0 0
+15f8f 8c 15 0
+1601b 7 0 0
+16022 3d 15 0
+1605f 67 28 0
+160c6 54 18 0
+1611a 3c 28 0
+16156 c 12 0
+16162 54 18 0
+161b6 2 27 0
+161b8 3e 28 0
+161f6 9 43 0 \ No newline at end of file
diff --git a/src/processor/testdata/symbols/linux_inline/BBA6FA10B8AAB33D00000000000000000/linux_inline.old.sym b/src/processor/testdata/symbols/linux_inline/BBA6FA10B8AAB33D00000000000000000/linux_inline.old.sym
new file mode 100644
index 00000000..775640f0
--- /dev/null
+++ b/src/processor/testdata/symbols/linux_inline/BBA6FA10B8AAB33D00000000000000000/linux_inline.old.sym
@@ -0,0 +1,68 @@
+MODULE Linux x86_64 BBA6FA10B8AAB33D00000000000000000 linux_inline
+INFO CODE_ID 10FAA6BBAAB83DB3
+FILE 0 linux_inline.cpp
+INLINE_ORIGIN 0 0 bar()
+INLINE_ORIGIN 1 0 foo()
+INLINE_ORIGIN 2 0 func()
+FUNC 15b30 6cf 0 main
+INLINE 0 42 1 15b45 6b1
+INLINE 1 39 0 15b72 684
+INLINE 2 32 2 15b83 673
+15b30 15 41 0
+15b45 11 36 0
+15b56 a 37 0
+15b60 6 37 0
+15b66 5 38 0
+15b6b 7 0 0
+15b72 11 31 0
+15b83 a 9 0
+15b8d 4 9 0
+15b91 6 9 0
+15b97 7 0 0
+15b9e 11 10 0
+15baf 7 0 0
+15bb6 2e 12 0
+15be4 7 0 0
+15beb 5 12 0
+15bf0 1d 13 0
+15c0d 1d 14 0
+15c2a e 0 0
+15c38 1c 15 0
+15c54 a 16 0
+15c5e 7 0 0
+15c65 2c 16 0
+15c91 15 0 0
+15ca6 a 16 0
+15cb0 87 15 0
+15d37 7 0 0
+15d3e 33 15 0
+15d71 7 0 0
+15d78 24 15 0
+15d9c a 17 0
+15da6 e 0 0
+15db4 a 18 0
+15dbe e 0 0
+15dcc a 19 0
+15dd6 7 0 0
+15ddd a 20 0
+15de7 7 0 0
+15dee 2c 21 0
+15e1a 3c 22 0
+15e56 28 23 0
+15e7e 5a 18 0
+15ed8 d 28 0
+15ee5 11 12 0
+15ef6 67 28 0
+15f5d 2b 15 0
+15f88 7 0 0
+15f8f 8c 15 0
+1601b 7 0 0
+16022 3d 15 0
+1605f 67 28 0
+160c6 54 18 0
+1611a 3c 28 0
+16156 c 12 0
+16162 54 18 0
+161b6 2 27 0
+161b8 3e 28 0
+161f6 9 43 0
diff --git a/src/processor/testdata/test_app.cc b/src/processor/testdata/test_app.cc
index 7882a8bd..79cabef0 100644
--- a/src/processor/testdata/test_app.cc
+++ b/src/processor/testdata/test_app.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2006, Google Inc.
-// All rights reserved.
+// Copyright 2006 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -38,9 +37,9 @@
namespace {
-static bool callback(const wchar_t *dump_path, const wchar_t *id,
- void *context, EXCEPTION_POINTERS *exinfo,
- MDRawAssertionInfo *assertion,
+static bool callback(const wchar_t* dump_path, const wchar_t* id,
+ void* context, EXCEPTION_POINTERS* exinfo,
+ MDRawAssertionInfo* assertion,
bool succeeded) {
if (succeeded) {
printf("dump guid is %ws\n", id);
@@ -53,13 +52,13 @@ static bool callback(const wchar_t *dump_path, const wchar_t *id,
}
static void CrashFunction() {
- int *i = reinterpret_cast<int*>(0x45);
+ int* i = reinterpret_cast<int*>(0x45);
*i = 5; // crash!
}
} // namespace
-int main(int argc, char **argv) {
+int main(int argc, char** argv) {
google_breakpad::ExceptionHandler eh(
L".", NULL, callback, NULL,
google_breakpad::ExceptionHandler::HANDLER_ALL);
diff --git a/src/processor/testdata/thread_name_list.dmp b/src/processor/testdata/thread_name_list.dmp
new file mode 100644
index 00000000..fbe84b63
--- /dev/null
+++ b/src/processor/testdata/thread_name_list.dmp
Binary files differ
diff --git a/src/processor/testdata/tiny-exe-fastfail.dmp b/src/processor/testdata/tiny-exe-fastfail.dmp
new file mode 100644
index 00000000..f7a0a502
--- /dev/null
+++ b/src/processor/testdata/tiny-exe-fastfail.dmp
Binary files differ
diff --git a/src/processor/testdata/tiny-exe-with-cet-xsave.dmp b/src/processor/testdata/tiny-exe-with-cet-xsave.dmp
new file mode 100644
index 00000000..9b641afb
--- /dev/null
+++ b/src/processor/testdata/tiny-exe-with-cet-xsave.dmp
Binary files differ
diff --git a/src/processor/testdata/write_av_non_canonical.dmp b/src/processor/testdata/write_av_non_canonical.dmp
new file mode 100644
index 00000000..02da25ee
--- /dev/null
+++ b/src/processor/testdata/write_av_non_canonical.dmp
Binary files differ
diff --git a/src/processor/tokenize.cc b/src/processor/tokenize.cc
index 8fce87a2..4e62f2ea 100644
--- a/src/processor/tokenize.cc
+++ b/src/processor/tokenize.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2010, Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -42,10 +41,10 @@ namespace google_breakpad {
using std::vector;
-bool Tokenize(char *line,
- const char *separators,
- int max_tokens,
- vector<char*> *tokens) {
+bool Tokenize(char* line,
+ const char* separators,
+ int max_tokens,
+ vector<char*>* tokens) {
tokens->clear();
tokens->reserve(max_tokens);
@@ -53,8 +52,8 @@ bool Tokenize(char *line,
// Split tokens on the separator character.
// strip them out before exhausting max_tokens.
- char *save_ptr;
- char *token = strtok_r(line, separators, &save_ptr);
+ char* save_ptr;
+ char* token = strtok_r(line, separators, &save_ptr);
while (token && --remaining > 0) {
tokens->push_back(token);
if (remaining > 1)
@@ -69,10 +68,9 @@ bool Tokenize(char *line,
return tokens->size() == static_cast<unsigned int>(max_tokens);
}
-void StringToVector(const string &str, vector<char> &vec) {
+void StringToVector(const string& str, vector<char>& vec) {
vec.resize(str.length() + 1);
- std::copy(str.begin(), str.end(),
- vec.begin());
+ std::copy(str.begin(), str.end(), vec.begin());
vec[str.length()] = '\0';
}
diff --git a/src/processor/tokenize.h b/src/processor/tokenize.h
index 9ff571d5..b30c7415 100644
--- a/src/processor/tokenize.h
+++ b/src/processor/tokenize.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2010, Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -50,13 +49,13 @@ namespace google_breakpad {
// Tokenize, but may be treated as a failure if the caller expects an
// exact, as opposed to maximum, number of tokens.
-bool Tokenize(char *line,
- const char *separators,
+bool Tokenize(char* line,
+ const char* separators,
int max_tokens,
- std::vector<char*> *tokens);
+ std::vector<char*>* tokens);
// For convenience, since you need a char* to pass to Tokenize.
// You can call StringToVector on a string, and use &vec[0].
-void StringToVector(const string &str, std::vector<char> &vec);
+void StringToVector(const string& str, std::vector<char>& vec);
} // namespace google_breakpad
diff --git a/src/processor/windows_frame_info.h b/src/processor/windows_frame_info.h
index f96e0a43..4014a1a9 100644
--- a/src/processor/windows_frame_info.h
+++ b/src/processor/windows_frame_info.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2006, Google Inc.
-// All rights reserved.
+// Copyright 2006 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -113,9 +112,9 @@ struct WindowsFrameInfo {
// otherwise. type, rva and code_size are present in the STACK line,
// but not the StackFrameInfo structure, so return them as outparams.
static WindowsFrameInfo *ParseFromString(const string string,
- int &type,
- uint64_t &rva,
- uint64_t &code_size) {
+ int& type,
+ uint64_t& rva,
+ uint64_t& code_size) {
// The format of a STACK WIN record is documented at:
//
// https://chromium.googlesource.com/breakpad/breakpad/+/master/docs/symbol_files.md
@@ -160,7 +159,7 @@ struct WindowsFrameInfo {
}
// CopyFrom makes "this" WindowsFrameInfo object identical to "that".
- void CopyFrom(const WindowsFrameInfo &that) {
+ void CopyFrom(const WindowsFrameInfo& that) {
type_ = that.type_;
valid = that.valid;
prolog_size = that.prolog_size;
diff --git a/src/third_party/curl/curlbuild.h b/src/third_party/curl/curlbuild.h
index 595df4e4..2fb1d020 100644
--- a/src/third_party/curl/curlbuild.h
+++ b/src/third_party/curl/curlbuild.h
@@ -156,7 +156,8 @@
/* The size of `long', as computed by sizeof. */
#if defined(_M_X64) || (defined(__x86_64__) && !defined(__ILP32__)) || \
defined(__aarch64__) || (defined(__mips__) && _MIPS_SIM == _ABI64) || \
- defined(__powerpc64__) || defined(__s390x__) || defined(__LP64__)
+ defined(__powerpc64__) || defined(__s390x__) || defined(__LP64__) || \
+ (defined(__riscv) && __riscv_xlen == 64)
#define CURL_SIZEOF_LONG 8
#else
#define CURL_SIZEOF_LONG 4
diff --git a/src/third_party/libdisasm/libdisasm.gyp b/src/third_party/libdisasm/libdisasm.gyp
deleted file mode 100644
index 5c8dc458..00000000
--- a/src/third_party/libdisasm/libdisasm.gyp
+++ /dev/null
@@ -1,67 +0,0 @@
-# Copyright 2014 Google Inc. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-# * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-# * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-{
- 'includes': [
- '../../build/common.gypi',
- ],
- 'targets': [
- {
- 'target_name': 'libdisasm',
- 'type': 'static_library',
- 'sources': [
- 'ia32_implicit.c',
- 'ia32_implicit.h',
- 'ia32_insn.c',
- 'ia32_insn.h',
- 'ia32_invariant.c',
- 'ia32_invariant.h',
- 'ia32_modrm.c',
- 'ia32_modrm.h',
- 'ia32_opcode_tables.c',
- 'ia32_opcode_tables.h',
- 'ia32_operand.c',
- 'ia32_operand.h',
- 'ia32_reg.c',
- 'ia32_reg.h',
- 'ia32_settings.c',
- 'ia32_settings.h',
- 'libdis.h',
- 'qword.h',
- 'x86_disasm.c',
- 'x86_format.c',
- 'x86_imm.c',
- 'x86_imm.h',
- 'x86_insn.c',
- 'x86_misc.c',
- 'x86_operand_list.c',
- 'x86_operand_list.h',
- ],
- },
- ],
-}
diff --git a/src/third_party/linux/include/gflags/gflags_completions.h b/src/third_party/linux/include/gflags/gflags_completions.h
index 9d9ce7a5..fe06b47a 100644
--- a/src/third_party/linux/include/gflags/gflags_completions.h
+++ b/src/third_party/linux/include/gflags/gflags_completions.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2008, Google Inc.
-// All rights reserved.
+// Copyright 2008 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/third_party/lss/linux_syscall_support.h b/src/third_party/lss/linux_syscall_support.h
index a0879033..99a4b444 100644
--- a/src/third_party/lss/linux_syscall_support.h
+++ b/src/third_party/lss/linux_syscall_support.h
@@ -88,7 +88,8 @@
*/
#if (defined(__i386__) || defined(__x86_64__) || defined(__ARM_ARCH_3__) || \
defined(__mips__) || defined(__PPC__) || defined(__ARM_EABI__) || \
- defined(__aarch64__) || defined(__s390__)) \
+ defined(__aarch64__) || defined(__s390__) || defined(__e2k__) || \
+ (defined(__riscv) && __riscv_xlen == 64) || defined(__loongarch_lp64)) \
&& (defined(__linux) || defined(__ANDROID__))
#ifndef SYS_CPLUSPLUS
@@ -266,6 +267,12 @@ struct kernel_timeval {
long tv_usec;
};
+/* include/linux/time.h */
+struct kernel_itimerval {
+ struct kernel_timeval it_interval;
+ struct kernel_timeval it_value;
+};
+
/* include/linux/resource.h */
struct kernel_rusage {
struct kernel_timeval ru_utime;
@@ -287,7 +294,8 @@ struct kernel_rusage {
};
#if defined(__i386__) || defined(__ARM_EABI__) || defined(__ARM_ARCH_3__) \
- || defined(__PPC__) || (defined(__s390__) && !defined(__s390x__))
+ || defined(__PPC__) || (defined(__s390__) && !defined(__s390x__)) \
+ || defined(__e2k__)
/* include/asm-{arm,i386,mips,ppc}/signal.h */
struct kernel_old_sigaction {
@@ -301,8 +309,8 @@ struct kernel_old_sigaction {
} __attribute__((packed,aligned(4)));
#elif (defined(__mips__) && _MIPS_SIM == _MIPS_SIM_ABI32)
#define kernel_old_sigaction kernel_sigaction
-#elif defined(__aarch64__)
- // No kernel_old_sigaction defined for arm64.
+#elif defined(__aarch64__) || defined(__riscv) || defined(__loongarch_lp64)
+ // No kernel_old_sigaction defined for arm64 riscv and loongarch64.
#endif
/* Some kernel functions (e.g. sigaction() in 2.6.23) require that the
@@ -341,7 +349,9 @@ struct kernel_sigaction {
void (*sa_sigaction_)(int, siginfo_t *, void *);
};
unsigned long sa_flags;
+#if !defined(__riscv) && !defined(__loongarch_lp64)
void (*sa_restorer)(void);
+#endif
struct kernel_sigset_t sa_mask;
#endif
};
@@ -355,6 +365,16 @@ struct kernel_sockaddr {
/* include/asm-{arm,aarch64,i386,mips,ppc,s390}/stat.h */
#ifdef __mips__
#if _MIPS_SIM == _MIPS_SIM_ABI64
+typedef unsigned long long kernel_blkcnt_t;
+typedef unsigned kernel_blksize_t;
+typedef unsigned kernel_dev_t;
+typedef unsigned kernel_gid_t;
+typedef unsigned long long kernel_ino_t;
+typedef unsigned kernel_mode_t;
+typedef unsigned kernel_nlink_t;
+typedef long long kernel_off_t;
+typedef unsigned kernel_time_t;
+typedef unsigned kernel_uid_t;
struct kernel_stat {
#else
struct kernel_stat64 {
@@ -401,6 +421,28 @@ struct kernel_stat64 {
unsigned long __unused4;
unsigned long __unused5;
};
+#elif defined(__e2k__)
+struct kernel_stat64 {
+ unsigned long long st_dev;
+ unsigned long long st_ino;
+ unsigned int st_mode;
+ unsigned int st_nlink;
+ unsigned int st_uid;
+ unsigned int st_gid;
+ unsigned long long st_rdev;
+ long long st_size;
+ int st_blksize;
+ int __pad2;
+ unsigned long long st_blocks;
+ int st_atime_;
+ unsigned int st_atime_nsec_;
+ int st_mtime_;
+ unsigned int st_mtime_nsec_;
+ int st_ctime_;
+ unsigned int st_ctime_nsec_;
+ unsigned int __unused4;
+ unsigned int __unused5;
+};
#else
struct kernel_stat64 {
unsigned long long st_dev;
@@ -427,165 +469,264 @@ struct kernel_stat64 {
/* include/asm-{arm,aarch64,i386,mips,x86_64,ppc,s390}/stat.h */
#if defined(__i386__) || defined(__ARM_ARCH_3__) || defined(__ARM_EABI__)
+typedef unsigned kernel_blkcnt_t;
+typedef unsigned kernel_blksize_t;
+typedef unsigned short kernel_dev_t;
+typedef unsigned short kernel_gid_t;
+typedef unsigned kernel_ino_t;
+typedef unsigned short kernel_mode_t;
+typedef unsigned short kernel_nlink_t;
+typedef unsigned kernel_off_t;
+typedef unsigned kernel_time_t;
+typedef unsigned short kernel_uid_t;
struct kernel_stat {
/* The kernel headers suggest that st_dev and st_rdev should be 32bit
* quantities encoding 12bit major and 20bit minor numbers in an interleaved
* format. In reality, we do not see useful data in the top bits. So,
* we'll leave the padding in here, until we find a better solution.
*/
- unsigned short st_dev;
+ kernel_dev_t st_dev;
short pad1;
- unsigned st_ino;
- unsigned short st_mode;
- unsigned short st_nlink;
- unsigned short st_uid;
- unsigned short st_gid;
- unsigned short st_rdev;
+ kernel_ino_t st_ino;
+ kernel_mode_t st_mode;
+ kernel_nlink_t st_nlink;
+ kernel_uid_t st_uid;
+ kernel_gid_t st_gid;
+ kernel_dev_t st_rdev;
short pad2;
- unsigned st_size;
- unsigned st_blksize;
- unsigned st_blocks;
- unsigned st_atime_;
+ kernel_off_t st_size;
+ kernel_blksize_t st_blksize;
+ kernel_blkcnt_t st_blocks;
+ kernel_time_t st_atime_;
unsigned st_atime_nsec_;
- unsigned st_mtime_;
+ kernel_time_t st_mtime_;
unsigned st_mtime_nsec_;
- unsigned st_ctime_;
+ kernel_time_t st_ctime_;
unsigned st_ctime_nsec_;
unsigned __unused4;
unsigned __unused5;
};
#elif defined(__x86_64__)
+typedef int64_t kernel_blkcnt_t;
+typedef int64_t kernel_blksize_t;
+typedef uint64_t kernel_dev_t;
+typedef unsigned kernel_gid_t;
+typedef uint64_t kernel_ino_t;
+typedef unsigned kernel_mode_t;
+typedef uint64_t kernel_nlink_t;
+typedef int64_t kernel_off_t;
+typedef uint64_t kernel_time_t;
+typedef unsigned kernel_uid_t;
struct kernel_stat {
- uint64_t st_dev;
- uint64_t st_ino;
- uint64_t st_nlink;
- unsigned st_mode;
- unsigned st_uid;
- unsigned st_gid;
+ kernel_dev_t st_dev;
+ kernel_ino_t st_ino;
+ kernel_nlink_t st_nlink;
+ kernel_mode_t st_mode;
+ kernel_uid_t st_uid;
+ kernel_gid_t st_gid;
unsigned __pad0;
- uint64_t st_rdev;
- int64_t st_size;
- int64_t st_blksize;
- int64_t st_blocks;
- uint64_t st_atime_;
+ kernel_dev_t st_rdev;
+ kernel_off_t st_size;
+ kernel_blksize_t st_blksize;
+ kernel_blkcnt_t st_blocks;
+ kernel_time_t st_atime_;
uint64_t st_atime_nsec_;
- uint64_t st_mtime_;
+ kernel_time_t st_mtime_;
uint64_t st_mtime_nsec_;
- uint64_t st_ctime_;
+ kernel_time_t st_ctime_;
uint64_t st_ctime_nsec_;
int64_t __unused4[3];
};
#elif defined(__PPC__)
+typedef unsigned long kernel_blkcnt_t;
+typedef unsigned long kernel_blksize_t;
+typedef unsigned kernel_dev_t;
+typedef unsigned kernel_gid_t;
+typedef unsigned long kernel_ino_t;
+typedef unsigned long kernel_mode_t;
+typedef unsigned short kernel_nlink_t;
+typedef long kernel_off_t;
+typedef unsigned long kernel_time_t;
+typedef unsigned kernel_uid_t;
struct kernel_stat {
- unsigned st_dev;
- unsigned long st_ino; // ino_t
- unsigned long st_mode; // mode_t
- unsigned short st_nlink; // nlink_t
- unsigned st_uid; // uid_t
- unsigned st_gid; // gid_t
- unsigned st_rdev;
- long st_size; // off_t
- unsigned long st_blksize;
- unsigned long st_blocks;
- unsigned long st_atime_;
+ kernel_dev_t st_dev;
+ kernel_ino_t st_ino;
+ kernel_mode_t st_mode;
+ kernel_nlink_t st_nlink;
+ kernel_gid_t st_uid;
+ kernel_uid_t st_gid;
+ kernel_dev_t st_rdev;
+ kernel_off_t st_size;
+ kernel_blksize_t st_blksize;
+ kernel_blkcnt_t st_blocks;
+ kernel_time_t st_atime_;
unsigned long st_atime_nsec_;
- unsigned long st_mtime_;
+ kernel_time_t st_mtime_;
unsigned long st_mtime_nsec_;
- unsigned long st_ctime_;
+ kernel_time_t st_ctime_;
unsigned long st_ctime_nsec_;
unsigned long __unused4;
unsigned long __unused5;
};
#elif (defined(__mips__) && _MIPS_SIM != _MIPS_SIM_ABI64)
+typedef int kernel_blkcnt_t;
+typedef int kernel_blksize_t;
+typedef unsigned kernel_dev_t;
+typedef unsigned kernel_gid_t;
+typedef unsigned kernel_ino_t;
+typedef unsigned kernel_mode_t;
+typedef unsigned kernel_nlink_t;
+typedef long kernel_off_t;
+typedef long kernel_time_t;
+typedef unsigned kernel_uid_t;
struct kernel_stat {
- unsigned st_dev;
+ kernel_dev_t st_dev;
int st_pad1[3];
- unsigned st_ino;
- unsigned st_mode;
- unsigned st_nlink;
- unsigned st_uid;
- unsigned st_gid;
- unsigned st_rdev;
+ kernel_ino_t st_ino;
+ kernel_mode_t st_mode;
+ kernel_nlink_t st_nlink;
+ kernel_uid_t st_uid;
+ kernel_gid_t st_gid;
+ kernel_dev_t st_rdev;
int st_pad2[2];
- long st_size;
+ kernel_off_t st_size;
int st_pad3;
- long st_atime_;
+ kernel_time_t st_atime_;
long st_atime_nsec_;
- long st_mtime_;
+ kernel_time_t st_mtime_;
long st_mtime_nsec_;
- long st_ctime_;
+ kernel_time_t st_ctime_;
long st_ctime_nsec_;
- int st_blksize;
- int st_blocks;
+ kernel_blksize_t st_blksize;
+ kernel_blkcnt_t st_blocks;
int st_pad4[14];
};
-#elif defined(__aarch64__)
+#elif defined(__aarch64__) || defined(__riscv) || defined(__loongarch_lp64)
+typedef long kernel_blkcnt_t;
+typedef int kernel_blksize_t;
+typedef unsigned long kernel_dev_t;
+typedef unsigned int kernel_gid_t;
+typedef unsigned long kernel_ino_t;
+typedef unsigned int kernel_mode_t;
+typedef unsigned int kernel_nlink_t;
+typedef long kernel_off_t;
+typedef long kernel_time_t;
+typedef unsigned int kernel_uid_t;
struct kernel_stat {
- unsigned long st_dev;
- unsigned long st_ino;
- unsigned int st_mode;
- unsigned int st_nlink;
- unsigned int st_uid;
- unsigned int st_gid;
- unsigned long st_rdev;
+ kernel_dev_t st_dev;
+ kernel_ino_t st_ino;
+ kernel_mode_t st_mode;
+ kernel_nlink_t st_nlink;
+ kernel_uid_t st_uid;
+ kernel_gid_t st_gid;
+ kernel_dev_t st_rdev;
unsigned long __pad1;
- long st_size;
- int st_blksize;
+ kernel_off_t st_size;
+ kernel_blksize_t st_blksize;
int __pad2;
- long st_blocks;
- long st_atime_;
+ kernel_blkcnt_t st_blocks;
+ kernel_time_t st_atime_;
unsigned long st_atime_nsec_;
- long st_mtime_;
+ kernel_time_t st_mtime_;
unsigned long st_mtime_nsec_;
- long st_ctime_;
+ kernel_time_t st_ctime_;
unsigned long st_ctime_nsec_;
unsigned int __unused4;
unsigned int __unused5;
};
#elif defined(__s390x__)
+typedef long kernel_blkcnt_t;
+typedef unsigned long kernel_blksize_t;
+typedef unsigned long kernel_dev_t;
+typedef unsigned int kernel_gid_t;
+typedef unsigned long kernel_ino_t;
+typedef unsigned int kernel_mode_t;
+typedef unsigned long kernel_nlink_t;
+typedef unsigned long kernel_off_t;
+typedef unsigned long kernel_time_t;
+typedef unsigned int kernel_uid_t;
struct kernel_stat {
- unsigned long st_dev;
- unsigned long st_ino;
- unsigned long st_nlink;
- unsigned int st_mode;
- unsigned int st_uid;
- unsigned int st_gid;
+ kernel_dev_t st_dev;
+ kernel_ino_t st_ino;
+ kernel_nlink_t st_nlink;
+ kernel_mode_t st_mode;
+ kernel_uid_t st_uid;
+ kernel_gid_t st_gid;
unsigned int __pad1;
- unsigned long st_rdev;
- unsigned long st_size;
- unsigned long st_atime_;
+ kernel_dev_t st_rdev;
+ kernel_off_t st_size;
+ kernel_time_t st_atime_;
unsigned long st_atime_nsec_;
- unsigned long st_mtime_;
+ kernel_time_t st_mtime_;
unsigned long st_mtime_nsec_;
- unsigned long st_ctime_;
+ kernel_time_t st_ctime_;
unsigned long st_ctime_nsec_;
- unsigned long st_blksize;
- long st_blocks;
+ kernel_blksize_t st_blksize;
+ kernel_blkcnt_t st_blocks;
unsigned long __unused[3];
};
#elif defined(__s390__)
+typedef unsigned long kernel_blkcnt_t;
+typedef unsigned long kernel_blksize_t;
+typedef unsigned short kernel_dev_t;
+typedef unsigned short kernel_gid_t;
+typedef unsigned long kernel_ino_t;
+typedef unsigned short kernel_mode_t;
+typedef unsigned short kernel_nlink_t;
+typedef unsigned long kernel_off_t;
+typedef unsigned long kernel_time_t;
+typedef unsigned short kernel_uid_t;
struct kernel_stat {
- unsigned short st_dev;
+ kernel_dev_t st_dev;
unsigned short __pad1;
- unsigned long st_ino;
- unsigned short st_mode;
- unsigned short st_nlink;
- unsigned short st_uid;
- unsigned short st_gid;
- unsigned short st_rdev;
+ kernel_ino_t st_ino;
+ kernel_mode_t st_mode;
+ kernel_nlink_t st_nlink;
+ kernel_uid_t st_uid;
+ kernel_gid_t st_gid;
+ kernel_dev_t st_rdev;
unsigned short __pad2;
- unsigned long st_size;
- unsigned long st_blksize;
- unsigned long st_blocks;
- unsigned long st_atime_;
+ kernel_off_t st_size;
+ kernel_blksize_t st_blksize;
+ kernel_blkcnt_t st_blocks;
+ kernel_time_t st_atime_;
unsigned long st_atime_nsec_;
- unsigned long st_mtime_;
+ kernel_time_t st_mtime_;
unsigned long st_mtime_nsec_;
- unsigned long st_ctime_;
+ kernel_time_t st_ctime_;
unsigned long st_ctime_nsec_;
unsigned long __unused4;
unsigned long __unused5;
};
+#elif defined(__e2k__)
+typedef unsigned long kernel_blkcnt_t;
+typedef unsigned long kernel_blksize_t;
+typedef unsigned long kernel_dev_t;
+typedef unsigned int kernel_gid_t;
+typedef unsigned long kernel_ino_t;
+typedef unsigned int kernel_mode_t;
+typedef unsigned long kernel_nlink_t;
+typedef unsigned long kernel_off_t;
+typedef unsigned long kernel_time_t;
+typedef unsigned int kernel_uid_t;
+struct kernel_stat {
+ kernel_dev_t st_dev;
+ kernel_ino_t st_ino;
+ kernel_mode_t st_mode;
+ kernel_nlink_t st_nlink;
+ kernel_uid_t st_uid;
+ kernel_gid_t st_gid;
+ kernel_dev_t st_rdev;
+ kernel_off_t st_size;
+ kernel_blksize_t st_blksize;
+ kernel_blkcnt_t st_blocks;
+ kernel_time_t st_atime_;
+ unsigned long st_atime_nsec_;
+ kernel_time_t st_mtime_;
+ unsigned long st_mtime_nsec_;
+ kernel_time_t st_ctime_;
+ unsigned long st_ctime_nsec_;
+};
#endif
/* include/asm-{arm,aarch64,i386,mips,x86_64,ppc,s390}/statfs.h */
@@ -701,6 +842,37 @@ struct kernel_statfs {
};
#endif
+struct kernel_statx_timestamp {
+ int64_t tv_sec;
+ uint32_t tv_nsec;
+ int32_t __reserved;
+};
+
+struct kernel_statx {
+ uint32_t stx_mask;
+ uint32_t stx_blksize;
+ uint64_t stx_attributes;
+ uint32_t stx_nlink;
+ uint32_t stx_uid;
+ uint32_t stx_gid;
+ uint16_t stx_mode;
+ uint16_t __spare0[1];
+ uint64_t stx_ino;
+ uint64_t stx_size;
+ uint64_t stx_blocks;
+ uint64_t stx_attributes_mask;
+ struct kernel_statx_timestamp stx_atime;
+ struct kernel_statx_timestamp stx_btime;
+ struct kernel_statx_timestamp stx_ctime;
+ struct kernel_statx_timestamp stx_mtime;
+ uint32_t stx_rdev_major;
+ uint32_t stx_rdev_minor;
+ uint32_t stx_dev_major;
+ uint32_t stx_dev_minor;
+ uint64_t stx_mnt_id;
+ uint64_t __spare2;
+ uint64_t __spare3[12];
+};
/* Definitions missing from the standard header files */
#ifndef O_DIRECTORY
@@ -737,6 +909,18 @@ struct kernel_statfs {
#ifndef AT_REMOVEDIR
#define AT_REMOVEDIR 0x200
#endif
+#ifndef AT_NO_AUTOMOUNT
+#define AT_NO_AUTOMOUNT 0x800
+#endif
+#ifndef AT_EMPTY_PATH
+#define AT_EMPTY_PATH 0x1000
+#endif
+#ifndef STATX_BASIC_STATS
+#define STATX_BASIC_STATS 0x000007ffU
+#endif
+#ifndef AT_STATX_SYNC_AS_STAT
+#define AT_STATX_SYNC_AS_STAT 0x0000
+#endif
#ifndef MREMAP_FIXED
#define MREMAP_FIXED 2
#endif
@@ -954,6 +1138,9 @@ struct kernel_statfs {
#ifndef __NR_fallocate
#define __NR_fallocate 324
#endif
+#ifndef __NR_getrandom
+#define __NR_getrandom 355
+#endif
/* End of i386 definitions */
#elif defined(__ARM_ARCH_3__) || defined(__ARM_EABI__)
#ifndef __NR_setresuid
@@ -1052,14 +1239,20 @@ struct kernel_statfs {
#ifndef __NR_ioprio_get
#define __NR_ioprio_get (__NR_SYSCALL_BASE + 315)
#endif
+#ifndef __NR_fstatat64
+#define __NR_fstatat64 (__NR_SYSCALL_BASE + 327)
+#endif
#ifndef __NR_move_pages
#define __NR_move_pages (__NR_SYSCALL_BASE + 344)
#endif
#ifndef __NR_getcpu
#define __NR_getcpu (__NR_SYSCALL_BASE + 345)
#endif
+#ifndef __NR_getrandom
+#define __NR_getrandom (__NR_SYSCALL_BASE + 384)
+#endif
/* End of ARM 3/EABI definitions */
-#elif defined(__aarch64__)
+#elif defined(__aarch64__) || defined(__riscv) || defined(__loongarch_lp64)
#ifndef __NR_setxattr
#define __NR_setxattr 5
#endif
@@ -1115,9 +1308,11 @@ struct kernel_statfs {
#ifndef __NR_readlinkat
#define __NR_readlinkat 78
#endif
+#if !defined(__loongarch_lp64)
#ifndef __NR_newfstatat
#define __NR_newfstatat 79
#endif
+#endif
#ifndef __NR_set_tid_address
#define __NR_set_tid_address 96
#endif
@@ -1155,7 +1350,12 @@ struct kernel_statfs {
#ifndef __NR_move_pages
#define __NR_move_pages 239
#endif
-/* End of aarch64 definitions */
+#ifndef __NR_getrandom
+#define __NR_getrandom 278
+#endif
+#ifndef __NR_statx
+#define __NR_statx 291
+#endif
#elif defined(__x86_64__)
#ifndef __NR_pread64
#define __NR_pread64 17
@@ -1246,6 +1446,9 @@ struct kernel_statfs {
#ifndef __NR_fallocate
#define __NR_fallocate 285
#endif
+#ifndef __NR_getrandom
+#define __NR_getrandom 318
+#endif
/* End of x86-64 definitions */
#elif defined(__mips__)
#if _MIPS_SIM == _MIPS_SIM_ABI32
@@ -1347,6 +1550,9 @@ struct kernel_statfs {
#ifndef __NR_ioprio_get
#define __NR_ioprio_get (__NR_Linux + 315)
#endif
+#ifndef __NR_getrandom
+#define __NR_getrandom (__NR_Linux + 353)
+#endif
/* End of MIPS (old 32bit API) definitions */
#elif _MIPS_SIM == _MIPS_SIM_ABI64
#ifndef __NR_pread64
@@ -1425,6 +1631,9 @@ struct kernel_statfs {
#ifndef __NR_ioprio_get
#define __NR_ioprio_get (__NR_Linux + 274)
#endif
+#ifndef __NR_getrandom
+#define __NR_getrandom (__NR_Linux + 313)
+#endif
/* End of MIPS (64bit API) definitions */
#else
#ifndef __NR_setresuid
@@ -1861,15 +2070,16 @@ struct kernel_statfs {
#endif
#undef LSS_RETURN
- #if (defined(__i386__) || defined(__x86_64__) || defined(__ARM_ARCH_3__) \
- || defined(__ARM_EABI__) || defined(__aarch64__) || defined(__s390__))
+ #if defined(__i386__) || defined(__x86_64__) || defined(__ARM_ARCH_3__) \
+ || defined(__ARM_EABI__) || defined(__aarch64__) || defined(__s390__) \
+ || defined(__e2k__) || defined(__riscv) || defined(__loongarch_lp64)
/* Failing system calls return a negative result in the range of
* -1..-4095. These are "errno" values with the sign inverted.
*/
#define LSS_RETURN(type, res) \
do { \
if ((unsigned long)(res) >= (unsigned long)(-4095)) { \
- LSS_ERRNO = -(res); \
+ LSS_ERRNO = (int)(-(res)); \
res = -1; \
} \
return (type) (res); \
@@ -2223,7 +2433,7 @@ struct kernel_statfs {
#define _LSS_RETURN(type, res, cast) \
do { \
if ((uint64_t)(res) >= (uint64_t)(-4095)) { \
- LSS_ERRNO = -(res); \
+ LSS_ERRNO = (int)(-(res)); \
res = -1; \
} \
return (type)(cast)(res); \
@@ -2772,7 +2982,7 @@ struct kernel_statfs {
void *newtls, int *child_tidptr) {
int64_t __res;
{
- register uint64_t __flags __asm__("x0") = flags;
+ register uint64_t __flags __asm__("x0") = (uint64_t)flags;
register void *__stack __asm__("x1") = child_stack;
register void *__ptid __asm__("x2") = parent_tidptr;
register void *__tls __asm__("x3") = newtls;
@@ -3355,6 +3565,503 @@ struct kernel_statfs {
}
LSS_RETURN(int, __ret);
}
+ #elif defined(__riscv) && __riscv_xlen == 64
+ #undef LSS_REG
+ #define LSS_REG(r,a) register int64_t __r##r __asm__("a"#r) = (int64_t)a
+ #undef LSS_BODY
+ #define LSS_BODY(type,name,args...) \
+ register int64_t __res_a0 __asm__("a0"); \
+ register int64_t __a7 __asm__("a7") = __NR_##name; \
+ int64_t __res; \
+ __asm__ __volatile__ ("scall\n" \
+ : "=r"(__res_a0) \
+ : "r"(__a7) , ## args \
+ : "memory"); \
+ __res = __res_a0; \
+ LSS_RETURN(type, __res)
+ #undef _syscall0
+ #define _syscall0(type, name) \
+ type LSS_NAME(name)(void) { \
+ LSS_BODY(type, name); \
+ }
+ #undef _syscall1
+ #define _syscall1(type, name, type1, arg1) \
+ type LSS_NAME(name)(type1 arg1) { \
+ LSS_REG(0, arg1); LSS_BODY(type, name, "r"(__r0)); \
+ }
+ #undef _syscall2
+ #define _syscall2(type, name, type1, arg1, type2, arg2) \
+ type LSS_NAME(name)(type1 arg1, type2 arg2) { \
+ LSS_REG(0, arg1); LSS_REG(1, arg2); \
+ LSS_BODY(type, name, "r"(__r0), "r"(__r1)); \
+ }
+ #undef _syscall3
+ #define _syscall3(type, name, type1, arg1, type2, arg2, type3, arg3) \
+ type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3) { \
+ LSS_REG(0, arg1); LSS_REG(1, arg2); LSS_REG(2, arg3); \
+ LSS_BODY(type, name, "r"(__r0), "r"(__r1), "r"(__r2)); \
+ }
+ #undef _syscall4
+ #define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4) \
+ type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4) { \
+ LSS_REG(0, arg1); LSS_REG(1, arg2); LSS_REG(2, arg3); \
+ LSS_REG(3, arg4); \
+ LSS_BODY(type, name, "r"(__r0), "r"(__r1), "r"(__r2), "r"(__r3)); \
+ }
+ #undef _syscall5
+ #define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \
+ type5,arg5) \
+ type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \
+ type5 arg5) { \
+ LSS_REG(0, arg1); LSS_REG(1, arg2); LSS_REG(2, arg3); \
+ LSS_REG(3, arg4); LSS_REG(4, arg5); \
+ LSS_BODY(type, name, "r"(__r0), "r"(__r1), "r"(__r2), "r"(__r3), \
+ "r"(__r4)); \
+ }
+ #undef _syscall6
+ #define _syscall6(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \
+ type5,arg5,type6,arg6) \
+ type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \
+ type5 arg5, type6 arg6) { \
+ LSS_REG(0, arg1); LSS_REG(1, arg2); LSS_REG(2, arg3); \
+ LSS_REG(3, arg4); LSS_REG(4, arg5); LSS_REG(5, arg6); \
+ LSS_BODY(type, name, "r"(__r0), "r"(__r1), "r"(__r2), "r"(__r3), \
+ "r"(__r4), "r"(__r5)); \
+ }
+
+ LSS_INLINE int LSS_NAME(clone)(int (*fn)(void *), void *child_stack,
+ int flags, void *arg, int *parent_tidptr,
+ void *newtls, int *child_tidptr) {
+ int64_t __res;
+ {
+ register int64_t __res_a0 __asm__("a0");
+ register uint64_t __flags __asm__("a0") = flags;
+ register void *__stack __asm__("a1") = child_stack;
+ register void *__ptid __asm__("a2") = parent_tidptr;
+ register void *__tls __asm__("a3") = newtls;
+ register int *__ctid __asm__("a4") = child_tidptr;
+ __asm__ __volatile__(/* Push "arg" and "fn" onto the stack that will be
+ * used by the child.
+ */
+ "addi %2,%2,-16\n"
+ "sd %1, 0(%2)\n"
+ "sd %4, 8(%2)\n"
+
+ /* %a0 = syscall(%a0 = flags,
+ * %a1 = child_stack,
+ * %a2 = parent_tidptr,
+ * %a3 = newtls,
+ * %a4 = child_tidptr)
+ */
+ "li a7, %8\n"
+ "scall\n"
+
+ /* if (%a0 != 0)
+ * return %a0;
+ */
+ "bnez %0, 1f\n"
+
+ /* In the child, now. Call "fn(arg)".
+ */
+ "ld a1, 0(sp)\n"
+ "ld a0, 8(sp)\n"
+ "jalr a1\n"
+
+ /* Call _exit(%a0).
+ */
+ "li a7, %9\n"
+ "scall\n"
+ "1:\n"
+ : "=r" (__res_a0)
+ : "r"(fn), "r"(__stack), "r"(__flags), "r"(arg),
+ "r"(__ptid), "r"(__tls), "r"(__ctid),
+ "i"(__NR_clone), "i"(__NR_exit)
+ : "cc", "memory");
+ __res = __res_a0;
+ }
+ LSS_RETURN(int, __res);
+ }
+ #elif defined(__e2k__)
+
+ #undef _LSS_BODY
+ #define _LSS_BODY(nr, type, name, ...) \
+ register unsigned long long __res; \
+ __asm__ __volatile__ \
+ ( \
+ "{\n\t" \
+ " sdisp %%ctpr1, 0x3\n\t" \
+ " addd, s 0x0, %[sys_num], %%b[0]\n\t" \
+ LSS_BODY_ASM##nr \
+ "}\n\t" \
+ "{\n\t" \
+ " call %%ctpr1, wbs = %#\n\t" \
+ "}\n\t" \
+ "{\n\t" \
+ " addd, s 0x0, %%b[0], %[res]\n\t" \
+ "}\n\t" \
+ : [res] "=r" (__res) \
+ : \
+ LSS_BODY_ARG##nr(__VA_ARGS__) \
+ [sys_num] "ri" (__NR_##name) \
+ : "ctpr1", "ctpr2", "ctpr3", \
+ "b[0]", "b[1]", "b[2]", "b[3]", \
+ "b[4]", "b[5]", "b[6]", "b[7]" \
+ ); \
+ LSS_RETURN(type, __res);
+
+ #undef LSS_BODY
+ #define LSS_BODY(nr, type, name, args...) \
+ _LSS_BODY(nr, type, name, ## args)
+
+ #undef LSS_BODY_ASM0
+ #undef LSS_BODY_ASM1
+ #undef LSS_BODY_ASM2
+ #undef LSS_BODY_ASM3
+ #undef LSS_BODY_ASM4
+ #undef LSS_BODY_ASM5
+ #undef LSS_BODY_ASM6
+
+ #define LSS_BODY_ASM0
+ #define LSS_BODY_ASM1 LSS_BODY_ASM0 \
+ " addd, s 0x0, %[arg1], %%b[1]\n\t"
+ #define LSS_BODY_ASM2 LSS_BODY_ASM1 \
+ " addd, s 0x0, %[arg2], %%b[2]\n\t"
+ #define LSS_BODY_ASM3 LSS_BODY_ASM2 \
+ " addd, s 0x0, %[arg3], %%b[3]\n\t"
+ #define LSS_BODY_ASM4 LSS_BODY_ASM3 \
+ " addd, s 0x0, %[arg4], %%b[4]\n\t"
+ #define LSS_BODY_ASM5 LSS_BODY_ASM4 \
+ " addd, s 0x0, %[arg5], %%b[5]\n\t"
+ #define LSS_BODY_ASM6 LSS_BODY_ASM5 \
+ "}\n\t" \
+ "{\n\t" \
+ " addd, s 0x0, %[arg6], %%b[6]\n\t"
+
+ #undef LSS_SYSCALL_ARG
+ #define LSS_SYSCALL_ARG(a) ((unsigned long long)(uintptr_t)(a))
+
+ #undef LSS_BODY_ARG0
+ #undef LSS_BODY_ARG1
+ #undef LSS_BODY_ARG2
+ #undef LSS_BODY_ARG3
+ #undef LSS_BODY_ARG4
+ #undef LSS_BODY_ARG5
+ #undef LSS_BODY_ARG6
+
+ #define LSS_BODY_ARG0()
+ #define LSS_BODY_ARG1(_arg1) \
+ [arg1] "ri" LSS_SYSCALL_ARG(_arg1),
+ #define LSS_BODY_ARG2(_arg1, _arg2) \
+ LSS_BODY_ARG1(_arg1) \
+ [arg2] "ri" LSS_SYSCALL_ARG(_arg2),
+ #define LSS_BODY_ARG3(_arg1, _arg2, _arg3) \
+ LSS_BODY_ARG2(_arg1, _arg2) \
+ [arg3] "ri" LSS_SYSCALL_ARG(_arg3),
+ #define LSS_BODY_ARG4(_arg1, _arg2, _arg3, _arg4) \
+ LSS_BODY_ARG3(_arg1, _arg2, _arg3) \
+ [arg4] "ri" LSS_SYSCALL_ARG(_arg4),
+ #define LSS_BODY_ARG5(_arg1, _arg2, _arg3, _arg4, _arg5) \
+ LSS_BODY_ARG4(_arg1, _arg2, _arg3, _arg4) \
+ [arg5] "ri" LSS_SYSCALL_ARG(_arg5),
+ #define LSS_BODY_ARG6(_arg1, _arg2, _arg3, _arg4, _arg5, _arg6) \
+ LSS_BODY_ARG5(_arg1, _arg2, _arg3, _arg4, _arg5) \
+ [arg6] "ri" LSS_SYSCALL_ARG(_arg6),
+
+ #undef _syscall0
+ #define _syscall0(type, name) \
+ type LSS_NAME(name)(void) { \
+ LSS_BODY(0, type, name); \
+ }
+
+ #undef _syscall1
+ #define _syscall1(type, name, type1, arg1) \
+ type LSS_NAME(name)(type1 arg1) { \
+ LSS_BODY(1, type, name, arg1) \
+ }
+
+ #undef _syscall2
+ #define _syscall2(type, name, type1, arg1, type2, arg2) \
+ type LSS_NAME(name)(type1 arg1, type2 arg2) { \
+ LSS_BODY(2, type, name, arg1, arg2) \
+ }
+
+ #undef _syscall3
+ #define _syscall3(type, name, type1, arg1, type2, arg2, type3, arg3) \
+ type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3) { \
+ LSS_BODY(3, type, name, arg1, arg2, arg3) \
+ }
+
+ #undef _syscall4
+ #define _syscall4(type, name, type1, arg1, type2, arg2, type3, arg3, \
+ type4, arg4) \
+ type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4) { \
+ LSS_BODY(4, type, name, arg1, arg2, arg3, arg4) \
+ }
+
+ #undef _syscall5
+ #define _syscall5(type, name, type1, arg1, type2, arg2, type3, arg3, \
+ type4, arg4, type5, arg5) \
+ type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \
+ type5 arg5) { \
+ LSS_BODY(5, type, name, arg1, arg2, arg3, arg4, arg5) \
+ }
+
+ #undef _syscall6
+ #define _syscall6(type, name, type1, arg1, type2, arg2, type3, arg3, \
+ type4, arg4, type5, arg5, type6, arg6) \
+ type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \
+ type5 arg5, type6 arg6) { \
+ LSS_BODY(6, type, name, arg1, arg2, arg3, arg4, arg5, arg6) \
+ }
+
+ LSS_INLINE int LSS_NAME(clone)(int (*fn)(void *), void *child_stack,
+ int flags, void *arg, int *parent_tidptr,
+ void *newtls, int *child_tidptr) {
+ unsigned long long __res;
+
+ __asm__ __volatile__ (
+ "{\n\t"
+ " addd,s 0x0, %[nr_clone], %%b[0]\n\t"
+ " addd,s 0x0, %[flags], %%db[1]\n\t"
+ " addd,s 0x0, %[child_stack], %%db[2]\n\t"
+ " addd,s 0x0, %[parent_tidptr], %%db[3]\n\t"
+ " addd,s 0x0, %[child_tidptr], %%db[4]\n\t"
+ " addd,s 0x0, %[newtls], %%db[5]\n\t"
+ "}\n\t"
+ /* if (fn == NULL)
+ * return -EINVAL;
+ */
+
+ "{\n\t"
+ " disp %%ctpr1, .L1\n\t"
+ "}\n\t"
+ "{\n\t"
+ " cmpesb,s 0x0, %[fn], %%pred0\n\t"
+ "}\n\t"
+ "{\n\t"
+ " ct %%ctpr1 ? %%pred0\n\t"
+ "}\n\t"
+
+ /* if (child_stack == NULL)
+ * return -EINVAL;
+ */
+ "{\n\t"
+ " cmpesb,s 0x0, %%db[2], %%pred0\n\t"
+ "}\n\t"
+ "{\n\t"
+ " ct %%ctpr1 ? %%pred0\n\t"
+ "}\n\t"
+
+ /* b[0] = syscall(%b[0] = __NR_clone,
+ * %db[1] = flags,
+ * %db[2] = child_stack,
+ * %db[3] = parent_tidptr,
+ * %db[4] = child_tidptr,
+ * %db[5] = newtls)
+ */
+ "{\n\t"
+ " sdisp %%ctpr1, 0x3\n\t"
+ "}\n\t"
+ "{\n\t"
+ " call %%ctpr1, wbs = %#\n\t"
+ "}\n\t"
+
+ /* if (%[b0] != 0)
+ * return %b[0];
+ */
+ "{\n\t"
+ " disp %%ctpr1, .L2\n\t"
+ " cmpesb,s 0x0, %%b[0], %%pred0\n\t"
+ "}\n\t"
+ "{\n\t"
+ " ct %%ctpr1 ? ~%%pred0\n\t"
+ "}\n\t"
+ /* In the child, now. Call "fn(arg)".
+ */
+
+ "{\n\t"
+ " movtd,s %[fn], %%ctpr1\n\t"
+ "}\n\t"
+ "{\n\t"
+ " addd,s 0x0, %[arg], %%db[0]\n\t"
+ "}\n\t"
+ "{\n\t"
+ " call %%ctpr1, wbs = %#\n\t"
+ "}\n\t"
+ /* Call _exit(%b[0]).
+ */
+
+ "{\n\t"
+ " sdisp %%ctpr1, 0x3\n\t"
+ " addd,s 0x0, %%b[0], %%b[1]\n\t"
+ "}\n\t"
+ "{\n\t"
+ " addd,s 0x0, %[nr_exit], %%b[0]\n\t"
+ "}\n\t"
+ "{\n\t"
+ " call %%ctpr1, wbs = %#\n\t"
+ "}\n\t"
+ "{\n\t"
+ " disp %%ctpr1, .L2\n\t"
+ " adds,s 0x0, 0x0, %%b[0]\n\t"
+ "}\n\t"
+ "{\n\t"
+ " ct %%ctpr1\n\t"
+ "}\n\t"
+ ".L1:\n\t"
+ "{\n\t"
+ " addd,s 0x0, %[einval], %%b[0]\n\t"
+ "}\n\t"
+ ".L2:\n\t"
+ "{\n\t"
+ " addd,s 0x0, %%b[0], %[res]\n\t"
+ "}\n\t"
+ : [res] "=r" LSS_SYSCALL_ARG(__res)
+ : [nr_clone] "ri" LSS_SYSCALL_ARG(__NR_clone)
+ [arg] "ri" LSS_SYSCALL_ARG(arg)
+ [nr_exit] "ri" LSS_SYSCALL_ARG(__NR_exit)
+ [flags] "ri" LSS_SYSCALL_ARG(flags)
+ [child_stack] "ri" LSS_SYSCALL_ARG(child_stack)
+ [parent_tidptr] "ri"
+ LSS_SYSCALL_ARG(parent_tidptr)
+ [newtls] "ri" LSS_SYSCALL_ARG(newtls)
+ [child_tidptr] "ri"
+ LSS_SYSCALL_ARG(child_tidptr)
+ [fn] "ri" LSS_SYSCALL_ARG(fn)
+ [einval] "ri" LSS_SYSCALL_ARG(-EINVAL)
+ : "ctpr1", "b[0]", "b[1]", "b[2]", "b[3]",
+ "b[4]", "b[5]", "pred0");
+ LSS_RETURN(int, __res);
+ }
+ #elif defined(__loongarch_lp64)
+ /* Most definitions of _syscallX() neglect to mark "memory" as being
+ * clobbered. This causes problems with compilers, that do a better job
+ * at optimizing across __asm__ calls.
+ * So, we just have to redefine all of the _syscallX() macros.
+ */
+ #undef LSS_REG
+ #define LSS_REG(ar,a) register int64_t __r##ar __asm__("a"#ar) = (int64_t)a
+ /* syscall is like subroutine calls, all caller-saved registers may be
+ * clobbered, we should add them to the |Clobbers| list.
+ * a0 is not included because it's in the output list.
+ */
+ #define LSS_SYSCALL_CLOBBERS "t0", "t1", "t2", "t3", "t4", "t5", "t6", \
+ "t7", "t8", "memory"
+ #undef LSS_BODY
+ #define LSS_BODY(type,name,args...) \
+ register int64_t __res_a0 __asm__("a0"); \
+ int64_t __res; \
+ __asm__ __volatile__ ("li.d $a7, %1\n" \
+ "syscall 0x0\n" \
+ : "=r"(__res_a0) \
+ : "i"(__NR_##name) , ## args \
+ : LSS_SYSCALL_CLOBBERS); \
+ __res = __res_a0; \
+ LSS_RETURN(type, __res)
+ #undef _syscall0
+ #define _syscall0(type, name) \
+ type LSS_NAME(name)(void) { \
+ LSS_BODY(type, name); \
+ }
+ #undef _syscall1
+ #define _syscall1(type, name, type1, arg1) \
+ type LSS_NAME(name)(type1 arg1) { \
+ LSS_REG(0, arg1); LSS_BODY(type, name, "r"(__r0)); \
+ }
+ #undef _syscall2
+ #define _syscall2(type, name, type1, arg1, type2, arg2) \
+ type LSS_NAME(name)(type1 arg1, type2 arg2) { \
+ LSS_REG(0, arg1); LSS_REG(1, arg2); \
+ LSS_BODY(type, name, "r"(__r0), "r"(__r1)); \
+ }
+ #undef _syscall3
+ #define _syscall3(type, name, type1, arg1, type2, arg2, type3, arg3) \
+ type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3) { \
+ LSS_REG(0, arg1); LSS_REG(1, arg2); LSS_REG(2, arg3); \
+ LSS_BODY(type, name, "r"(__r0), "r"(__r1), "r"(__r2)); \
+ }
+ #undef _syscall4
+ #define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4) \
+ type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4) { \
+ LSS_REG(0, arg1); LSS_REG(1, arg2); LSS_REG(2, arg3); \
+ LSS_REG(3, arg4); \
+ LSS_BODY(type, name, "r"(__r0), "r"(__r1), "r"(__r2), "r"(__r3)); \
+ }
+ #undef _syscall5
+ #define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \
+ type5,arg5) \
+ type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \
+ type5 arg5) { \
+ LSS_REG(0, arg1); LSS_REG(1, arg2); LSS_REG(2, arg3); \
+ LSS_REG(3, arg4); LSS_REG(4, arg5); \
+ LSS_BODY(type, name, "r"(__r0), "r"(__r1), "r"(__r2), "r"(__r3), \
+ "r"(__r4)); \
+ }
+ #undef _syscall6
+ #define _syscall6(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \
+ type5,arg5,type6,arg6) \
+ type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \
+ type5 arg5, type6 arg6) { \
+ LSS_REG(0, arg1); LSS_REG(1, arg2); LSS_REG(2, arg3); \
+ LSS_REG(3, arg4); LSS_REG(4, arg5); LSS_REG(5, arg6); \
+ LSS_BODY(type, name, "r"(__r0), "r"(__r1), "r"(__r2), "r"(__r3), \
+ "r"(__r4), "r"(__r5)); \
+ }
+
+ LSS_INLINE int LSS_NAME(clone)(int (*fn)(void *), void *child_stack,
+ int flags, void *arg, int *parent_tidptr,
+ void *newtls, int *child_tidptr) {
+ int64_t __res;
+ {
+ register int64_t __res_a0 __asm__("a0");
+ register uint64_t __flags __asm__("a0") = flags;
+ register void *__stack __asm__("a1") = child_stack;
+ register void *__ptid __asm__("a2") = parent_tidptr;
+ register void *__tls __asm__("a3") = newtls;
+ register int *__ctid __asm__("a4") = child_tidptr;
+ __asm__ __volatile__(/* Push "arg" and "fn" onto the stack that will be
+ * used by the child.
+ */
+ "addi.d %2, %2, -16\n"
+ "st.d %1, %2, 8\n"
+ "st.d %4, %2, 0\n"
+
+ /* %a0 = syscall(%a0 = flags,
+ * %a1 = child_stack,
+ * %a2 = parent_tidptr,
+ * %a3 = newtls,
+ * %a4 = child_tidptr)
+ */
+ "li.d $a7, %8\n"
+ "syscall 0x0\n"
+
+ /* if (%a0 != 0)
+ * return %a0;
+ */
+ "bnez $a0, 1f\n"
+
+ /* In the child, now. Call "fn(arg)".
+ */
+ "ld.d $a0, $sp, 0\n"
+ "ld.d $a1, $sp, 8\n"
+ "addi.d $sp, $sp, 16\n"
+ "jirl $ra, $a1, 0\n"
+
+ /* Call _exit(%a0).
+ */
+ "li.d $a7, %9\n"
+ "syscall 0x0\n"
+ "1:\n"
+ : "=r" (__res_a0)
+ : "r"(fn), "r"(__stack), "r"(__flags), "r"(arg),
+ "r"(__ptid), "r"(__tls), "r"(__ctid),
+ "i"(__NR_clone), "i"(__NR_exit)
+ : LSS_SYSCALL_CLOBBERS);
+ __res = __res_a0;
+ }
+ LSS_RETURN(int, __res);
+ }
+
#endif
#define __NR__exit __NR_exit
#define __NR__gettid __NR_gettid
@@ -3385,8 +4092,10 @@ struct kernel_statfs {
// fork is polyfilled below when not available.
LSS_INLINE _syscall0(pid_t, fork)
#endif
+ #if defined(__NR_fstat)
LSS_INLINE _syscall2(int, fstat, int, f,
struct kernel_stat*, b)
+ #endif
LSS_INLINE _syscall2(int, fstatfs, int, f,
struct kernel_statfs*, b)
#if defined(__x86_64__)
@@ -3408,6 +4117,8 @@ struct kernel_statfs {
struct kernel_dirent64*, d, int, c)
LSS_INLINE _syscall0(gid_t, getegid)
LSS_INLINE _syscall0(uid_t, geteuid)
+ LSS_INLINE _syscall2(int, getitimer, int, w,
+ struct kernel_itimerval*, c)
#if defined(__NR_getpgrp)
LSS_INLINE _syscall0(pid_t, getpgrp)
#endif
@@ -3419,10 +4130,10 @@ struct kernel_statfs {
gid_t *, e, gid_t *, s)
LSS_INLINE _syscall3(int, getresuid, uid_t *, r,
uid_t *, e, uid_t *, s)
-#if !defined(__ARM_EABI__)
+ #if defined(__NR_getrlimit)
LSS_INLINE _syscall2(int, getrlimit, int, r,
struct kernel_rlimit*, l)
-#endif
+ #endif
LSS_INLINE _syscall1(pid_t, getsid, pid_t, p)
LSS_INLINE _syscall0(pid_t, _gettid)
LSS_INLINE _syscall2(pid_t, gettimeofday, struct kernel_timeval*, t,
@@ -3529,6 +4240,9 @@ struct kernel_statfs {
LSS_INLINE _syscall1(int, setfsuid, uid_t, u)
LSS_INLINE _syscall1(int, setuid, uid_t, u)
LSS_INLINE _syscall1(int, setgid, gid_t, g)
+ LSS_INLINE _syscall3(int, setitimer, int, w,
+ const struct kernel_itimerval*, n,
+ struct kernel_itimerval*, o)
LSS_INLINE _syscall2(int, setpgid, pid_t, p,
pid_t, g)
LSS_INLINE _syscall3(int, setpriority, int, a,
@@ -3537,8 +4251,10 @@ struct kernel_statfs {
gid_t, e, gid_t, s)
LSS_INLINE _syscall3(int, setresuid, uid_t, r,
uid_t, e, uid_t, s)
+ #if defined(__NR_setrlimit)
LSS_INLINE _syscall2(int, setrlimit, int, r,
const struct kernel_rlimit*, l)
+ #endif
LSS_INLINE _syscall0(pid_t, setsid)
LSS_INLINE _syscall2(int, sigaltstack, const stack_t*, s,
const stack_t*, o)
@@ -3546,10 +4262,14 @@ struct kernel_statfs {
LSS_INLINE _syscall1(int, sigreturn, unsigned long, u)
#endif
#if defined(__NR_stat)
- // stat is polyfilled below when not available.
+ // stat and lstat are polyfilled below when not available.
LSS_INLINE _syscall2(int, stat, const char*, f,
struct kernel_stat*, b)
#endif
+ #if defined(__NR_lstat)
+ LSS_INLINE _syscall2(int, lstat, const char*, f,
+ struct kernel_stat*, b)
+ #endif
LSS_INLINE _syscall2(int, statfs, const char*, f,
struct kernel_statfs*, b)
LSS_INLINE _syscall3(int, tgkill, pid_t, p,
@@ -3568,23 +4288,6 @@ struct kernel_statfs {
LSS_INLINE _syscall3(long, getcpu, unsigned *, cpu,
unsigned *, node, void *, unused)
#endif
- #if defined(__x86_64__) || \
- (defined(__mips__) && _MIPS_SIM != _MIPS_SIM_ABI32)
- LSS_INLINE _syscall3(int, recvmsg, int, s,
- struct kernel_msghdr*, m, int, f)
- LSS_INLINE _syscall3(int, sendmsg, int, s,
- const struct kernel_msghdr*, m, int, f)
- LSS_INLINE _syscall6(int, sendto, int, s,
- const void*, m, size_t, l,
- int, f,
- const struct kernel_sockaddr*, a, int, t)
- LSS_INLINE _syscall2(int, shutdown, int, s,
- int, h)
- LSS_INLINE _syscall3(int, socket, int, d,
- int, t, int, p)
- LSS_INLINE _syscall4(int, socketpair, int, d,
- int, t, int, p, int*, s)
- #endif
#if defined(__NR_fadvise64)
#if defined(__x86_64__)
/* Need to make sure loff_t isn't truncated to 32-bits under x32. */
@@ -3658,11 +4361,21 @@ struct kernel_statfs {
int, f, int, mode, loff_t, offset, loff_t, len)
#endif
#endif
+ #if defined(__NR_getrandom)
+ LSS_INLINE _syscall3(ssize_t, getrandom, void*, buffer, size_t, length,
+ unsigned int, flags)
+ #endif
#if defined(__NR_newfstatat)
LSS_INLINE _syscall4(int, newfstatat, int, d,
const char *, p,
struct kernel_stat*, b, int, f)
#endif
+ #if defined(__NR_statx)
+ LSS_INLINE _syscall5(int, statx, int, d,
+ const char *, p,
+ int, f, int, m,
+ struct kernel_statx*, b)
+ #endif
#if defined(__x86_64__) || defined(__s390x__)
LSS_INLINE int LSS_NAME(getresgid32)(gid_t *rgid,
gid_t *egid,
@@ -3869,43 +4582,43 @@ struct kernel_statfs {
LSS_INLINE int LSS_NAME(sigaddset)(struct kernel_sigset_t *set,
int signum) {
- if (signum < 1 || signum > (int)(8*sizeof(set->sig))) {
+ if (signum < 1 || (size_t)signum > (8*sizeof(set->sig))) {
LSS_ERRNO = EINVAL;
return -1;
} else {
- set->sig[(signum - 1)/(8*sizeof(set->sig[0]))]
- |= 1UL << ((signum - 1) % (8*sizeof(set->sig[0])));
+ set->sig[(size_t)(signum - 1)/(8*sizeof(set->sig[0]))]
+ |= 1UL << ((size_t)(signum - 1) % (8*sizeof(set->sig[0])));
return 0;
}
}
LSS_INLINE int LSS_NAME(sigdelset)(struct kernel_sigset_t *set,
int signum) {
- if (signum < 1 || signum > (int)(8*sizeof(set->sig))) {
+ if (signum < 1 || (size_t)signum > (8*sizeof(set->sig))) {
LSS_ERRNO = EINVAL;
return -1;
} else {
- set->sig[(signum - 1)/(8*sizeof(set->sig[0]))]
- &= ~(1UL << ((signum - 1) % (8*sizeof(set->sig[0]))));
+ set->sig[(size_t)(signum - 1)/(8*sizeof(set->sig[0]))]
+ &= ~(1UL << ((size_t)(signum - 1) % (8*sizeof(set->sig[0]))));
return 0;
}
}
LSS_INLINE int LSS_NAME(sigismember)(struct kernel_sigset_t *set,
int signum) {
- if (signum < 1 || signum > (int)(8*sizeof(set->sig))) {
+ if (signum < 1 || (size_t)signum > (8*sizeof(set->sig))) {
LSS_ERRNO = EINVAL;
return -1;
} else {
- return !!(set->sig[(signum - 1)/(8*sizeof(set->sig[0]))] &
- (1UL << ((signum - 1) % (8*sizeof(set->sig[0])))));
+ return !!(set->sig[(size_t)(signum - 1)/(8*sizeof(set->sig[0]))] &
+ (1UL << ((size_t)(signum - 1) % (8*sizeof(set->sig[0])))));
}
}
#if defined(__i386__) || \
defined(__ARM_ARCH_3__) || defined(__ARM_EABI__) || \
(defined(__mips__) && _MIPS_SIM == _MIPS_SIM_ABI32) || \
defined(__PPC__) || \
- (defined(__s390__) && !defined(__s390x__))
+ (defined(__s390__) && !defined(__s390x__)) || defined(__e2k__)
#define __NR__sigaction __NR_sigaction
#define __NR__sigpending __NR_sigpending
#define __NR__sigsuspend __NR_sigsuspend
@@ -4159,23 +4872,31 @@ struct kernel_statfs {
LSS_SC_BODY(4, int, 8, d, type, protocol, sv);
}
#endif
- #if defined(__ARM_EABI__) || defined (__aarch64__)
+ #if defined(__NR_recvmsg)
LSS_INLINE _syscall3(ssize_t, recvmsg, int, s, struct kernel_msghdr*, msg,
int, flags)
+ #endif
+ #if defined(__NR_sendmsg)
LSS_INLINE _syscall3(ssize_t, sendmsg, int, s, const struct kernel_msghdr*,
msg, int, flags)
+ #endif
+ #if defined(__NR_sendto)
LSS_INLINE _syscall6(ssize_t, sendto, int, s, const void*, buf, size_t,len,
int, flags, const struct kernel_sockaddr*, to,
unsigned int, tolen)
+ #endif
+ #if defined(__NR_shutdown)
LSS_INLINE _syscall2(int, shutdown, int, s, int, how)
+ #endif
+ #if defined(__NR_socket)
LSS_INLINE _syscall3(int, socket, int, domain, int, type, int, protocol)
+ #endif
+ #if defined(__NR_socketpair)
LSS_INLINE _syscall4(int, socketpair, int, d, int, type, int, protocol,
int*, sv)
#endif
- #if defined(__i386__) || defined(__ARM_ARCH_3__) || \
- (defined(__mips__) && _MIPS_SIM == _MIPS_SIM_ABI32) || \
- defined(__s390__)
- #define __NR__socketcall __NR_socketcall
+
+ #if defined(__NR_socketcall)
LSS_INLINE _syscall2(int, _socketcall, int, c,
va_list, a)
LSS_INLINE int LSS_NAME(socketcall)(int op, ...) {
@@ -4187,36 +4908,43 @@ struct kernel_statfs {
return rc;
}
+ # if !defined(__NR_recvmsg)
LSS_INLINE ssize_t LSS_NAME(recvmsg)(int s,struct kernel_msghdr *msg,
int flags){
return (ssize_t)LSS_NAME(socketcall)(17, s, msg, flags);
}
-
+ # endif
+ # if !defined(__NR_sendmsg)
LSS_INLINE ssize_t LSS_NAME(sendmsg)(int s,
const struct kernel_msghdr *msg,
int flags) {
return (ssize_t)LSS_NAME(socketcall)(16, s, msg, flags);
}
-
+ # endif
+ # if !defined(__NR_sendto)
LSS_INLINE ssize_t LSS_NAME(sendto)(int s, const void *buf, size_t len,
int flags,
const struct kernel_sockaddr *to,
unsigned int tolen) {
return (ssize_t)LSS_NAME(socketcall)(11, s, buf, len, flags, to, tolen);
}
-
+ # endif
+ # if !defined(__NR_shutdown)
LSS_INLINE int LSS_NAME(shutdown)(int s, int how) {
return LSS_NAME(socketcall)(13, s, how);
}
-
+ # endif
+ # if !defined(__NR_socket)
LSS_INLINE int LSS_NAME(socket)(int domain, int type, int protocol) {
return LSS_NAME(socketcall)(1, domain, type, protocol);
}
-
+ # endif
+ # if !defined(__NR_socketpair)
LSS_INLINE int LSS_NAME(socketpair)(int d, int type, int protocol,
int sv[2]) {
return LSS_NAME(socketcall)(8, d, type, protocol, sv);
}
+ # endif
#endif
#if defined(__NR_fstatat64)
LSS_INLINE _syscall4(int, fstatat64, int, d,
@@ -4298,12 +5026,12 @@ struct kernel_statfs {
va_start(ap, flags);
new_address = va_arg(ap, void *);
rc = LSS_NAME(_mremap)(old_address, old_size, new_size,
- flags, new_address);
+ (unsigned long)flags, new_address);
va_end(ap);
return rc;
}
- LSS_INLINE int LSS_NAME(ptrace_detach)(pid_t pid) {
+ LSS_INLINE long LSS_NAME(ptrace_detach)(pid_t pid) {
/* PTRACE_DETACH can sometimes forget to wake up the tracee and it
* then sends job control signals to the real parent, rather than to
* the tracer. We reduce the risk of this happening by starting a
@@ -4314,7 +5042,8 @@ struct kernel_statfs {
* detached. Large multi threaded apps can take a long time in the kernel
* processing SIGCONT.
*/
- int rc, err;
+ long rc;
+ int err;
LSS_NAME(sched_yield)();
rc = LSS_NAME(ptrace)(PTRACE_DETACH, pid, (void *)0, (void *)0);
err = LSS_ERRNO;
@@ -4347,7 +5076,7 @@ struct kernel_statfs {
LSS_SYSCALL_ARG(c), (uint64_t)(o));
}
- LSS_INLINE int LSS_NAME(readahead)(int f, loff_t o, unsigned c) {
+ LSS_INLINE int LSS_NAME(readahead)(int f, loff_t o, size_t c) {
LSS_BODY(3, int, readahead, LSS_SYSCALL_ARG(f), (uint64_t)(o),
LSS_SYSCALL_ARG(c));
}
@@ -4386,7 +5115,7 @@ struct kernel_statfs {
unsigned, o2)
LSS_INLINE _syscall5(ssize_t, _pwrite64, int, f,
const void *, b, size_t, c, unsigned, o1,
- long, o2)
+ unsigned, o2)
LSS_INLINE _syscall4(int, _readahead, int, f,
unsigned, o1, unsigned, o2, size_t, c)
#endif
@@ -4407,9 +5136,9 @@ struct kernel_statfs {
return LSS_NAME(_pwrite64)(fd, buf, count,
LSS_LLARG_PAD o.arg[0], o.arg[1]);
}
- LSS_INLINE int LSS_NAME(readahead)(int fd, loff_t off, int len) {
+ LSS_INLINE int LSS_NAME(readahead)(int fd, loff_t off, size_t count) {
union { loff_t off; unsigned arg[2]; } o = { off };
- return LSS_NAME(_readahead)(fd, LSS_LLARG_PAD o.arg[0], o.arg[1], len);
+ return LSS_NAME(_readahead)(fd, LSS_LLARG_PAD o.arg[0], o.arg[1], count);
}
#endif
#endif
@@ -4464,10 +5193,79 @@ struct kernel_statfs {
}
#endif
+#if defined(__NR_statx)
+ /* copy the contents of kernel_statx to the kernel_stat structure. */
+ LSS_INLINE void LSS_NAME(cp_stat_statx)(struct kernel_stat *to,
+ struct kernel_statx *from) {
+ memset(to, 0, sizeof(struct kernel_stat));
+ to->st_dev = (kernel_dev_t)((from->stx_dev_minor & 0xff) |
+ ((from->stx_dev_major & 0xfff) << 8) |
+ ((from->stx_dev_minor & ~0xffu) << 12));
+ to->st_rdev = (kernel_dev_t)((from->stx_rdev_minor & 0xff) |
+ ((from->stx_rdev_major & 0xfff) << 8) |
+ ((from->stx_rdev_minor & ~0xffu) << 12));
+ to->st_ino = (kernel_ino_t)from->stx_ino;
+ to->st_mode = (kernel_mode_t)from->stx_mode;
+ to->st_nlink = (kernel_nlink_t)from->stx_nlink;
+ to->st_uid = (kernel_uid_t)from->stx_uid;
+ to->st_gid = (kernel_gid_t)from->stx_gid;
+ to->st_atime_ = (kernel_time_t)(from->stx_atime.tv_sec);
+ to->st_atime_nsec_ = from->stx_atime.tv_nsec;
+ to->st_mtime_ = (kernel_time_t)(from->stx_mtime.tv_sec);
+ to->st_mtime_nsec_ = from->stx_mtime.tv_nsec;
+ to->st_ctime_ = (kernel_time_t)(from->stx_ctime.tv_sec);
+ to->st_ctime_nsec_ = from->stx_ctime.tv_nsec;
+ to->st_size = (kernel_off_t)(from->stx_size);
+ to->st_blocks = (kernel_blkcnt_t)(from->stx_blocks);
+ to->st_blksize = (kernel_blksize_t)from->stx_blksize;
+ }
+#endif
+
+#if !defined(__NR_fstat)
+ LSS_INLINE int LSS_NAME(fstat)(int fd,
+ struct kernel_stat *buf) {
+ #if defined(__NR_newfstatat)
+ return LSS_NAME(newfstatat)(fd, "", buf, AT_EMPTY_PATH);
+ #elif defined(__NR_statx)
+ struct kernel_statx stx;
+ int flags = AT_NO_AUTOMOUNT | AT_EMPTY_PATH;
+ int mask = STATX_BASIC_STATS;
+ int res = LSS_NAME(statx)(fd, "", flags, mask, &stx);
+ LSS_NAME(cp_stat_statx)(buf, &stx);
+ return res;
+ #endif
+ }
+#endif
+
#if !defined(__NR_stat)
LSS_INLINE int LSS_NAME(stat)(const char *pathname,
struct kernel_stat *buf) {
- return LSS_NAME(newfstatat)(AT_FDCWD, pathname, buf, 0);
+ #if defined(__NR_newfstatat)
+ return LSS_NAME(newfstatat)(AT_FDCWD, pathname, buf, 0);
+ #elif defined(__NR_statx)
+ struct kernel_statx stx;
+ int flags = AT_NO_AUTOMOUNT | AT_STATX_SYNC_AS_STAT;
+ int mask = STATX_BASIC_STATS;
+ int res = LSS_NAME(statx)(AT_FDCWD, pathname, flags, mask, &stx);
+ LSS_NAME(cp_stat_statx)(buf, &stx);
+ return res;
+ #endif
+ }
+#endif
+
+#if !defined(__NR_lstat)
+ LSS_INLINE int LSS_NAME(lstat)(const char *pathname,
+ struct kernel_stat *buf) {
+ #if defined(__NR_newfstatat)
+ return LSS_NAME(newfstatat)(AT_FDCWD, pathname, buf, AT_SYMLINK_NOFOLLOW);
+ #elif defined(__NR_statx)
+ struct kernel_statx stx;
+ int flags = AT_NO_AUTOMOUNT | AT_SYMLINK_NOFOLLOW;
+ int mask = STATX_BASIC_STATS;
+ int res = LSS_NAME(statx)(AT_FDCWD, pathname, flags, mask, &stx);
+ LSS_NAME(cp_stat_statx)(buf, &stx);
+ return res;
+ #endif
}
#endif
@@ -4481,7 +5279,7 @@ struct kernel_statfs {
// TODO: define this in an arch-independant way instead of inlining the clone
// syscall body.
-# if defined(__aarch64__)
+# if defined(__aarch64__) || defined(__riscv) || defined(__loongarch_lp64)
LSS_INLINE pid_t LSS_NAME(fork)(void) {
// No fork syscall on aarch64 - implement by means of the clone syscall.
// Note that this does not reset glibc's cached view of the PID/TID, so
diff --git a/src/tools/linux/core2md/core2md.cc b/src/tools/linux/core2md/core2md.cc
index c3a9da39..3f34294f 100644
--- a/src/tools/linux/core2md/core2md.cc
+++ b/src/tools/linux/core2md/core2md.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2012, Google Inc.
-// All rights reserved.
+// Copyright 2012 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -33,13 +32,15 @@
#include "client/linux/minidump_writer/minidump_writer.h"
#include "client/linux/minidump_writer/linux_core_dumper.h"
+#include "common/path_helper.h"
using google_breakpad::AppMemoryList;
using google_breakpad::MappingList;
using google_breakpad::LinuxCoreDumper;
static int ShowUsage(const char* argv0) {
- fprintf(stderr, "Usage: %s <core file> <procfs dir> <output>\n", argv0);
+ fprintf(stderr, "Usage: %s <core file> <procfs dir> <output>\n",
+ google_breakpad::BaseName(argv0).c_str());
return 1;
}
diff --git a/src/tools/linux/core_handler/core_handler.cc b/src/tools/linux/core_handler/core_handler.cc
new file mode 100644
index 00000000..224073d3
--- /dev/null
+++ b/src/tools/linux/core_handler/core_handler.cc
@@ -0,0 +1,147 @@
+// Copyright 2020 Google LLC
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google LLC nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// core_handler.cc: A tool to handle coredumps on Linux
+
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <syslog.h>
+#include <unistd.h>
+#include <sstream>
+
+#include "client/linux/minidump_writer/linux_core_dumper.h"
+#include "client/linux/minidump_writer/minidump_writer.h"
+#include "common/path_helper.h"
+#include "common/scoped_ptr.h"
+
+namespace {
+
+using google_breakpad::AppMemoryList;
+using google_breakpad::LinuxCoreDumper;
+using google_breakpad::MappingList;
+using google_breakpad::scoped_array;
+
+// Size of the core dump to read in order to access all the threads
+// descriptions.
+//
+// The first section is the note0 section which contains the thread states. On
+// x86-64 a typical thread description take about 1432B. Reading 1 MB allows
+// several hundreds of threads.
+const int core_read_size = 1024 * 1024;
+
+void ShowUsage(const char* argv0) {
+ fprintf(stderr, "Usage: %s <process id> <minidump file>\n\n",
+ google_breakpad::BaseName(argv0).c_str());
+ fprintf(stderr,
+ "A tool which serves as a core dump handler and produces "
+ "minidump files.\n");
+ fprintf(stderr, "Please refer to the online documentation:\n");
+ fprintf(stderr,
+ "https://chromium.googlesource.com/breakpad/breakpad/+/HEAD"
+ "/docs/linux_core_handler.md\n");
+}
+
+bool WriteMinidumpFromCore(const char* filename,
+ const char* core_path,
+ const char* procfs_override) {
+ MappingList mappings;
+ AppMemoryList memory_list;
+ LinuxCoreDumper dumper(0, core_path, procfs_override);
+ return google_breakpad::WriteMinidump(filename, mappings, memory_list,
+ &dumper);
+}
+
+bool HandleCrash(pid_t pid, const char* procfs_dir, const char* md_filename) {
+ int r = 0;
+ scoped_array<char> buf(new char[core_read_size]);
+ while (r != core_read_size) {
+ int ret = read(STDIN_FILENO, &buf[r], core_read_size - r);
+ if (ret == 0) {
+ break;
+ } else if (ret == -1) {
+ return false;
+ }
+ r += ret;
+ }
+
+ int fd = memfd_create("core_file", MFD_CLOEXEC);
+ if (fd == -1) {
+ return false;
+ }
+
+ int w = write(fd, &buf[0], r);
+ if (w != r) {
+ close(fd);
+ return false;
+ }
+
+ std::stringstream core_file_ss;
+ core_file_ss << "/proc/self/fd/" << fd;
+ std::string core_file(core_file_ss.str());
+
+ if (!WriteMinidumpFromCore(md_filename, core_file.c_str(), procfs_dir)) {
+ close(fd);
+ return false;
+ }
+ close(fd);
+
+ return true;
+}
+
+} // namespace
+
+int main(int argc, char* argv[]) {
+ int ret = EXIT_FAILURE;
+
+ if (argc != 3) {
+ ShowUsage(argv[0]);
+ return ret;
+ }
+
+ const char* pid_str = argv[1];
+ const char* md_filename = argv[2];
+ pid_t pid = atoi(pid_str);
+
+ std::stringstream proc_dir_ss;
+ proc_dir_ss << "/proc/" << pid_str;
+ std::string proc_dir(proc_dir_ss.str());
+
+ openlog("core_handler", 0, 0);
+ if (HandleCrash(pid, proc_dir.c_str(), md_filename)) {
+ syslog(LOG_NOTICE, "Minidump generated at %s\n", md_filename);
+ ret = EXIT_SUCCESS;
+ } else {
+ syslog(LOG_ERR, "Cannot generate minidump %s\n", md_filename);
+ }
+ closelog();
+
+ return ret;
+}
diff --git a/src/tools/linux/dump_syms/dump_syms.cc b/src/tools/linux/dump_syms/dump_syms.cc
index ebdf2314..8998b3b3 100644
--- a/src/tools/linux/dump_syms/dump_syms.cc
+++ b/src/tools/linux/dump_syms/dump_syms.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2011, Google Inc.
-// All rights reserved.
+// Copyright 2011 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -37,32 +36,41 @@
#include <vector>
#include "common/linux/dump_symbols.h"
+#include "common/path_helper.h"
using google_breakpad::WriteSymbolFile;
using google_breakpad::WriteSymbolFileHeader;
int usage(const char* self) {
- fprintf(stderr, "Usage: %s [OPTION] <binary-with-debugging-info> "
- "[directories-for-debug-file]\n\n", self);
+ fprintf(stderr,
+ "Usage: %s [OPTION] <binary-with-debugging-info> "
+ "[directories-for-debug-file]\n\n",
+ google_breakpad::BaseName(self).c_str());
fprintf(stderr, "Options:\n");
fprintf(stderr, " -i: Output module header information only.\n");
fprintf(stderr, " -c Do not generate CFI section\n");
+ fprintf(stderr, " -d Generate INLINE/INLINE_ORIGIN records\n");
fprintf(stderr, " -r Do not handle inter-compilation "
"unit references\n");
fprintf(stderr, " -v Print all warnings to stderr\n");
fprintf(stderr, " -n <name> Use specified name for name of the object\n");
fprintf(stderr, " -o <os> Use specified name for the "
"operating system\n");
+ fprintf(stderr, " -m Enable writing the optional 'm' field on FUNC"
+ "and PUBLIC, denoting multiple symbols for "
+ "the address.\n");
return 1;
}
-int main(int argc, char **argv) {
+int main(int argc, char** argv) {
if (argc < 2)
return usage(argv[0]);
bool header_only = false;
bool cfi = true;
+ bool handle_inlines = false;
bool handle_inter_cu_refs = true;
bool log_to_stderr = false;
+ bool enable_multiple_field = false;
std::string obj_name;
const char* obj_os = "Linux";
int arg_index = 1;
@@ -72,6 +80,8 @@ int main(int argc, char **argv) {
header_only = true;
} else if (strcmp("-c", argv[arg_index]) == 0) {
cfi = false;
+ } else if (strcmp("-d", argv[arg_index]) == 0) {
+ handle_inlines = true;
} else if (strcmp("-r", argv[arg_index]) == 0) {
handle_inter_cu_refs = false;
} else if (strcmp("-v", argv[arg_index]) == 0) {
@@ -90,6 +100,8 @@ int main(int argc, char **argv) {
}
obj_os = argv[arg_index + 1];
++arg_index;
+ } else if (strcmp("-m", argv[arg_index]) == 0) {
+ enable_multiple_field = true;
} else {
printf("2.4 %s\n", argv[arg_index]);
return usage(argv[0]);
@@ -124,8 +136,10 @@ int main(int argc, char **argv) {
return 1;
}
} else {
- SymbolData symbol_data = cfi ? ALL_SYMBOL_DATA : NO_CFI;
- google_breakpad::DumpOptions options(symbol_data, handle_inter_cu_refs);
+ SymbolData symbol_data = (handle_inlines ? INLINES : NO_DATA) |
+ (cfi ? CFI : NO_DATA) | SYMBOLS_AND_FILES;
+ google_breakpad::DumpOptions options(symbol_data, handle_inter_cu_refs,
+ enable_multiple_field);
if (!WriteSymbolFile(binary, obj_name, obj_os, debug_dirs, options,
std::cout)) {
fprintf(saved_stderr, "Failed to write symbol file.\n");
diff --git a/src/tools/linux/md2core/minidump-2-core.cc b/src/tools/linux/md2core/minidump-2-core.cc
index a60be323..a4ddbe8e 100644
--- a/src/tools/linux/md2core/minidump-2-core.cc
+++ b/src/tools/linux/md2core/minidump-2-core.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2009, Google Inc.
-// All rights reserved.
+// Copyright 2009 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -77,6 +76,8 @@
#define ELF_ARCH EM_MIPS
#elif defined(__aarch64__)
#define ELF_ARCH EM_AARCH64
+#elif defined(__riscv)
+ #define ELF_ARCH EM_RISCV
#endif
#if defined(__arm__)
@@ -84,7 +85,7 @@
// containing core registers, while they use 'user_regs_struct' on other
// architectures. This file-local typedef simplifies the source code.
typedef user_regs user_regs_struct;
-#elif defined (__mips__)
+#elif defined (__mips__) || defined(__riscv)
// This file-local typedef simplifies the source code.
typedef gregset_t user_regs_struct;
#endif
@@ -149,16 +150,14 @@ SetupOptions(int argc, const char* argv[], Options* options) {
options->use_filename = false;
options->inc_guid = false;
- while ((ch = getopt(argc, (char * const *)argv, "fhio:S:v")) != -1) {
+ while ((ch = getopt(argc, (char * const*)argv, "fhio:S:v")) != -1) {
switch (ch) {
case 'h':
Usage(argc, argv);
exit(0);
- break;
case '?':
Usage(argc, argv);
exit(1);
- break;
case 'f':
options->use_filename = true;
@@ -224,7 +223,7 @@ writea(int fd, const void* idata, size_t length) {
*/
static inline int sex() {
int probe = 1;
- return !*(char *)&probe;
+ return !*(char*)&probe;
}
typedef struct elf_timeval { /* Time value with microsecond resolution */
@@ -261,7 +260,7 @@ typedef struct prpsinfo { /* Information about process */
unsigned char pr_zomb; /* Zombie */
signed char pr_nice; /* Nice val */
unsigned long pr_flag; /* Flags */
-#if defined(__x86_64__) || defined(__mips__)
+#if defined(__x86_64__) || defined(__mips__) || defined(__riscv)
uint32_t pr_uid; /* User ID */
uint32_t pr_gid; /* Group ID */
#else
@@ -308,7 +307,7 @@ struct CrashedProcess {
struct Thread {
pid_t tid;
-#if defined(__mips__)
+#if defined(__mips__) || defined(__riscv)
mcontext_t mcontext;
#else
user_regs_struct regs;
@@ -535,6 +534,71 @@ ParseThreadRegisters(CrashedProcess::Thread* thread,
thread->mcontext.fpc_eir = rawregs->float_save.fir;
#endif
}
+#elif defined(__riscv)
+static void
+ParseThreadRegisters(CrashedProcess::Thread* thread,
+ const MinidumpMemoryRange& range) {
+# if __riscv_xlen == 32
+ const MDRawContextRISCV* rawregs = range.GetData<MDRawContextRISCV>(0);
+# elif __riscv_xlen == 64
+ const MDRawContextRISCV64* rawregs = range.GetData<MDRawContextRISCV64>(0);
+# else
+# error "Unexpected __riscv_xlen"
+# endif
+
+ thread->mcontext.__gregs[0] = rawregs->pc;
+ thread->mcontext.__gregs[1] = rawregs->ra;
+ thread->mcontext.__gregs[2] = rawregs->sp;
+ thread->mcontext.__gregs[3] = rawregs->gp;
+ thread->mcontext.__gregs[4] = rawregs->tp;
+ thread->mcontext.__gregs[5] = rawregs->t0;
+ thread->mcontext.__gregs[6] = rawregs->t1;
+ thread->mcontext.__gregs[7] = rawregs->t2;
+ thread->mcontext.__gregs[8] = rawregs->s0;
+ thread->mcontext.__gregs[9] = rawregs->s1;
+ thread->mcontext.__gregs[10] = rawregs->a0;
+ thread->mcontext.__gregs[11] = rawregs->a1;
+ thread->mcontext.__gregs[12] = rawregs->a2;
+ thread->mcontext.__gregs[13] = rawregs->a3;
+ thread->mcontext.__gregs[14] = rawregs->a4;
+ thread->mcontext.__gregs[15] = rawregs->a5;
+ thread->mcontext.__gregs[16] = rawregs->a6;
+ thread->mcontext.__gregs[17] = rawregs->a7;
+ thread->mcontext.__gregs[18] = rawregs->s2;
+ thread->mcontext.__gregs[19] = rawregs->s3;
+ thread->mcontext.__gregs[20] = rawregs->s4;
+ thread->mcontext.__gregs[21] = rawregs->s5;
+ thread->mcontext.__gregs[22] = rawregs->s6;
+ thread->mcontext.__gregs[23] = rawregs->s7;
+ thread->mcontext.__gregs[24] = rawregs->s8;
+ thread->mcontext.__gregs[25] = rawregs->s9;
+ thread->mcontext.__gregs[26] = rawregs->s10;
+ thread->mcontext.__gregs[27] = rawregs->s11;
+ thread->mcontext.__gregs[28] = rawregs->t3;
+ thread->mcontext.__gregs[29] = rawregs->t4;
+ thread->mcontext.__gregs[30] = rawregs->t5;
+ thread->mcontext.__gregs[31] = rawregs->t6;
+
+# if __riscv_flen == 32
+ for (int i = 0; i < MD_FLOATINGSAVEAREA_RISCV_FPR_COUNT; ++i) {
+ thread->mcontext.__fpregs.__f.__f[i] = rawregs->float_save.regs[i];
+ }
+ thread->mcontext.__fpregs.__f.__fcsr = rawregs->float_save.fpcsr;
+# elif __riscv_flen == 64
+ for (int i = 0; i < MD_FLOATINGSAVEAREA_RISCV_FPR_COUNT; ++i) {
+ thread->mcontext.__fpregs.__d.__f[i] = rawregs->float_save.regs[i];
+ }
+ thread->mcontext.__fpregs.__d.__fcsr = rawregs->float_save.fpcsr;
+# elif __riscv_flen == 128
+ for (int i = 0; i < MD_FLOATINGSAVEAREA_RISCV_FPR_COUNT; ++i) {
+ thread->mcontext.__fpregs.__q.__f[2*i] = rawregs->float_save.regs[i].high;
+ thread->mcontext.__fpregs.__q.__f[2*i+1] = rawregs->float_save.regs[i].low;
+ }
+ thread->mcontext.__fpregs.__q.__fcsr = rawregs->float_save.fpcsr;
+# else
+# error "Unexpected __riscv_flen"
+# endif
+}
#else
#error "This code has not been ported to your platform yet"
#endif
@@ -602,7 +666,8 @@ ParseSystemInfo(const Options& options, CrashedProcess* crashinfo,
exit(1);
}
#elif defined(__aarch64__)
- if (sysinfo->processor_architecture != MD_CPU_ARCHITECTURE_ARM64_OLD) {
+ if (sysinfo->processor_architecture != MD_CPU_ARCHITECTURE_ARM64_OLD &&
+ sysinfo->processor_architecture != MD_CPU_ARCHITECTURE_ARM64) {
fprintf(stderr,
"This version of minidump-2-core only supports ARM (64bit).\n");
exit(1);
@@ -623,11 +688,26 @@ ParseSystemInfo(const Options& options, CrashedProcess* crashinfo,
# else
# error "This mips ABI is currently not supported (n32)"
# endif
+#elif defined(__riscv)
+# if __riscv_xlen == 32
+ if (sysinfo->processor_architecture != MD_CPU_ARCHITECTURE_RISCV) {
+ fprintf(stderr,
+ "This version of minidump-2-core only supports RISCV.\n");
+ exit(1);
+ }
+# elif __riscv_xlen == 64
+ if (sysinfo->processor_architecture != MD_CPU_ARCHITECTURE_RISCV64) {
+ fprintf(stderr,
+ "This version of minidump-2-core only supports RISCV64.\n");
+ exit(1);
+ }
+# else
+# error "Unexpected __riscv_xlen"
+# endif
#else
#error "This code has not been ported to your platform yet"
#endif
- if (!strstr(full_file.GetAsciiMDString(sysinfo->csd_version_rva).c_str(),
- "Linux") &&
+ if (sysinfo->platform_id != MD_OS_LINUX &&
sysinfo->platform_id != MD_OS_NACL) {
fprintf(stderr, "This minidump was not generated by Linux or NaCl.\n");
exit(1);
@@ -651,6 +731,10 @@ ParseSystemInfo(const Options& options, CrashedProcess* crashinfo,
? "MIPS"
: sysinfo->processor_architecture == MD_CPU_ARCHITECTURE_MIPS64
? "MIPS64"
+ : sysinfo->processor_architecture == MD_CPU_ARCHITECTURE_RISCV
+ ? "RISCV"
+ : sysinfo->processor_architecture == MD_CPU_ARCHITECTURE_RISCV64
+ ? "RISCV64"
: "???",
sysinfo->number_of_processors,
sysinfo->processor_level,
@@ -660,10 +744,10 @@ ParseSystemInfo(const Options& options, CrashedProcess* crashinfo,
sysinfo->processor_architecture == MD_CPU_ARCHITECTURE_AMD64) {
fputs("Vendor id: ", stderr);
const char *nul =
- (const char *)memchr(sysinfo->cpu.x86_cpu_info.vendor_id, 0,
+ (const char*)memchr(sysinfo->cpu.x86_cpu_info.vendor_id, 0,
sizeof(sysinfo->cpu.x86_cpu_info.vendor_id));
fwrite(sysinfo->cpu.x86_cpu_info.vendor_id,
- nul ? nul - (const char *)&sysinfo->cpu.x86_cpu_info.vendor_id[0]
+ nul ? nul - (const char*)&sysinfo->cpu.x86_cpu_info.vendor_id[0]
: sizeof(sysinfo->cpu.x86_cpu_info.vendor_id), 1, stderr);
fputs("\n", stderr);
}
@@ -759,7 +843,7 @@ ParseEnvironment(const Options& options, CrashedProcess* crashinfo,
memcpy(env, range.data(), range.length());
int nul_count = 0;
for (char *ptr = env;;) {
- ptr = (char *)memchr(ptr, '\000', range.length() - (ptr - env));
+ ptr = (char*)memchr(ptr, '\000', range.length() - (ptr - env));
if (!ptr) {
break;
}
@@ -928,6 +1012,8 @@ WriteThread(const Options& options, const CrashedProcess::Thread& thread,
pr.pr_pid = thread.tid;
#if defined(__mips__)
memcpy(&pr.pr_reg, &thread.mcontext.gregs, sizeof(user_regs_struct));
+#elif defined(__riscv)
+ memcpy(&pr.pr_reg, &thread.mcontext.__gregs, sizeof(user_regs_struct));
#else
memcpy(&pr.pr_reg, &thread.regs, sizeof(user_regs_struct));
#endif
@@ -1076,7 +1162,7 @@ AugmentMappings(const Options& options, CrashedProcess* crashinfo,
for (unsigned i = 0; i < crashinfo->threads.size(); ++i) {
const CrashedProcess::Thread& thread = crashinfo->threads[i];
AddDataToMapping(crashinfo,
- string((char *)thread.stack, thread.stack_length),
+ string((char*)thread.stack, thread.stack_length),
thread.stack_addr);
}
diff --git a/src/tools/linux/md2core/minidump_memory_range.h b/src/tools/linux/md2core/minidump_memory_range.h
index a793e2cf..6cf07470 100644
--- a/src/tools/linux/md2core/minidump_memory_range.h
+++ b/src/tools/linux/md2core/minidump_memory_range.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2011, Google Inc.
-// All rights reserved.
+// Copyright 2011 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/tools/linux/md2core/minidump_memory_range_unittest.cc b/src/tools/linux/md2core/minidump_memory_range_unittest.cc
index fe4ded83..9012101d 100644
--- a/src/tools/linux/md2core/minidump_memory_range_unittest.cc
+++ b/src/tools/linux/md2core/minidump_memory_range_unittest.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2011, Google Inc.
-// All rights reserved.
+// Copyright 2011 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/src/tools/linux/pid2md/pid2md.cc b/src/tools/linux/pid2md/pid2md.cc
new file mode 100644
index 00000000..ca1cb637
--- /dev/null
+++ b/src/tools/linux/pid2md/pid2md.cc
@@ -0,0 +1,58 @@
+// Copyright 2020 Google LLC
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google LLC nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// pid2md.cc: An utility to generate a minidump from a running process
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "client/linux/minidump_writer/minidump_writer.h"
+#include "common/path_helper.h"
+
+int main(int argc, char* argv[]) {
+ if (argc != 3) {
+ fprintf(stderr, "Usage: %s <process id> <minidump file>\n\n",
+ google_breakpad::BaseName(argv[0]).c_str());
+ fprintf(stderr,
+ "A tool to generate a minidump from a running process. The process "
+ "resumes its\nactivity once the operation is completed. Permission "
+ "to trace the process is\nrequired.\n");
+ return EXIT_FAILURE;
+ }
+
+ pid_t process_id = atoi(argv[1]);
+ const char* minidump_file = argv[2];
+
+ if (!google_breakpad::WriteMinidump(minidump_file, process_id, process_id)) {
+ fprintf(stderr, "Unable to generate minidump.\n");
+ return EXIT_FAILURE;
+ }
+
+ return EXIT_SUCCESS;
+}
diff --git a/src/tools/linux/symupload/minidump_upload.cc b/src/tools/linux/symupload/minidump_upload.cc
index 19f17450..6adead03 100644
--- a/src/tools/linux/symupload/minidump_upload.cc
+++ b/src/tools/linux/symupload/minidump_upload.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2006, Google Inc.
-// All rights reserved.
+// Copyright 2006 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -41,6 +40,7 @@
#include <string>
#include "common/linux/http_upload.h"
+#include "common/path_helper.h"
#include "common/using_std_string.h"
using google_breakpad::HTTPUpload;
@@ -91,8 +91,10 @@ static void Start(Options *options) {
static void
Usage(int argc, const char *argv[]) {
fprintf(stderr, "Submit minidump information.\n");
- fprintf(stderr, "Usage: %s [options...] -p <product> -v <version> <minidump> "
- "<upload-URL>\n", argv[0]);
+ fprintf(stderr,
+ "Usage: %s [options...] -p <product> -v <version> <minidump> "
+ "<upload-URL>\n",
+ google_breakpad::BaseName(argv[0]).c_str());
fprintf(stderr, "Options:\n");
fprintf(stderr, "<minidump> should be a minidump.\n");
fprintf(stderr, "<upload-URL> is the destination for the upload\n");
@@ -111,7 +113,7 @@ SetupOptions(int argc, const char *argv[], Options *options) {
extern int optind;
int ch;
- while ((ch = getopt(argc, (char * const *)argv, "p:u:v:x:h?")) != -1) {
+ while ((ch = getopt(argc, (char * const*)argv, "p:u:v:x:h?")) != -1) {
switch (ch) {
case 'p':
options->product = optarg;
diff --git a/src/tools/linux/symupload/sym_upload.cc b/src/tools/linux/symupload/sym_upload.cc
index f155eb95..8f5e8a50 100644
--- a/src/tools/linux/symupload/sym_upload.cc
+++ b/src/tools/linux/symupload/sym_upload.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2006, Google Inc.
-// All rights reserved.
+// Copyright 2006 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -47,6 +46,7 @@
#include <locale>
#include "common/linux/symbol_upload.h"
+#include "common/path_helper.h"
using google_breakpad::sym_upload::UploadProtocol;
using google_breakpad::sym_upload::Options;
@@ -66,10 +66,11 @@ static void
Usage(int argc, const char *argv[]) {
fprintf(stderr, "Submit symbol information.\n");
fprintf(stderr, "Usage: %s [options...] <symbol-file> <upload-URL>\n",
- argv[0]);
+ google_breakpad::BaseName(argv[0]).c_str());
fprintf(stderr, "Options:\n");
- fprintf(stderr, "<symbol-file> should be created by using the dump_syms"
- "tool.\n");
+ fprintf(stderr,
+ "<symbol-file> should be created by using the dump_syms "
+ "tool.\n");
fprintf(stderr, "<upload-URL> is the destination for the upload\n");
fprintf(stderr, "-p:\t <protocol> One of ['sym-upload-v1',"
" 'sym-upload-v2'], defaults to 'sym-upload-v1'.\n");
@@ -111,17 +112,20 @@ Usage(int argc, const char *argv[]) {
//=============================================================================
static void
SetupOptions(int argc, const char *argv[], Options *options) {
- extern int optind;
+ extern int optind, optopt;
int ch;
constexpr char flag_pattern[] = "u:v:x:p:k:t:c:i:hf?";
- while ((ch = getopt(argc, (char * const *)argv, flag_pattern)) != -1) {
+ while ((ch = getopt(argc, (char * const*)argv, flag_pattern)) != -1) {
switch (ch) {
case 'h':
case '?':
Usage(argc, argv);
- exit(0);
- break;
+ // ch might be '?' because getopt found an error while parsing args (as
+ // opposed to finding "-?" as an arg), in which case optopt is set to
+ // the bad arg value, so return an error code if optopt is set,
+ // otherwise exit cleanly.
+ exit(optopt == 0 ? 0 : 1);
case 'u':
options->proxy_user_pwd = optarg;
break;
@@ -166,7 +170,6 @@ SetupOptions(int argc, const char *argv[], Options *options) {
fprintf(stderr, "Invalid option '%c'\n", ch);
Usage(argc, argv);
exit(1);
- break;
}
}
diff --git a/src/tools/linux/tools_linux.gypi b/src/tools/linux/tools_linux.gypi
deleted file mode 100644
index 020e4c1c..00000000
--- a/src/tools/linux/tools_linux.gypi
+++ /dev/null
@@ -1,83 +0,0 @@
-# Copyright 2014 Google Inc. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-# * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-# * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-{
- 'target_defaults': {
- 'include_dirs': [
- '../..',
- ],
- },
- 'targets': [
- {
- 'target_name': 'dump_syms',
- 'type': 'executable',
- 'sources': [
- 'dump_syms/dump_syms.cc',
- ],
- 'dependencies': [
- '../common/common.gyp:common',
- ],
- },
- {
- 'target_name': 'md2core',
- 'type': 'executable',
- 'sources': [
- 'md2core/minidump-2-core.cc',
- 'md2core/minidump_memory_range.h',
- ],
- 'dependencies': [
- '../common/common.gyp:common',
- ],
- },
- {
- 'target_name': 'minidump_upload',
- 'type': 'executable',
- 'sources': [
- 'symupload/minidump_upload.cc',
- ],
- 'dependencies': [
- '../common/common.gyp:common',
- ],
- },
- {
- 'target_name': 'symupload',
- 'type': 'executable',
- 'sources': [
- 'symupload/sym_upload.cc',
- ],
- 'link_settings': {
- 'libraries': [
- '-ldl',
- ],
- },
- 'dependencies': [
- '../common/common.gyp:common',
- ],
- },
- ],
-}
diff --git a/src/tools/mac/crash_report/crash_report.mm b/src/tools/mac/crash_report/crash_report.mm
deleted file mode 100644
index f68200c7..00000000
--- a/src/tools/mac/crash_report/crash_report.mm
+++ /dev/null
@@ -1,408 +0,0 @@
-// Copyright (c) 2010 Google Inc.
-// All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-// crash_report.mm: Convert the contents of a minidump into a format that
-// looks more like Apple's CrashReporter format
-
-#include <unistd.h>
-
-#include <mach/machine.h>
-#include <mach-o/arch.h>
-
-#include <string>
-
-#include <Foundation/Foundation.h>
-
-#include "common/scoped_ptr.h"
-#include "google_breakpad/processor/basic_source_line_resolver.h"
-#include "google_breakpad/processor/call_stack.h"
-#include "google_breakpad/processor/code_module.h"
-#include "google_breakpad/processor/minidump.h"
-#include "google_breakpad/processor/minidump_processor.h"
-#include "google_breakpad/processor/process_state.h"
-#include "google_breakpad/processor/stack_frame_cpu.h"
-#include "google_breakpad/processor/system_info.h"
-#include "processor/pathname_stripper.h"
-#include "processor/simple_symbol_supplier.h"
-
-#include "on_demand_symbol_supplier.h"
-
-using std::string;
-
-using google_breakpad::BasicSourceLineResolver;
-using google_breakpad::CallStack;
-using google_breakpad::CodeModule;
-using google_breakpad::CodeModules;
-using google_breakpad::Minidump;
-using google_breakpad::MinidumpProcessor;
-using google_breakpad::OnDemandSymbolSupplier;
-using google_breakpad::PathnameStripper;
-using google_breakpad::ProcessState;
-using google_breakpad::scoped_ptr;
-using google_breakpad::StackFrame;
-using google_breakpad::StackFramePPC;
-using google_breakpad::StackFrameX86;
-using google_breakpad::SystemInfo;
-
-typedef struct {
- NSString *minidumpPath;
- NSString *searchDir;
- NSString *symbolSearchDir;
- BOOL printThreadMemory;
-} Options;
-
-//=============================================================================
-static int PrintRegister(const char *name, u_int32_t value, int sequence) {
- if (sequence % 4 == 0) {
- printf("\n");
- }
- printf("%6s = 0x%08x ", name, value);
- return ++sequence;
-}
-
-//=============================================================================
-static void PrintStack(const CallStack *stack, const string &cpu) {
- size_t frame_count = stack->frames()->size();
- char buffer[1024];
- for (size_t frame_index = 0; frame_index < frame_count; ++frame_index) {
- const StackFrame *frame = stack->frames()->at(frame_index);
- const CodeModule *module = frame->module;
- printf("%2zu ", frame_index);
-
- if (module) {
- // Module name (20 chars max)
- strcpy(buffer, PathnameStripper::File(module->code_file()).c_str());
- int maxStr = 20;
- buffer[maxStr] = 0;
- printf("%-*s", maxStr, buffer);
-
- strcpy(buffer, module->version().c_str());
- buffer[maxStr] = 0;
-
- printf("%-*s",maxStr, buffer);
-
- u_int64_t instruction = frame->instruction;
-
- // PPC only: Adjust the instruction to match that of Crash reporter. The
- // instruction listed is actually the return address. See the detailed
- // comments in stackwalker_ppc.cc for more information.
- if (cpu == "ppc" && frame_index)
- instruction += 4;
-
- printf(" 0x%08llx ", instruction);
-
- // Function name
- if (!frame->function_name.empty()) {
- printf("%s", frame->function_name.c_str());
- if (!frame->source_file_name.empty()) {
- string source_file = PathnameStripper::File(frame->source_file_name);
- printf(" + 0x%llx (%s:%d)",
- instruction - frame->source_line_base,
- source_file.c_str(), frame->source_line);
- } else {
- printf(" + 0x%llx", instruction - frame->function_base);
- }
- }
- }
- printf("\n");
- }
-}
-
-//=============================================================================
-static void PrintRegisters(const CallStack *stack, const string &cpu) {
- int sequence = 0;
- const StackFrame *frame = stack->frames()->at(0);
- if (cpu == "x86") {
- const StackFrameX86 *frame_x86 =
- reinterpret_cast<const StackFrameX86*>(frame);
-
- if (frame_x86->context_validity & StackFrameX86::CONTEXT_VALID_EIP)
- sequence = PrintRegister("eip", frame_x86->context.eip, sequence);
- if (frame_x86->context_validity & StackFrameX86::CONTEXT_VALID_ESP)
- sequence = PrintRegister("esp", frame_x86->context.esp, sequence);
- if (frame_x86->context_validity & StackFrameX86::CONTEXT_VALID_EBP)
- sequence = PrintRegister("ebp", frame_x86->context.ebp, sequence);
- if (frame_x86->context_validity & StackFrameX86::CONTEXT_VALID_EBX)
- sequence = PrintRegister("ebx", frame_x86->context.ebx, sequence);
- if (frame_x86->context_validity & StackFrameX86::CONTEXT_VALID_ESI)
- sequence = PrintRegister("esi", frame_x86->context.esi, sequence);
- if (frame_x86->context_validity & StackFrameX86::CONTEXT_VALID_EDI)
- sequence = PrintRegister("edi", frame_x86->context.edi, sequence);
- if (frame_x86->context_validity == StackFrameX86::CONTEXT_VALID_ALL) {
- sequence = PrintRegister("eax", frame_x86->context.eax, sequence);
- sequence = PrintRegister("ecx", frame_x86->context.ecx, sequence);
- sequence = PrintRegister("edx", frame_x86->context.edx, sequence);
- sequence = PrintRegister("efl", frame_x86->context.eflags, sequence);
- }
- } else if (cpu == "ppc") {
- const StackFramePPC *frame_ppc =
- reinterpret_cast<const StackFramePPC*>(frame);
-
- if ((frame_ppc->context_validity & StackFramePPC::CONTEXT_VALID_ALL) ==
- StackFramePPC::CONTEXT_VALID_ALL) {
- sequence = PrintRegister("srr0", frame_ppc->context.srr0, sequence);
- sequence = PrintRegister("srr1", frame_ppc->context.srr1, sequence);
- sequence = PrintRegister("cr", frame_ppc->context.cr, sequence);
- sequence = PrintRegister("xer", frame_ppc->context.xer, sequence);
- sequence = PrintRegister("lr", frame_ppc->context.lr, sequence);
- sequence = PrintRegister("ctr", frame_ppc->context.ctr, sequence);
- sequence = PrintRegister("mq", frame_ppc->context.mq, sequence);
- sequence = PrintRegister("vrsave", frame_ppc->context.vrsave, sequence);
-
- sequence = 0;
- char buffer[5];
- for (int i = 0; i < MD_CONTEXT_PPC_GPR_COUNT; ++i) {
- sprintf(buffer, "r%d", i);
- sequence = PrintRegister(buffer, frame_ppc->context.gpr[i], sequence);
- }
- } else {
- if (frame_ppc->context_validity & StackFramePPC::CONTEXT_VALID_SRR0)
- sequence = PrintRegister("srr0", frame_ppc->context.srr0, sequence);
- if (frame_ppc->context_validity & StackFramePPC::CONTEXT_VALID_GPR1)
- sequence = PrintRegister("r1", frame_ppc->context.gpr[1], sequence);
- }
- }
-
- printf("\n");
-}
-
-static void PrintModules(const CodeModules *modules) {
- if (!modules)
- return;
-
- printf("\n");
- printf("Loaded modules:\n");
-
- u_int64_t main_address = 0;
- const CodeModule *main_module = modules->GetMainModule();
- if (main_module) {
- main_address = main_module->base_address();
- }
-
- unsigned int module_count = modules->module_count();
- for (unsigned int module_sequence = 0;
- module_sequence < module_count;
- ++module_sequence) {
- const CodeModule *module = modules->GetModuleAtSequence(module_sequence);
- assert(module);
- u_int64_t base_address = module->base_address();
- printf("0x%08llx - 0x%08llx %s %s%s %s\n",
- base_address, base_address + module->size() - 1,
- PathnameStripper::File(module->code_file()).c_str(),
- module->version().empty() ? "???" : module->version().c_str(),
- main_module != NULL && base_address == main_address ?
- " (main)" : "",
- module->code_file().c_str());
- }
-}
-
-static void ProcessSingleReport(Options *options, NSString *file_path) {
- string minidump_file([file_path fileSystemRepresentation]);
- BasicSourceLineResolver resolver;
- string search_dir = options->searchDir ?
- [options->searchDir fileSystemRepresentation] : "";
- string symbol_search_dir = options->symbolSearchDir ?
- [options->symbolSearchDir fileSystemRepresentation] : "";
- scoped_ptr<OnDemandSymbolSupplier> symbol_supplier(
- new OnDemandSymbolSupplier(search_dir, symbol_search_dir));
- scoped_ptr<MinidumpProcessor>
- minidump_processor(new MinidumpProcessor(symbol_supplier.get(), &resolver));
- ProcessState process_state;
- scoped_ptr<Minidump> dump(new google_breakpad::Minidump(minidump_file));
-
- if (!dump->Read()) {
- fprintf(stderr, "Minidump %s could not be read\n", dump->path().c_str());
- return;
- }
- if (minidump_processor->Process(dump.get(), &process_state) !=
- google_breakpad::PROCESS_OK) {
- fprintf(stderr, "MinidumpProcessor::Process failed\n");
- return;
- }
-
- const SystemInfo *system_info = process_state.system_info();
- string cpu = system_info->cpu;
-
- // Convert the time to a string
- u_int32_t time_date_stamp = process_state.time_date_stamp();
- struct tm timestruct;
- gmtime_r(reinterpret_cast<time_t*>(&time_date_stamp), &timestruct);
- char timestr[20];
- strftime(timestr, 20, "%Y-%m-%d %H:%M:%S", &timestruct);
- printf("Date: %s GMT\n", timestr);
-
- printf("Operating system: %s (%s)\n", system_info->os.c_str(),
- system_info->os_version.c_str());
- printf("Architecture: %s\n", cpu.c_str());
-
- if (process_state.crashed()) {
- printf("Crash reason: %s\n", process_state.crash_reason().c_str());
- printf("Crash address: 0x%llx\n", process_state.crash_address());
- } else {
- printf("No crash\n");
- }
-
- int requesting_thread = process_state.requesting_thread();
- if (requesting_thread != -1) {
- printf("\n");
- printf("Thread %d (%s)\n",
- requesting_thread,
- process_state.crashed() ? "crashed" :
- "requested dump, did not crash");
- PrintStack(process_state.threads()->at(requesting_thread), cpu);
- }
-
- // Print all of the threads in the dump.
- int thread_count = static_cast<int>(process_state.threads()->size());
- const std::vector<google_breakpad::MemoryRegion*>
- *thread_memory_regions = process_state.thread_memory_regions();
-
- for (int thread_index = 0; thread_index < thread_count; ++thread_index) {
- if (thread_index != requesting_thread) {
- // Don't print the crash thread again, it was already printed.
- printf("\n");
- printf("Thread %d\n", thread_index);
- PrintStack(process_state.threads()->at(thread_index), cpu);
- google_breakpad::MemoryRegion *thread_stack_bytes =
- thread_memory_regions->at(thread_index);
- if (options->printThreadMemory) {
- thread_stack_bytes->Print();
- }
- }
- }
-
- // Print the crashed registers
- if (requesting_thread != -1) {
- printf("\nThread %d:", requesting_thread);
- PrintRegisters(process_state.threads()->at(requesting_thread), cpu);
- }
-
- // Print information about modules
- PrintModules(process_state.modules());
-}
-
-//=============================================================================
-static void Start(Options *options) {
- NSFileManager *manager = [NSFileManager defaultManager];
- NSString *minidump_path = options->minidumpPath;
- BOOL is_dir = NO;
- BOOL file_exists = [manager fileExistsAtPath:minidump_path
- isDirectory:&is_dir];
- if (file_exists && is_dir) {
- NSDirectoryEnumerator *enumerator =
- [manager enumeratorAtPath:minidump_path];
- NSString *current_file = nil;
- while ((current_file = [enumerator nextObject])) {
- NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
- if ([[current_file pathExtension] isEqualTo:@"dmp"]) {
- printf("Attempting to process report: %s\n",
- [current_file cStringUsingEncoding:NSASCIIStringEncoding]);
- NSString *full_path =
- [minidump_path stringByAppendingPathComponent:current_file];
- ProcessSingleReport(options, full_path);
- }
- [pool release];
- }
- } else if (file_exists) {
- ProcessSingleReport(options, minidump_path);
- }
-}
-
-//=============================================================================
-static void Usage(int argc, const char *argv[]) {
- fprintf(stderr, "Convert a minidump to a crash report. Breakpad symbol "
- "files will be used (or created if missing) in /tmp.\n"
- "If a symbol-file-search-dir is specified, any symbol "
- "files in it will be used instead of being loaded from "
- "modules on disk.\n"
- "If modules cannot be found at the paths stored in the "
- "minidump file, they will be searched for at "
- "<module-search-dir>/<path-in-minidump-file>.\n");
- fprintf(stderr, "Usage: %s [-s module-search-dir] [-S symbol-file-search-dir] "
- "minidump-file\n", argv[0]);
- fprintf(stderr, "\t-s: Specify a search directory to use for missing modules\n"
- "\t-S: Specify a search directory to use for symbol files\n"
- "\t-t: Print thread stack memory in hex\n"
- "\t-h: Usage\n"
- "\t-?: Usage\n");
-}
-
-//=============================================================================
-static void SetupOptions(int argc, const char *argv[], Options *options) {
- extern int optind;
- char ch;
-
- while ((ch = getopt(argc, (char * const *)argv, "S:s:ht?")) != -1) {
- switch (ch) {
- case 's':
- options->searchDir = [[NSFileManager defaultManager]
- stringWithFileSystemRepresentation:optarg
- length:strlen(optarg)];
- break;
-
- case 'S':
- options->symbolSearchDir = [[NSFileManager defaultManager]
- stringWithFileSystemRepresentation:optarg
- length:strlen(optarg)];
- break;
-
- case 't':
- options->printThreadMemory = YES;
- break;
- case 'h':
- case '?':
- Usage(argc, argv);
- exit(1);
- break;
- }
- }
-
- if ((argc - optind) != 1) {
- fprintf(stderr, "%s: Missing minidump file\n", argv[0]);
- Usage(argc, argv);
- exit(1);
- }
-
- options->minidumpPath = [[NSFileManager defaultManager]
- stringWithFileSystemRepresentation:argv[optind]
- length:strlen(argv[optind])];
-}
-
-//=============================================================================
-int main (int argc, const char * argv[]) {
- NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
- Options options;
-
- bzero(&options, sizeof(Options));
- SetupOptions(argc, argv, &options);
- Start(&options);
- [pool release];
-
- return 0;
-}
diff --git a/src/tools/mac/crash_report/crash_report.xcodeproj/project.pbxproj b/src/tools/mac/crash_report/crash_report.xcodeproj/project.pbxproj
deleted file mode 100644
index 33204f7e..00000000
--- a/src/tools/mac/crash_report/crash_report.xcodeproj/project.pbxproj
+++ /dev/null
@@ -1,618 +0,0 @@
-// !$*UTF8*$!
-{
- archiveVersion = 1;
- classes = {
- };
- objectVersion = 45;
- objects = {
-
-/* Begin PBXBuildFile section */
- 162F64FE161C5ECB00CD68D5 /* arch_utilities.cc in Sources */ = {isa = PBXBuildFile; fileRef = 162F64FC161C5ECB00CD68D5 /* arch_utilities.cc */; };
- 4214B800211109A600B769FA /* convert_old_arm64_context.cc in Sources */ = {isa = PBXBuildFile; fileRef = 4214B7FE211109A600B769FA /* convert_old_arm64_context.cc */; };
- 4247E6402110D5A500482558 /* path_helper.cc in Sources */ = {isa = PBXBuildFile; fileRef = 4247E63F2110D5A500482558 /* path_helper.cc */; };
- 4D2C721B126F9ACC00B43EAF /* source_line_resolver_base.cc in Sources */ = {isa = PBXBuildFile; fileRef = 4D2C721A126F9ACC00B43EAF /* source_line_resolver_base.cc */; };
- 4D2C721F126F9ADE00B43EAF /* exploitability.cc in Sources */ = {isa = PBXBuildFile; fileRef = 4D2C721E126F9ADE00B43EAF /* exploitability.cc */; };
- 4D2C7223126F9AF900B43EAF /* exploitability_win.cc in Sources */ = {isa = PBXBuildFile; fileRef = 4D2C7222126F9AF900B43EAF /* exploitability_win.cc */; };
- 4D2C7227126F9B0F00B43EAF /* disassembler_x86.cc in Sources */ = {isa = PBXBuildFile; fileRef = 4D2C7226126F9B0F00B43EAF /* disassembler_x86.cc */; };
- 4D2C722B126F9B5A00B43EAF /* x86_disasm.c in Sources */ = {isa = PBXBuildFile; fileRef = 4D2C722A126F9B5A00B43EAF /* x86_disasm.c */; };
- 4D2C722D126F9B6E00B43EAF /* x86_misc.c in Sources */ = {isa = PBXBuildFile; fileRef = 4D2C722C126F9B6E00B43EAF /* x86_misc.c */; };
- 4D2C722F126F9B8300B43EAF /* x86_operand_list.c in Sources */ = {isa = PBXBuildFile; fileRef = 4D2C722E126F9B8300B43EAF /* x86_operand_list.c */; };
- 4D2C7233126F9BB000B43EAF /* ia32_invariant.c in Sources */ = {isa = PBXBuildFile; fileRef = 4D2C7232126F9BB000B43EAF /* ia32_invariant.c */; settings = {COMPILER_FLAGS = "-Wno-error"; }; };
- 4D2C7235126F9BC200B43EAF /* ia32_settings.c in Sources */ = {isa = PBXBuildFile; fileRef = 4D2C7234126F9BC200B43EAF /* ia32_settings.c */; };
- 4D2C7246126F9C0B00B43EAF /* ia32_insn.c in Sources */ = {isa = PBXBuildFile; fileRef = 4D2C7245126F9C0B00B43EAF /* ia32_insn.c */; };
- 4D2C724A126F9C2300B43EAF /* ia32_opcode_tables.c in Sources */ = {isa = PBXBuildFile; fileRef = 4D2C7249126F9C2300B43EAF /* ia32_opcode_tables.c */; settings = {COMPILER_FLAGS = "-Wno-error"; }; };
- 4D2C724C126F9C3800B43EAF /* ia32_implicit.c in Sources */ = {isa = PBXBuildFile; fileRef = 4D2C724B126F9C3800B43EAF /* ia32_implicit.c */; settings = {COMPILER_FLAGS = "-Wno-error"; }; };
- 4D2C724E126F9C4D00B43EAF /* ia32_reg.c in Sources */ = {isa = PBXBuildFile; fileRef = 4D2C724D126F9C4D00B43EAF /* ia32_reg.c */; settings = {COMPILER_FLAGS = "-Wno-error"; }; };
- 4D2C725B126F9C8000B43EAF /* ia32_operand.c in Sources */ = {isa = PBXBuildFile; fileRef = 4D2C725A126F9C8000B43EAF /* ia32_operand.c */; };
- 4D2C725D126F9C9200B43EAF /* x86_insn.c in Sources */ = {isa = PBXBuildFile; fileRef = 4D2C725C126F9C9200B43EAF /* x86_insn.c */; };
- 4D2C7264126F9CBB00B43EAF /* ia32_modrm.c in Sources */ = {isa = PBXBuildFile; fileRef = 4D2C7261126F9CBB00B43EAF /* ia32_modrm.c */; };
- 4D2C726D126F9CDC00B43EAF /* x86_imm.c in Sources */ = {isa = PBXBuildFile; fileRef = 4D2C7263126F9CBB00B43EAF /* x86_imm.c */; };
- 4D72CA5713DFBA84006CABE3 /* md5.cc in Sources */ = {isa = PBXBuildFile; fileRef = 4D72CA5613DFBA84006CABE3 /* md5.cc */; };
- 557800400BE1F28500EC23E0 /* macho_utilities.cc in Sources */ = {isa = PBXBuildFile; fileRef = 5578003E0BE1F28500EC23E0 /* macho_utilities.cc */; };
- 8B31FF2A11F0C62700FCF3E4 /* dwarf_cfi_to_module.cc in Sources */ = {isa = PBXBuildFile; fileRef = 8B31FF2411F0C62700FCF3E4 /* dwarf_cfi_to_module.cc */; };
- 8B31FF2B11F0C62700FCF3E4 /* dwarf_cu_to_module.cc in Sources */ = {isa = PBXBuildFile; fileRef = 8B31FF2611F0C62700FCF3E4 /* dwarf_cu_to_module.cc */; };
- 8B31FF2C11F0C62700FCF3E4 /* dwarf_line_to_module.cc in Sources */ = {isa = PBXBuildFile; fileRef = 8B31FF2811F0C62700FCF3E4 /* dwarf_line_to_module.cc */; };
- 8B31FF4111F0C64400FCF3E4 /* stabs_reader.cc in Sources */ = {isa = PBXBuildFile; fileRef = 8B31FF3D11F0C64400FCF3E4 /* stabs_reader.cc */; };
- 8B31FF4211F0C64400FCF3E4 /* stabs_to_module.cc in Sources */ = {isa = PBXBuildFile; fileRef = 8B31FF3F11F0C64400FCF3E4 /* stabs_to_module.cc */; };
- 8B31FF7411F0C6E000FCF3E4 /* macho_reader.cc in Sources */ = {isa = PBXBuildFile; fileRef = 8B31FF7211F0C6E000FCF3E4 /* macho_reader.cc */; };
- 8B31FF8811F0C6FB00FCF3E4 /* language.cc in Sources */ = {isa = PBXBuildFile; fileRef = 8B31FF8411F0C6FB00FCF3E4 /* language.cc */; };
- 8B31FF8911F0C6FB00FCF3E4 /* module.cc in Sources */ = {isa = PBXBuildFile; fileRef = 8B31FF8611F0C6FB00FCF3E4 /* module.cc */; };
- 8B31FFC511F0C8AB00FCF3E4 /* dwarf2diehandler.cc in Sources */ = {isa = PBXBuildFile; fileRef = 8B31FFC311F0C8AB00FCF3E4 /* dwarf2diehandler.cc */; };
- 8B40BDC00C0638E4009535AF /* logging.cc in Sources */ = {isa = PBXBuildFile; fileRef = 8B40BDBF0C0638E4009535AF /* logging.cc */; };
- 8DD76F9A0486AA7600D96B5E /* crash_report.mm in Sources */ = {isa = PBXBuildFile; fileRef = 08FB7796FE84155DC02AAC07 /* crash_report.mm */; settings = {ATTRIBUTES = (); }; };
- 8DD76F9C0486AA7600D96B5E /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 08FB779EFE84155DC02AAC07 /* Foundation.framework */; };
- 9B35FEEA0B26761C008DE8C7 /* basic_code_modules.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9B35FEE70B26761C008DE8C7 /* basic_code_modules.cc */; };
- 9B3904990B2E52FD0059FABE /* basic_source_line_resolver.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9B3904980B2E52FD0059FABE /* basic_source_line_resolver.cc */; };
- 9BDF172C0B1B8B2400F8391B /* call_stack.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9BDF172A0B1B8B2400F8391B /* call_stack.cc */; };
- 9BDF172D0B1B8B2400F8391B /* minidump_processor.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9BDF172B0B1B8B2400F8391B /* minidump_processor.cc */; };
- 9BDF17410B1B8B9A00F8391B /* minidump.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9BDF173F0B1B8B9A00F8391B /* minidump.cc */; };
- 9BDF17540B1B8BF900F8391B /* stackwalker_ppc.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9BDF17510B1B8BF900F8391B /* stackwalker_ppc.cc */; };
- 9BDF17550B1B8BF900F8391B /* stackwalker_x86.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9BDF17520B1B8BF900F8391B /* stackwalker_x86.cc */; };
- 9BDF17560B1B8BF900F8391B /* stackwalker.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9BDF17530B1B8BF900F8391B /* stackwalker.cc */; };
- 9BDF175D0B1B8C1B00F8391B /* process_state.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9BDF175B0B1B8C1B00F8391B /* process_state.cc */; };
- 9BDF176E0B1B8CB100F8391B /* on_demand_symbol_supplier.mm in Sources */ = {isa = PBXBuildFile; fileRef = 9BDF176C0B1B8CB100F8391B /* on_demand_symbol_supplier.mm */; };
- 9BDF1A280B1BD58200F8391B /* pathname_stripper.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9BDF1A270B1BD58200F8391B /* pathname_stripper.cc */; };
- 9BDF21A70B1E825400F8391B /* dump_syms.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9BDF192E0B1BC15D00F8391B /* dump_syms.cc */; };
- 9BE650B20B52FE3000611104 /* file_id.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9BE650AC0B52FE3000611104 /* file_id.cc */; };
- 9BE650B40B52FE3000611104 /* macho_id.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9BE650AE0B52FE3000611104 /* macho_id.cc */; };
- 9BE650B60B52FE3000611104 /* macho_walker.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9BE650B00B52FE3000611104 /* macho_walker.cc */; };
- D2A5DD4D1188651100081F03 /* cfi_frame_info.cc in Sources */ = {isa = PBXBuildFile; fileRef = D2A5DD4C1188651100081F03 /* cfi_frame_info.cc */; };
- D2A5DD631188658B00081F03 /* tokenize.cc in Sources */ = {isa = PBXBuildFile; fileRef = D2A5DD621188658B00081F03 /* tokenize.cc */; };
- F407DC48185773C10064622B /* exploitability_linux.cc in Sources */ = {isa = PBXBuildFile; fileRef = F407DC40185773C10064622B /* exploitability_linux.cc */; };
- F407DC49185773C10064622B /* stack_frame_symbolizer.cc in Sources */ = {isa = PBXBuildFile; fileRef = F407DC41185773C10064622B /* stack_frame_symbolizer.cc */; };
- F407DC4A185773C10064622B /* stackwalker_arm64.cc in Sources */ = {isa = PBXBuildFile; fileRef = F407DC42185773C10064622B /* stackwalker_arm64.cc */; };
- F407DC4B185773C10064622B /* stackwalker_mips.cc in Sources */ = {isa = PBXBuildFile; fileRef = F407DC44185773C10064622B /* stackwalker_mips.cc */; };
- F407DC4C185773C10064622B /* stackwalker_ppc64.cc in Sources */ = {isa = PBXBuildFile; fileRef = F407DC46185773C10064622B /* stackwalker_ppc64.cc */; };
- F44DDD8719C85CD50047280E /* dump_context.cc in Sources */ = {isa = PBXBuildFile; fileRef = F44DDD8419C85CD50047280E /* dump_context.cc */; };
- F44DDD8819C85CD50047280E /* dump_object.cc in Sources */ = {isa = PBXBuildFile; fileRef = F44DDD8519C85CD50047280E /* dump_object.cc */; };
- F44DDD8919C85CD50047280E /* microdump_processor.cc in Sources */ = {isa = PBXBuildFile; fileRef = F44DDD8619C85CD50047280E /* microdump_processor.cc */; };
- F47180561D745DEF0032F208 /* elf_reader.cc in Sources */ = {isa = PBXBuildFile; fileRef = F47180541D745DEF0032F208 /* elf_reader.cc */; };
- F47180581D7467630032F208 /* proc_maps_linux.cc in Sources */ = {isa = PBXBuildFile; fileRef = F47180571D7467630032F208 /* proc_maps_linux.cc */; };
- F471805A1D7468A40032F208 /* symbolic_constants_win.cc in Sources */ = {isa = PBXBuildFile; fileRef = F47180591D7468A40032F208 /* symbolic_constants_win.cc */; };
- F4D43B2F1A38490700C290B2 /* microdump.cc in Sources */ = {isa = PBXBuildFile; fileRef = F4D43B2E1A38490700C290B2 /* microdump.cc */; };
- F9C7ECE50E8ABCA600E953AD /* bytereader.cc in Sources */ = {isa = PBXBuildFile; fileRef = F9C7ECE20E8ABCA600E953AD /* bytereader.cc */; };
- F9C7ECE60E8ABCA600E953AD /* dwarf2reader.cc in Sources */ = {isa = PBXBuildFile; fileRef = F9C7ECE30E8ABCA600E953AD /* dwarf2reader.cc */; };
- F9C7ECE70E8ABCA600E953AD /* functioninfo.cc in Sources */ = {isa = PBXBuildFile; fileRef = F9C7ECE40E8ABCA600E953AD /* functioninfo.cc */; };
- F9F0706710FBC02D0037B88B /* stackwalker_arm.cc in Sources */ = {isa = PBXBuildFile; fileRef = F9F0706510FBC02D0037B88B /* stackwalker_arm.cc */; };
- FD6625CD0CF4D45C004AC844 /* stackwalker_amd64.cc in Sources */ = {isa = PBXBuildFile; fileRef = FD6625C40CF4D438004AC844 /* stackwalker_amd64.cc */; };
- FD8EDEAE0CADDAD400A5EDF1 /* stackwalker_sparc.cc in Sources */ = {isa = PBXBuildFile; fileRef = FD8EDEAC0CADDAD400A5EDF1 /* stackwalker_sparc.cc */; };
-/* End PBXBuildFile section */
-
-/* Begin PBXFileReference section */
- 08FB7796FE84155DC02AAC07 /* crash_report.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = crash_report.mm; sourceTree = "<group>"; };
- 08FB779EFE84155DC02AAC07 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
- 162F64FC161C5ECB00CD68D5 /* arch_utilities.cc */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = arch_utilities.cc; path = ../../../common/mac/arch_utilities.cc; sourceTree = "<group>"; };
- 162F64FD161C5ECB00CD68D5 /* arch_utilities.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = arch_utilities.h; path = ../../../common/mac/arch_utilities.h; sourceTree = "<group>"; };
- 4214B7FE211109A600B769FA /* convert_old_arm64_context.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = convert_old_arm64_context.cc; path = ../../../processor/convert_old_arm64_context.cc; sourceTree = "<group>"; };
- 4214B7FF211109A600B769FA /* convert_old_arm64_context.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = convert_old_arm64_context.h; path = ../../../processor/convert_old_arm64_context.h; sourceTree = "<group>"; };
- 4247E63E2110D5A500482558 /* path_helper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = path_helper.h; path = ../../../common/path_helper.h; sourceTree = "<group>"; };
- 4247E63F2110D5A500482558 /* path_helper.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = path_helper.cc; path = ../../../common/path_helper.cc; sourceTree = "<group>"; };
- 4D2C721A126F9ACC00B43EAF /* source_line_resolver_base.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = source_line_resolver_base.cc; path = ../../../processor/source_line_resolver_base.cc; sourceTree = SOURCE_ROOT; };
- 4D2C721E126F9ADE00B43EAF /* exploitability.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = exploitability.cc; path = ../../../processor/exploitability.cc; sourceTree = SOURCE_ROOT; };
- 4D2C7222126F9AF900B43EAF /* exploitability_win.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = exploitability_win.cc; path = ../../../processor/exploitability_win.cc; sourceTree = SOURCE_ROOT; };
- 4D2C7226126F9B0F00B43EAF /* disassembler_x86.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = disassembler_x86.cc; path = ../../../processor/disassembler_x86.cc; sourceTree = SOURCE_ROOT; };
- 4D2C722A126F9B5A00B43EAF /* x86_disasm.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = x86_disasm.c; path = ../../../third_party/libdisasm/x86_disasm.c; sourceTree = SOURCE_ROOT; };
- 4D2C722C126F9B6E00B43EAF /* x86_misc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = x86_misc.c; path = ../../../third_party/libdisasm/x86_misc.c; sourceTree = SOURCE_ROOT; };
- 4D2C722E126F9B8300B43EAF /* x86_operand_list.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = x86_operand_list.c; path = ../../../third_party/libdisasm/x86_operand_list.c; sourceTree = SOURCE_ROOT; };
- 4D2C7232126F9BB000B43EAF /* ia32_invariant.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = ia32_invariant.c; path = ../../../third_party/libdisasm/ia32_invariant.c; sourceTree = SOURCE_ROOT; };
- 4D2C7234126F9BC200B43EAF /* ia32_settings.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = ia32_settings.c; path = ../../../third_party/libdisasm/ia32_settings.c; sourceTree = SOURCE_ROOT; };
- 4D2C7245126F9C0B00B43EAF /* ia32_insn.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = ia32_insn.c; path = ../../../third_party/libdisasm/ia32_insn.c; sourceTree = SOURCE_ROOT; };
- 4D2C7249126F9C2300B43EAF /* ia32_opcode_tables.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = ia32_opcode_tables.c; path = ../../../third_party/libdisasm/ia32_opcode_tables.c; sourceTree = SOURCE_ROOT; };
- 4D2C724B126F9C3800B43EAF /* ia32_implicit.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = ia32_implicit.c; path = ../../../third_party/libdisasm/ia32_implicit.c; sourceTree = SOURCE_ROOT; };
- 4D2C724D126F9C4D00B43EAF /* ia32_reg.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = ia32_reg.c; path = ../../../third_party/libdisasm/ia32_reg.c; sourceTree = SOURCE_ROOT; };
- 4D2C725A126F9C8000B43EAF /* ia32_operand.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = ia32_operand.c; path = ../../../third_party/libdisasm/ia32_operand.c; sourceTree = SOURCE_ROOT; };
- 4D2C725C126F9C9200B43EAF /* x86_insn.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = x86_insn.c; path = ../../../third_party/libdisasm/x86_insn.c; sourceTree = SOURCE_ROOT; };
- 4D2C7261126F9CBB00B43EAF /* ia32_modrm.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = ia32_modrm.c; path = ../../../third_party/libdisasm/ia32_modrm.c; sourceTree = SOURCE_ROOT; };
- 4D2C7263126F9CBB00B43EAF /* x86_imm.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = x86_imm.c; path = ../../../third_party/libdisasm/x86_imm.c; sourceTree = SOURCE_ROOT; };
- 4D72CA5613DFBA84006CABE3 /* md5.cc */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.cpp; fileEncoding = 4; name = md5.cc; path = ../../../common/md5.cc; sourceTree = SOURCE_ROOT; };
- 5578003E0BE1F28500EC23E0 /* macho_utilities.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = macho_utilities.cc; path = ../../../common/mac/macho_utilities.cc; sourceTree = SOURCE_ROOT; };
- 5578003F0BE1F28500EC23E0 /* macho_utilities.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = macho_utilities.h; path = ../../../common/mac/macho_utilities.h; sourceTree = SOURCE_ROOT; };
- 8B31025311F0D2D400FCF3E4 /* Breakpad.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Breakpad.xcconfig; path = ../../../common/mac/Breakpad.xcconfig; sourceTree = SOURCE_ROOT; };
- 8B3102DA11F0D65600FCF3E4 /* BreakpadDebug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = BreakpadDebug.xcconfig; path = ../../../common/mac/BreakpadDebug.xcconfig; sourceTree = SOURCE_ROOT; };
- 8B3102DB11F0D65600FCF3E4 /* BreakpadRelease.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = BreakpadRelease.xcconfig; path = ../../../common/mac/BreakpadRelease.xcconfig; sourceTree = SOURCE_ROOT; };
- 8B31FF2411F0C62700FCF3E4 /* dwarf_cfi_to_module.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = dwarf_cfi_to_module.cc; path = ../../../common/dwarf_cfi_to_module.cc; sourceTree = SOURCE_ROOT; };
- 8B31FF2511F0C62700FCF3E4 /* dwarf_cfi_to_module.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dwarf_cfi_to_module.h; path = ../../../common/dwarf_cfi_to_module.h; sourceTree = SOURCE_ROOT; };
- 8B31FF2611F0C62700FCF3E4 /* dwarf_cu_to_module.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = dwarf_cu_to_module.cc; path = ../../../common/dwarf_cu_to_module.cc; sourceTree = SOURCE_ROOT; };
- 8B31FF2711F0C62700FCF3E4 /* dwarf_cu_to_module.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dwarf_cu_to_module.h; path = ../../../common/dwarf_cu_to_module.h; sourceTree = SOURCE_ROOT; };
- 8B31FF2811F0C62700FCF3E4 /* dwarf_line_to_module.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = dwarf_line_to_module.cc; path = ../../../common/dwarf_line_to_module.cc; sourceTree = SOURCE_ROOT; };
- 8B31FF2911F0C62700FCF3E4 /* dwarf_line_to_module.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dwarf_line_to_module.h; path = ../../../common/dwarf_line_to_module.h; sourceTree = SOURCE_ROOT; };
- 8B31FF3D11F0C64400FCF3E4 /* stabs_reader.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = stabs_reader.cc; path = ../../../common/stabs_reader.cc; sourceTree = SOURCE_ROOT; };
- 8B31FF3E11F0C64400FCF3E4 /* stabs_reader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = stabs_reader.h; path = ../../../common/stabs_reader.h; sourceTree = SOURCE_ROOT; };
- 8B31FF3F11F0C64400FCF3E4 /* stabs_to_module.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = stabs_to_module.cc; path = ../../../common/stabs_to_module.cc; sourceTree = SOURCE_ROOT; };
- 8B31FF4011F0C64400FCF3E4 /* stabs_to_module.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = stabs_to_module.h; path = ../../../common/stabs_to_module.h; sourceTree = SOURCE_ROOT; };
- 8B31FF7211F0C6E000FCF3E4 /* macho_reader.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = macho_reader.cc; path = ../../../common/mac/macho_reader.cc; sourceTree = SOURCE_ROOT; };
- 8B31FF7311F0C6E000FCF3E4 /* macho_reader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = macho_reader.h; path = ../../../common/mac/macho_reader.h; sourceTree = SOURCE_ROOT; };
- 8B31FF8411F0C6FB00FCF3E4 /* language.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = language.cc; path = ../../../common/language.cc; sourceTree = SOURCE_ROOT; };
- 8B31FF8511F0C6FB00FCF3E4 /* language.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = language.h; path = ../../../common/language.h; sourceTree = SOURCE_ROOT; };
- 8B31FF8611F0C6FB00FCF3E4 /* module.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = module.cc; path = ../../../common/module.cc; sourceTree = SOURCE_ROOT; };
- 8B31FF8711F0C6FB00FCF3E4 /* module.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = module.h; path = ../../../common/module.h; sourceTree = SOURCE_ROOT; };
- 8B31FFC311F0C8AB00FCF3E4 /* dwarf2diehandler.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = dwarf2diehandler.cc; path = ../../../common/dwarf/dwarf2diehandler.cc; sourceTree = SOURCE_ROOT; };
- 8B31FFC411F0C8AB00FCF3E4 /* dwarf2diehandler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dwarf2diehandler.h; path = ../../../common/dwarf/dwarf2diehandler.h; sourceTree = SOURCE_ROOT; };
- 8B40BDBF0C0638E4009535AF /* logging.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = logging.cc; path = ../../../processor/logging.cc; sourceTree = SOURCE_ROOT; };
- 8DD76FA10486AA7600D96B5E /* crash_report */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = crash_report; sourceTree = BUILT_PRODUCTS_DIR; };
- 9B35FEE20B2675F9008DE8C7 /* code_module.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = code_module.h; path = ../../../google_breakpad/processor/code_module.h; sourceTree = SOURCE_ROOT; };
- 9B35FEE30B2675F9008DE8C7 /* code_modules.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = code_modules.h; path = ../../../google_breakpad/processor/code_modules.h; sourceTree = SOURCE_ROOT; };
- 9B35FEE60B26761C008DE8C7 /* basic_code_module.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = basic_code_module.h; path = ../../../processor/basic_code_module.h; sourceTree = SOURCE_ROOT; };
- 9B35FEE70B26761C008DE8C7 /* basic_code_modules.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = basic_code_modules.cc; path = ../../../processor/basic_code_modules.cc; sourceTree = SOURCE_ROOT; };
- 9B35FEE80B26761C008DE8C7 /* basic_code_modules.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = basic_code_modules.h; path = ../../../processor/basic_code_modules.h; sourceTree = SOURCE_ROOT; };
- 9B3904940B2E52D90059FABE /* basic_source_line_resolver.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = basic_source_line_resolver.h; sourceTree = "<group>"; };
- 9B3904950B2E52D90059FABE /* source_line_resolver_interface.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = source_line_resolver_interface.h; sourceTree = "<group>"; };
- 9B3904980B2E52FD0059FABE /* basic_source_line_resolver.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = basic_source_line_resolver.cc; path = ../../../processor/basic_source_line_resolver.cc; sourceTree = SOURCE_ROOT; };
- 9B44619D0B66C66B00BBB817 /* system_info.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = system_info.h; sourceTree = "<group>"; };
- 9BDF16F90B1B8ACD00F8391B /* breakpad_types.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = breakpad_types.h; sourceTree = "<group>"; };
- 9BDF16FA0B1B8ACD00F8391B /* minidump_format.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = minidump_format.h; sourceTree = "<group>"; };
- 9BDF16FC0B1B8ACD00F8391B /* call_stack.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = call_stack.h; sourceTree = "<group>"; };
- 9BDF16FD0B1B8ACD00F8391B /* memory_region.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = memory_region.h; sourceTree = "<group>"; };
- 9BDF16FE0B1B8ACD00F8391B /* minidump.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = minidump.h; sourceTree = "<group>"; };
- 9BDF16FF0B1B8ACD00F8391B /* minidump_processor.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = minidump_processor.h; sourceTree = "<group>"; };
- 9BDF17000B1B8ACD00F8391B /* process_state.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = process_state.h; sourceTree = "<group>"; };
- 9BDF17010B1B8ACD00F8391B /* stack_frame.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = stack_frame.h; sourceTree = "<group>"; };
- 9BDF17020B1B8ACD00F8391B /* stack_frame_cpu.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = stack_frame_cpu.h; sourceTree = "<group>"; };
- 9BDF17030B1B8ACD00F8391B /* stackwalker.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = stackwalker.h; sourceTree = "<group>"; };
- 9BDF17040B1B8ACD00F8391B /* symbol_supplier.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = symbol_supplier.h; sourceTree = "<group>"; };
- 9BDF172A0B1B8B2400F8391B /* call_stack.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = call_stack.cc; path = ../../../processor/call_stack.cc; sourceTree = SOURCE_ROOT; };
- 9BDF172B0B1B8B2400F8391B /* minidump_processor.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = minidump_processor.cc; path = ../../../processor/minidump_processor.cc; sourceTree = SOURCE_ROOT; };
- 9BDF173F0B1B8B9A00F8391B /* minidump.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = minidump.cc; path = ../../../processor/minidump.cc; sourceTree = SOURCE_ROOT; };
- 9BDF17510B1B8BF900F8391B /* stackwalker_ppc.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = stackwalker_ppc.cc; path = ../../../processor/stackwalker_ppc.cc; sourceTree = SOURCE_ROOT; };
- 9BDF17520B1B8BF900F8391B /* stackwalker_x86.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = stackwalker_x86.cc; path = ../../../processor/stackwalker_x86.cc; sourceTree = SOURCE_ROOT; };
- 9BDF17530B1B8BF900F8391B /* stackwalker.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = stackwalker.cc; path = ../../../processor/stackwalker.cc; sourceTree = SOURCE_ROOT; };
- 9BDF175B0B1B8C1B00F8391B /* process_state.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = process_state.cc; path = ../../../processor/process_state.cc; sourceTree = SOURCE_ROOT; };
- 9BDF176B0B1B8CB100F8391B /* on_demand_symbol_supplier.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = on_demand_symbol_supplier.h; sourceTree = "<group>"; };
- 9BDF176C0B1B8CB100F8391B /* on_demand_symbol_supplier.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = on_demand_symbol_supplier.mm; sourceTree = "<group>"; };
- 9BDF192D0B1BC15D00F8391B /* dump_syms.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = dump_syms.h; path = ../../../common/mac/dump_syms.h; sourceTree = SOURCE_ROOT; };
- 9BDF192E0B1BC15D00F8391B /* dump_syms.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.objcpp; name = dump_syms.cc; path = ../../../common/mac/dump_syms.cc; sourceTree = SOURCE_ROOT; };
- 9BDF1A270B1BD58200F8391B /* pathname_stripper.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = pathname_stripper.cc; path = ../../../processor/pathname_stripper.cc; sourceTree = SOURCE_ROOT; };
- 9BDF1A7A0B1BE30100F8391B /* range_map-inl.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = "range_map-inl.h"; path = "../../../processor/range_map-inl.h"; sourceTree = SOURCE_ROOT; };
- 9BDF1A7B0B1BE30100F8391B /* range_map.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = range_map.h; path = ../../../processor/range_map.h; sourceTree = SOURCE_ROOT; };
- 9BDF1AFA0B1BEB6300F8391B /* address_map-inl.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = "address_map-inl.h"; path = "../../../processor/address_map-inl.h"; sourceTree = SOURCE_ROOT; };
- 9BDF1AFB0B1BEB6300F8391B /* address_map.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = address_map.h; path = ../../../processor/address_map.h; sourceTree = SOURCE_ROOT; };
- 9BE650AC0B52FE3000611104 /* file_id.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = file_id.cc; path = ../../../common/mac/file_id.cc; sourceTree = SOURCE_ROOT; };
- 9BE650AD0B52FE3000611104 /* file_id.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = file_id.h; path = ../../../common/mac/file_id.h; sourceTree = SOURCE_ROOT; };
- 9BE650AE0B52FE3000611104 /* macho_id.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = macho_id.cc; path = ../../../common/mac/macho_id.cc; sourceTree = SOURCE_ROOT; };
- 9BE650AF0B52FE3000611104 /* macho_id.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = macho_id.h; path = ../../../common/mac/macho_id.h; sourceTree = SOURCE_ROOT; };
- 9BE650B00B52FE3000611104 /* macho_walker.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = macho_walker.cc; path = ../../../common/mac/macho_walker.cc; sourceTree = SOURCE_ROOT; };
- 9BE650B10B52FE3000611104 /* macho_walker.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = macho_walker.h; path = ../../../common/mac/macho_walker.h; sourceTree = SOURCE_ROOT; };
- D2A5DD4C1188651100081F03 /* cfi_frame_info.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = cfi_frame_info.cc; path = ../../../processor/cfi_frame_info.cc; sourceTree = SOURCE_ROOT; };
- D2A5DD621188658B00081F03 /* tokenize.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = tokenize.cc; path = ../../../processor/tokenize.cc; sourceTree = SOURCE_ROOT; };
- F407DC40185773C10064622B /* exploitability_linux.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = exploitability_linux.cc; path = ../../../processor/exploitability_linux.cc; sourceTree = "<group>"; };
- F407DC41185773C10064622B /* stack_frame_symbolizer.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = stack_frame_symbolizer.cc; path = ../../../processor/stack_frame_symbolizer.cc; sourceTree = "<group>"; };
- F407DC42185773C10064622B /* stackwalker_arm64.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = stackwalker_arm64.cc; path = ../../../processor/stackwalker_arm64.cc; sourceTree = "<group>"; };
- F407DC43185773C10064622B /* stackwalker_arm64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = stackwalker_arm64.h; path = ../../../processor/stackwalker_arm64.h; sourceTree = "<group>"; };
- F407DC44185773C10064622B /* stackwalker_mips.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = stackwalker_mips.cc; path = ../../../processor/stackwalker_mips.cc; sourceTree = "<group>"; };
- F407DC45185773C10064622B /* stackwalker_mips.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = stackwalker_mips.h; path = ../../../processor/stackwalker_mips.h; sourceTree = "<group>"; };
- F407DC46185773C10064622B /* stackwalker_ppc64.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = stackwalker_ppc64.cc; path = ../../../processor/stackwalker_ppc64.cc; sourceTree = "<group>"; };
- F407DC47185773C10064622B /* stackwalker_ppc64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = stackwalker_ppc64.h; path = ../../../processor/stackwalker_ppc64.h; sourceTree = "<group>"; };
- F44DDD8419C85CD50047280E /* dump_context.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = dump_context.cc; path = ../../../processor/dump_context.cc; sourceTree = "<group>"; };
- F44DDD8519C85CD50047280E /* dump_object.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = dump_object.cc; path = ../../../processor/dump_object.cc; sourceTree = "<group>"; };
- F44DDD8619C85CD50047280E /* microdump_processor.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = microdump_processor.cc; path = ../../../processor/microdump_processor.cc; sourceTree = "<group>"; };
- F44DDD8A19C85CFB0047280E /* dump_context.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = dump_context.h; path = ../../../google_breakpad/processor/dump_context.h; sourceTree = "<group>"; };
- F44DDD8B19C85CFB0047280E /* dump_object.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = dump_object.h; path = ../../../google_breakpad/processor/dump_object.h; sourceTree = "<group>"; };
- F44DDD8C19C85CFC0047280E /* microdump_processor.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = microdump_processor.h; path = ../../../google_breakpad/processor/microdump_processor.h; sourceTree = "<group>"; };
- F44DDD8D19C85CFC0047280E /* process_result.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = process_result.h; path = ../../../google_breakpad/processor/process_result.h; sourceTree = "<group>"; };
- F47180541D745DEF0032F208 /* elf_reader.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = elf_reader.cc; path = ../../../common/dwarf/elf_reader.cc; sourceTree = "<group>"; };
- F47180551D745DEF0032F208 /* elf_reader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = elf_reader.h; path = ../../../common/dwarf/elf_reader.h; sourceTree = "<group>"; };
- F47180571D7467630032F208 /* proc_maps_linux.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = proc_maps_linux.cc; path = ../../../processor/proc_maps_linux.cc; sourceTree = "<group>"; };
- F47180591D7468A40032F208 /* symbolic_constants_win.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = symbolic_constants_win.cc; path = ../../../processor/symbolic_constants_win.cc; sourceTree = "<group>"; };
- F4D43B2E1A38490700C290B2 /* microdump.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = microdump.cc; path = ../../../processor/microdump.cc; sourceTree = "<group>"; };
- F4D43B301A38492000C290B2 /* microdump.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = microdump.h; path = ../../../google_breakpad/processor/microdump.h; sourceTree = "<group>"; };
- F9C7ECE20E8ABCA600E953AD /* bytereader.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = bytereader.cc; path = ../../../common/dwarf/bytereader.cc; sourceTree = SOURCE_ROOT; };
- F9C7ECE30E8ABCA600E953AD /* dwarf2reader.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = dwarf2reader.cc; path = ../../../common/dwarf/dwarf2reader.cc; sourceTree = SOURCE_ROOT; };
- F9C7ECE40E8ABCA600E953AD /* functioninfo.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = functioninfo.cc; path = ../../../common/dwarf/functioninfo.cc; sourceTree = SOURCE_ROOT; };
- F9F0706510FBC02D0037B88B /* stackwalker_arm.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = stackwalker_arm.cc; path = ../../../processor/stackwalker_arm.cc; sourceTree = SOURCE_ROOT; };
- F9F0706610FBC02D0037B88B /* stackwalker_arm.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = stackwalker_arm.h; path = ../../../processor/stackwalker_arm.h; sourceTree = SOURCE_ROOT; };
- FD6625C40CF4D438004AC844 /* stackwalker_amd64.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = stackwalker_amd64.cc; path = ../../../processor/stackwalker_amd64.cc; sourceTree = SOURCE_ROOT; };
- FD6625C50CF4D438004AC844 /* stackwalker_amd64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = stackwalker_amd64.h; path = ../../../processor/stackwalker_amd64.h; sourceTree = SOURCE_ROOT; };
- FD8EDEAC0CADDAD400A5EDF1 /* stackwalker_sparc.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = stackwalker_sparc.cc; path = ../../../processor/stackwalker_sparc.cc; sourceTree = SOURCE_ROOT; };
- FD8EDEAD0CADDAD400A5EDF1 /* stackwalker_sparc.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = stackwalker_sparc.h; path = ../../../processor/stackwalker_sparc.h; sourceTree = SOURCE_ROOT; };
-/* End PBXFileReference section */
-
-/* Begin PBXFrameworksBuildPhase section */
- 8DD76F9B0486AA7600D96B5E /* Frameworks */ = {
- isa = PBXFrameworksBuildPhase;
- buildActionMask = 2147483647;
- files = (
- 8DD76F9C0486AA7600D96B5E /* Foundation.framework in Frameworks */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
-/* End PBXFrameworksBuildPhase section */
-
-/* Begin PBXGroup section */
- 08FB7794FE84155DC02AAC07 /* crash_report */ = {
- isa = PBXGroup;
- children = (
- 4214B7FE211109A600B769FA /* convert_old_arm64_context.cc */,
- 4214B7FF211109A600B769FA /* convert_old_arm64_context.h */,
- 4247E63F2110D5A500482558 /* path_helper.cc */,
- 4247E63E2110D5A500482558 /* path_helper.h */,
- 8B31025311F0D2D400FCF3E4 /* Breakpad.xcconfig */,
- 8B3102DA11F0D65600FCF3E4 /* BreakpadDebug.xcconfig */,
- 8B3102DB11F0D65600FCF3E4 /* BreakpadRelease.xcconfig */,
- F9C7ECE10E8ABC7F00E953AD /* DWARF */,
- 162F64FC161C5ECB00CD68D5 /* arch_utilities.cc */,
- 162F64FD161C5ECB00CD68D5 /* arch_utilities.h */,
- 5578003E0BE1F28500EC23E0 /* macho_utilities.cc */,
- 5578003F0BE1F28500EC23E0 /* macho_utilities.h */,
- 8B31FF7211F0C6E000FCF3E4 /* macho_reader.cc */,
- 8B31FF7311F0C6E000FCF3E4 /* macho_reader.h */,
- 9BDF192D0B1BC15D00F8391B /* dump_syms.h */,
- 9BDF192E0B1BC15D00F8391B /* dump_syms.cc */,
- 08FB7796FE84155DC02AAC07 /* crash_report.mm */,
- F44DDD8D19C85CFC0047280E /* process_result.h */,
- 9BDF176B0B1B8CB100F8391B /* on_demand_symbol_supplier.h */,
- F44DDD8419C85CD50047280E /* dump_context.cc */,
- F44DDD8A19C85CFB0047280E /* dump_context.h */,
- F44DDD8519C85CD50047280E /* dump_object.cc */,
- F44DDD8B19C85CFB0047280E /* dump_object.h */,
- F4D43B2E1A38490700C290B2 /* microdump.cc */,
- F4D43B301A38492000C290B2 /* microdump.h */,
- F44DDD8619C85CD50047280E /* microdump_processor.cc */,
- F44DDD8C19C85CFC0047280E /* microdump_processor.h */,
- 9BDF176C0B1B8CB100F8391B /* on_demand_symbol_supplier.mm */,
- 8B31FF2411F0C62700FCF3E4 /* dwarf_cfi_to_module.cc */,
- 8B31FF2511F0C62700FCF3E4 /* dwarf_cfi_to_module.h */,
- 8B31FF2611F0C62700FCF3E4 /* dwarf_cu_to_module.cc */,
- 8B31FF2711F0C62700FCF3E4 /* dwarf_cu_to_module.h */,
- 8B31FF2811F0C62700FCF3E4 /* dwarf_line_to_module.cc */,
- 8B31FF2911F0C62700FCF3E4 /* dwarf_line_to_module.h */,
- 8B31FF3D11F0C64400FCF3E4 /* stabs_reader.cc */,
- 8B31FF3E11F0C64400FCF3E4 /* stabs_reader.h */,
- 8B31FF3F11F0C64400FCF3E4 /* stabs_to_module.cc */,
- 8B31FF4011F0C64400FCF3E4 /* stabs_to_module.h */,
- 8B31FF8411F0C6FB00FCF3E4 /* language.cc */,
- 8B31FF8511F0C6FB00FCF3E4 /* language.h */,
- 4D72CA5613DFBA84006CABE3 /* md5.cc */,
- 8B31FF8611F0C6FB00FCF3E4 /* module.cc */,
- 8B31FF8711F0C6FB00FCF3E4 /* module.h */,
- 08FB7795FE84155DC02AAC07 /* breakpad */,
- 4D2C726E126F9CE200B43EAF /* libdisasm */,
- 08FB779DFE84155DC02AAC07 /* External Frameworks and Libraries */,
- 1AB674ADFE9D54B511CA2CBB /* Products */,
- );
- name = crash_report;
- sourceTree = "<group>";
- };
- 08FB7795FE84155DC02AAC07 /* breakpad */ = {
- isa = PBXGroup;
- children = (
- 9BE650AB0B52FE1A00611104 /* common */,
- 9BDF17280B1B8B0200F8391B /* processor */,
- 9BDF16F70B1B8ACD00F8391B /* google_breakpad */,
- );
- name = breakpad;
- sourceTree = "<group>";
- };
- 08FB779DFE84155DC02AAC07 /* External Frameworks and Libraries */ = {
- isa = PBXGroup;
- children = (
- 08FB779EFE84155DC02AAC07 /* Foundation.framework */,
- );
- name = "External Frameworks and Libraries";
- sourceTree = "<group>";
- };
- 1AB674ADFE9D54B511CA2CBB /* Products */ = {
- isa = PBXGroup;
- children = (
- 8DD76FA10486AA7600D96B5E /* crash_report */,
- );
- name = Products;
- sourceTree = "<group>";
- };
- 4D2C726E126F9CE200B43EAF /* libdisasm */ = {
- isa = PBXGroup;
- children = (
- 4D2C7226126F9B0F00B43EAF /* disassembler_x86.cc */,
- 4D2C724B126F9C3800B43EAF /* ia32_implicit.c */,
- 4D2C7245126F9C0B00B43EAF /* ia32_insn.c */,
- 4D2C7232126F9BB000B43EAF /* ia32_invariant.c */,
- 4D2C7261126F9CBB00B43EAF /* ia32_modrm.c */,
- 4D2C7249126F9C2300B43EAF /* ia32_opcode_tables.c */,
- 4D2C725A126F9C8000B43EAF /* ia32_operand.c */,
- 4D2C724D126F9C4D00B43EAF /* ia32_reg.c */,
- 4D2C7234126F9BC200B43EAF /* ia32_settings.c */,
- 4D2C722A126F9B5A00B43EAF /* x86_disasm.c */,
- 4D2C7263126F9CBB00B43EAF /* x86_imm.c */,
- 4D2C725C126F9C9200B43EAF /* x86_insn.c */,
- 4D2C722C126F9B6E00B43EAF /* x86_misc.c */,
- 4D2C722E126F9B8300B43EAF /* x86_operand_list.c */,
- );
- name = libdisasm;
- sourceTree = "<group>";
- };
- 9BDF16F70B1B8ACD00F8391B /* google_breakpad */ = {
- isa = PBXGroup;
- children = (
- 9BDF16F80B1B8ACD00F8391B /* common */,
- 9BDF16FB0B1B8ACD00F8391B /* processor */,
- );
- name = google_breakpad;
- path = ../../../google_breakpad;
- sourceTree = SOURCE_ROOT;
- };
- 9BDF16F80B1B8ACD00F8391B /* common */ = {
- isa = PBXGroup;
- children = (
- 9BDF16F90B1B8ACD00F8391B /* breakpad_types.h */,
- 9BDF16FA0B1B8ACD00F8391B /* minidump_format.h */,
- );
- path = common;
- sourceTree = "<group>";
- };
- 9BDF16FB0B1B8ACD00F8391B /* processor */ = {
- isa = PBXGroup;
- children = (
- 9B3904940B2E52D90059FABE /* basic_source_line_resolver.h */,
- 9BDF16FC0B1B8ACD00F8391B /* call_stack.h */,
- 9B35FEE20B2675F9008DE8C7 /* code_module.h */,
- 9B35FEE30B2675F9008DE8C7 /* code_modules.h */,
- 9BDF16FD0B1B8ACD00F8391B /* memory_region.h */,
- 9BDF16FE0B1B8ACD00F8391B /* minidump.h */,
- 9BDF16FF0B1B8ACD00F8391B /* minidump_processor.h */,
- 9BDF17000B1B8ACD00F8391B /* process_state.h */,
- 9B3904950B2E52D90059FABE /* source_line_resolver_interface.h */,
- 9BDF17010B1B8ACD00F8391B /* stack_frame.h */,
- 9BDF17020B1B8ACD00F8391B /* stack_frame_cpu.h */,
- 9BDF17030B1B8ACD00F8391B /* stackwalker.h */,
- 9BDF17040B1B8ACD00F8391B /* symbol_supplier.h */,
- 9B44619D0B66C66B00BBB817 /* system_info.h */,
- );
- path = processor;
- sourceTree = "<group>";
- };
- 9BDF17280B1B8B0200F8391B /* processor */ = {
- isa = PBXGroup;
- children = (
- 4D2C7222126F9AF900B43EAF /* exploitability_win.cc */,
- F407DC40185773C10064622B /* exploitability_linux.cc */,
- F407DC41185773C10064622B /* stack_frame_symbolizer.cc */,
- F407DC42185773C10064622B /* stackwalker_arm64.cc */,
- F407DC43185773C10064622B /* stackwalker_arm64.h */,
- F407DC44185773C10064622B /* stackwalker_mips.cc */,
- F407DC45185773C10064622B /* stackwalker_mips.h */,
- F407DC46185773C10064622B /* stackwalker_ppc64.cc */,
- F407DC47185773C10064622B /* stackwalker_ppc64.h */,
- 4D2C721E126F9ADE00B43EAF /* exploitability.cc */,
- 4D2C721A126F9ACC00B43EAF /* source_line_resolver_base.cc */,
- D2A5DD621188658B00081F03 /* tokenize.cc */,
- D2A5DD4C1188651100081F03 /* cfi_frame_info.cc */,
- F9F0706510FBC02D0037B88B /* stackwalker_arm.cc */,
- F9F0706610FBC02D0037B88B /* stackwalker_arm.h */,
- 9B3904980B2E52FD0059FABE /* basic_source_line_resolver.cc */,
- 9BDF1AFA0B1BEB6300F8391B /* address_map-inl.h */,
- 9BDF1AFB0B1BEB6300F8391B /* address_map.h */,
- 9B35FEE60B26761C008DE8C7 /* basic_code_module.h */,
- 9B35FEE70B26761C008DE8C7 /* basic_code_modules.cc */,
- 9B35FEE80B26761C008DE8C7 /* basic_code_modules.h */,
- 9BDF172A0B1B8B2400F8391B /* call_stack.cc */,
- 8B40BDBF0C0638E4009535AF /* logging.cc */,
- 9BDF173F0B1B8B9A00F8391B /* minidump.cc */,
- 9BDF172B0B1B8B2400F8391B /* minidump_processor.cc */,
- 9BDF1A270B1BD58200F8391B /* pathname_stripper.cc */,
- F47180571D7467630032F208 /* proc_maps_linux.cc */,
- 9BDF175B0B1B8C1B00F8391B /* process_state.cc */,
- 9BDF1A7A0B1BE30100F8391B /* range_map-inl.h */,
- 9BDF1A7B0B1BE30100F8391B /* range_map.h */,
- 9BDF17530B1B8BF900F8391B /* stackwalker.cc */,
- 9BDF17510B1B8BF900F8391B /* stackwalker_ppc.cc */,
- 9BDF17520B1B8BF900F8391B /* stackwalker_x86.cc */,
- FD8EDEAC0CADDAD400A5EDF1 /* stackwalker_sparc.cc */,
- FD8EDEAD0CADDAD400A5EDF1 /* stackwalker_sparc.h */,
- FD6625C40CF4D438004AC844 /* stackwalker_amd64.cc */,
- FD6625C50CF4D438004AC844 /* stackwalker_amd64.h */,
- F47180591D7468A40032F208 /* symbolic_constants_win.cc */,
- );
- name = processor;
- sourceTree = "<group>";
- };
- 9BE650AB0B52FE1A00611104 /* common */ = {
- isa = PBXGroup;
- children = (
- 9BE650AC0B52FE3000611104 /* file_id.cc */,
- 9BE650AD0B52FE3000611104 /* file_id.h */,
- 9BE650AE0B52FE3000611104 /* macho_id.cc */,
- 9BE650AF0B52FE3000611104 /* macho_id.h */,
- 9BE650B00B52FE3000611104 /* macho_walker.cc */,
- 9BE650B10B52FE3000611104 /* macho_walker.h */,
- );
- name = common;
- sourceTree = "<group>";
- };
- F9C7ECE10E8ABC7F00E953AD /* DWARF */ = {
- isa = PBXGroup;
- children = (
- F9C7ECE20E8ABCA600E953AD /* bytereader.cc */,
- F9C7ECE30E8ABCA600E953AD /* dwarf2reader.cc */,
- 8B31FFC311F0C8AB00FCF3E4 /* dwarf2diehandler.cc */,
- 8B31FFC411F0C8AB00FCF3E4 /* dwarf2diehandler.h */,
- F47180541D745DEF0032F208 /* elf_reader.cc */,
- F47180551D745DEF0032F208 /* elf_reader.h */,
- F9C7ECE40E8ABCA600E953AD /* functioninfo.cc */,
- );
- name = DWARF;
- sourceTree = "<group>";
- };
-/* End PBXGroup section */
-
-/* Begin PBXNativeTarget section */
- 8DD76F960486AA7600D96B5E /* crash_report */ = {
- isa = PBXNativeTarget;
- buildConfigurationList = 1DEB927408733DD40010E9CD /* Build configuration list for PBXNativeTarget "crash_report" */;
- buildPhases = (
- 8DD76F990486AA7600D96B5E /* Sources */,
- 8DD76F9B0486AA7600D96B5E /* Frameworks */,
- );
- buildRules = (
- );
- dependencies = (
- );
- name = crash_report;
- productInstallPath = "$(HOME)/bin";
- productName = crash_report;
- productReference = 8DD76FA10486AA7600D96B5E /* crash_report */;
- productType = "com.apple.product-type.tool";
- };
-/* End PBXNativeTarget section */
-
-/* Begin PBXProject section */
- 08FB7793FE84155DC02AAC07 /* Project object */ = {
- isa = PBXProject;
- attributes = {
- };
- buildConfigurationList = 1DEB927808733DD40010E9CD /* Build configuration list for PBXProject "crash_report" */;
- compatibilityVersion = "Xcode 3.1";
- developmentRegion = en;
- hasScannedForEncodings = 1;
- knownRegions = (
- English,
- Japanese,
- French,
- German,
- );
- mainGroup = 08FB7794FE84155DC02AAC07 /* crash_report */;
- projectDirPath = "";
- projectRoot = "";
- targets = (
- 8DD76F960486AA7600D96B5E /* crash_report */,
- );
- };
-/* End PBXProject section */
-
-/* Begin PBXSourcesBuildPhase section */
- 8DD76F990486AA7600D96B5E /* Sources */ = {
- isa = PBXSourcesBuildPhase;
- buildActionMask = 2147483647;
- files = (
- 162F64FE161C5ECB00CD68D5 /* arch_utilities.cc in Sources */,
- 8DD76F9A0486AA7600D96B5E /* crash_report.mm in Sources */,
- F47180581D7467630032F208 /* proc_maps_linux.cc in Sources */,
- 9BDF172C0B1B8B2400F8391B /* call_stack.cc in Sources */,
- 9BDF172D0B1B8B2400F8391B /* minidump_processor.cc in Sources */,
- 9BDF17410B1B8B9A00F8391B /* minidump.cc in Sources */,
- F44DDD8719C85CD50047280E /* dump_context.cc in Sources */,
- 9BDF17540B1B8BF900F8391B /* stackwalker_ppc.cc in Sources */,
- 9BDF17550B1B8BF900F8391B /* stackwalker_x86.cc in Sources */,
- 9BDF17560B1B8BF900F8391B /* stackwalker.cc in Sources */,
- 9BDF175D0B1B8C1B00F8391B /* process_state.cc in Sources */,
- F47180561D745DEF0032F208 /* elf_reader.cc in Sources */,
- 9BDF176E0B1B8CB100F8391B /* on_demand_symbol_supplier.mm in Sources */,
- 9BDF1A280B1BD58200F8391B /* pathname_stripper.cc in Sources */,
- 9BDF21A70B1E825400F8391B /* dump_syms.cc in Sources */,
- 9B35FEEA0B26761C008DE8C7 /* basic_code_modules.cc in Sources */,
- 9B3904990B2E52FD0059FABE /* basic_source_line_resolver.cc in Sources */,
- 9BE650B20B52FE3000611104 /* file_id.cc in Sources */,
- 9BE650B40B52FE3000611104 /* macho_id.cc in Sources */,
- 9BE650B60B52FE3000611104 /* macho_walker.cc in Sources */,
- 557800400BE1F28500EC23E0 /* macho_utilities.cc in Sources */,
- 8B40BDC00C0638E4009535AF /* logging.cc in Sources */,
- FD8EDEAE0CADDAD400A5EDF1 /* stackwalker_sparc.cc in Sources */,
- FD6625CD0CF4D45C004AC844 /* stackwalker_amd64.cc in Sources */,
- F9C7ECE50E8ABCA600E953AD /* bytereader.cc in Sources */,
- F9C7ECE60E8ABCA600E953AD /* dwarf2reader.cc in Sources */,
- F9C7ECE70E8ABCA600E953AD /* functioninfo.cc in Sources */,
- F9F0706710FBC02D0037B88B /* stackwalker_arm.cc in Sources */,
- D2A5DD4D1188651100081F03 /* cfi_frame_info.cc in Sources */,
- D2A5DD631188658B00081F03 /* tokenize.cc in Sources */,
- 8B31FF2A11F0C62700FCF3E4 /* dwarf_cfi_to_module.cc in Sources */,
- F4D43B2F1A38490700C290B2 /* microdump.cc in Sources */,
- 8B31FF2B11F0C62700FCF3E4 /* dwarf_cu_to_module.cc in Sources */,
- F44DDD8819C85CD50047280E /* dump_object.cc in Sources */,
- 8B31FF2C11F0C62700FCF3E4 /* dwarf_line_to_module.cc in Sources */,
- 8B31FF4111F0C64400FCF3E4 /* stabs_reader.cc in Sources */,
- 8B31FF4211F0C64400FCF3E4 /* stabs_to_module.cc in Sources */,
- 8B31FF7411F0C6E000FCF3E4 /* macho_reader.cc in Sources */,
- 8B31FF8811F0C6FB00FCF3E4 /* language.cc in Sources */,
- 8B31FF8911F0C6FB00FCF3E4 /* module.cc in Sources */,
- 8B31FFC511F0C8AB00FCF3E4 /* dwarf2diehandler.cc in Sources */,
- F407DC49185773C10064622B /* stack_frame_symbolizer.cc in Sources */,
- F471805A1D7468A40032F208 /* symbolic_constants_win.cc in Sources */,
- 4D2C721B126F9ACC00B43EAF /* source_line_resolver_base.cc in Sources */,
- 4D2C721F126F9ADE00B43EAF /* exploitability.cc in Sources */,
- 4D2C7223126F9AF900B43EAF /* exploitability_win.cc in Sources */,
- 4D2C7227126F9B0F00B43EAF /* disassembler_x86.cc in Sources */,
- F407DC48185773C10064622B /* exploitability_linux.cc in Sources */,
- 4214B800211109A600B769FA /* convert_old_arm64_context.cc in Sources */,
- 4D2C722B126F9B5A00B43EAF /* x86_disasm.c in Sources */,
- 4D2C722D126F9B6E00B43EAF /* x86_misc.c in Sources */,
- 4D2C722F126F9B8300B43EAF /* x86_operand_list.c in Sources */,
- F407DC4A185773C10064622B /* stackwalker_arm64.cc in Sources */,
- 4D2C7233126F9BB000B43EAF /* ia32_invariant.c in Sources */,
- 4D2C7235126F9BC200B43EAF /* ia32_settings.c in Sources */,
- 4D2C7246126F9C0B00B43EAF /* ia32_insn.c in Sources */,
- 4D2C724A126F9C2300B43EAF /* ia32_opcode_tables.c in Sources */,
- 4D2C724C126F9C3800B43EAF /* ia32_implicit.c in Sources */,
- 4247E6402110D5A500482558 /* path_helper.cc in Sources */,
- F44DDD8919C85CD50047280E /* microdump_processor.cc in Sources */,
- 4D2C724E126F9C4D00B43EAF /* ia32_reg.c in Sources */,
- 4D2C725B126F9C8000B43EAF /* ia32_operand.c in Sources */,
- F407DC4C185773C10064622B /* stackwalker_ppc64.cc in Sources */,
- 4D2C725D126F9C9200B43EAF /* x86_insn.c in Sources */,
- 4D2C7264126F9CBB00B43EAF /* ia32_modrm.c in Sources */,
- F407DC4B185773C10064622B /* stackwalker_mips.cc in Sources */,
- 4D2C726D126F9CDC00B43EAF /* x86_imm.c in Sources */,
- 4D72CA5713DFBA84006CABE3 /* md5.cc in Sources */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
-/* End PBXSourcesBuildPhase section */
-
-/* Begin XCBuildConfiguration section */
- 1DEB927508733DD40010E9CD /* Debug */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- CLANG_CXX_LANGUAGE_STANDARD = "c++0x";
- HEADER_SEARCH_PATHS = ../../../../src;
- PRODUCT_NAME = crash_report;
- };
- name = Debug;
- };
- 1DEB927608733DD40010E9CD /* Release */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- CLANG_CXX_LANGUAGE_STANDARD = "c++0x";
- HEADER_SEARCH_PATHS = ../../../../src;
- PRODUCT_NAME = crash_report;
- };
- name = Release;
- };
- 1DEB927908733DD40010E9CD /* Debug */ = {
- isa = XCBuildConfiguration;
- baseConfigurationReference = 8B3102DA11F0D65600FCF3E4 /* BreakpadDebug.xcconfig */;
- buildSettings = {
- GCC_PREPROCESSOR_DEFINITIONS = HAVE_MACH_O_NLIST_H;
- GCC_TREAT_WARNINGS_AS_ERRORS = NO;
- };
- name = Debug;
- };
- 1DEB927A08733DD40010E9CD /* Release */ = {
- isa = XCBuildConfiguration;
- baseConfigurationReference = 8B3102DB11F0D65600FCF3E4 /* BreakpadRelease.xcconfig */;
- buildSettings = {
- GCC_PREPROCESSOR_DEFINITIONS = HAVE_MACH_O_NLIST_H;
- };
- name = Release;
- };
-/* End XCBuildConfiguration section */
-
-/* Begin XCConfigurationList section */
- 1DEB927408733DD40010E9CD /* Build configuration list for PBXNativeTarget "crash_report" */ = {
- isa = XCConfigurationList;
- buildConfigurations = (
- 1DEB927508733DD40010E9CD /* Debug */,
- 1DEB927608733DD40010E9CD /* Release */,
- );
- defaultConfigurationIsVisible = 0;
- defaultConfigurationName = Release;
- };
- 1DEB927808733DD40010E9CD /* Build configuration list for PBXProject "crash_report" */ = {
- isa = XCConfigurationList;
- buildConfigurations = (
- 1DEB927908733DD40010E9CD /* Debug */,
- 1DEB927A08733DD40010E9CD /* Release */,
- );
- defaultConfigurationIsVisible = 0;
- defaultConfigurationName = Release;
- };
-/* End XCConfigurationList section */
- };
- rootObject = 08FB7793FE84155DC02AAC07 /* Project object */;
-}
diff --git a/src/tools/mac/crash_report/on_demand_symbol_supplier.h b/src/tools/mac/crash_report/on_demand_symbol_supplier.h
deleted file mode 100644
index 3fbe108e..00000000
--- a/src/tools/mac/crash_report/on_demand_symbol_supplier.h
+++ /dev/null
@@ -1,111 +0,0 @@
-// Copyright (c) 2006, Google Inc.
-// All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-// on_demand_symbol_supplier.h: Provides a Symbol Supplier that will create
-// a breakpad symbol file on demand.
-
-#ifndef TOOLS_MAC_CRASH_REPORT_ON_DEMAND_SYMBOL_SUPPLIER_H__
-#define TOOLS_MAC_CRASH_REPORT_ON_DEMAND_SYMBOL_SUPPLIER_H__
-
-#include <map>
-#include <string>
-#include "google_breakpad/processor/symbol_supplier.h"
-
-namespace google_breakpad {
-
-using std::map;
-using std::string;
-class MinidumpModule;
-
-class OnDemandSymbolSupplier : public SymbolSupplier {
- public:
- // |search_dir| is the directory to search for alternative symbols with
- // the same name as the module in the minidump
- OnDemandSymbolSupplier(const string &search_dir,
- const string &symbol_search_dir);
- virtual ~OnDemandSymbolSupplier() {}
-
- // Returns the path to the symbol file for the given module.
- virtual SymbolResult GetSymbolFile(const CodeModule *module,
- const SystemInfo *system_info,
- string *symbol_file);
-
- // Returns the path to the symbol file for the given module.
- virtual SymbolResult GetSymbolFile(const CodeModule *module,
- const SystemInfo *system_info,
- string *symbol_file,
- string *symbol_data);
- // Allocates data buffer on heap, and takes the ownership of
- // the data buffer.
- virtual SymbolResult GetCStringSymbolData(const CodeModule *module,
- const SystemInfo *system_info,
- string *symbol_file,
- char **symbol_data,
- size_t *symbol_data_size);
-
- // Delete the data buffer allocated for module in GetCStringSymbolData().
- virtual void FreeSymbolData(const CodeModule *module);
-
- protected:
- // Search directory
- string search_dir_;
- string symbol_search_dir_;
-
- // When we create a symbol file for a module, save the name of the module
- // and the path to that module's symbol file.
- map<string, string> module_file_map_;
-
- // Map of allocated data buffers, keyed by module->code_file().
- map<string, char *> memory_buffers_;
-
- // Return the name for |module| This will be the value used as the key
- // to the |module_file_map_|.
- string GetNameForModule(const CodeModule *module);
-
- // Find the module on local system. If the module resides in a different
- // location than the full path in the minidump, this will be the location
- // used.
- string GetLocalModulePath(const CodeModule *module);
-
- // Return the full path for |module|.
- string GetModulePath(const CodeModule *module);
-
- // Return the path to the symbol file for |module|. If an empty string is
- // returned, then |module| doesn't have a symbol file.
- string GetModuleSymbolFile(const CodeModule *module);
-
- // Generate the breakpad symbol file for |module|. Return true if successful.
- // File is generated in /tmp.
- bool GenerateSymbolFile(const CodeModule *module,
- const SystemInfo *system_info);
-};
-
-} // namespace google_breakpad
-
-#endif // TOOLS_MAC_CRASH_REPORT_ON_DEMAND_SYMBOL_SUPPLIER_H__
diff --git a/src/tools/mac/crash_report/on_demand_symbol_supplier.mm b/src/tools/mac/crash_report/on_demand_symbol_supplier.mm
deleted file mode 100644
index 1955d266..00000000
--- a/src/tools/mac/crash_report/on_demand_symbol_supplier.mm
+++ /dev/null
@@ -1,314 +0,0 @@
-// Copyright (c) 2006, Google Inc.
-// All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-#import <Foundation/Foundation.h>
-#include <sys/stat.h>
-#include <map>
-#include <string>
-#include <iostream>
-#include <fstream>
-#include <utility>
-
-#include "google_breakpad/processor/basic_source_line_resolver.h"
-#include "google_breakpad/processor/minidump.h"
-#include "google_breakpad/processor/system_info.h"
-#include "processor/pathname_stripper.h"
-
-#include "on_demand_symbol_supplier.h"
-#include "common/mac/dump_syms.h"
-
-using std::map;
-using std::string;
-
-using google_breakpad::OnDemandSymbolSupplier;
-using google_breakpad::PathnameStripper;
-using google_breakpad::SymbolSupplier;
-using google_breakpad::SystemInfo;
-
-OnDemandSymbolSupplier::OnDemandSymbolSupplier(const string &search_dir,
- const string &symbol_search_dir)
- : search_dir_(search_dir) {
- NSFileManager *mgr = [NSFileManager defaultManager];
- size_t length = symbol_search_dir.length();
- if (length) {
- // Load all sym files in symbol_search_dir into our module_file_map
- // A symbol file always starts with a line like this:
- // MODULE mac x86 BBF0A8F9BEADDD2048E6464001CA193F0 GoogleDesktopDaemon
- // or
- // MODULE mac ppc BBF0A8F9BEADDD2048E6464001CA193F0 GoogleDesktopDaemon
- const char *symbolSearchStr = symbol_search_dir.c_str();
- NSString *symbolSearchPath =
- [mgr stringWithFileSystemRepresentation:symbolSearchStr
- length:strlen(symbolSearchStr)];
- NSDirectoryEnumerator *dirEnum = [mgr enumeratorAtPath:symbolSearchPath];
- NSString *fileName;
- NSCharacterSet *hexSet =
- [NSCharacterSet characterSetWithCharactersInString:@"0123456789ABCDEF"];
- NSCharacterSet *newlineSet =
- [NSCharacterSet characterSetWithCharactersInString:@"\r\n"];
- while ((fileName = [dirEnum nextObject])) {
- // Check to see what type of file we have
- NSDictionary *attrib = [dirEnum fileAttributes];
- NSString *fileType = [attrib objectForKey:NSFileType];
- if ([fileType isEqualToString:NSFileTypeDirectory]) {
- // Skip subdirectories
- [dirEnum skipDescendents];
- } else {
- NSString *filePath = [symbolSearchPath stringByAppendingPathComponent:fileName];
- NSString *dataStr = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:NULL];
- if (dataStr) {
- // Check file to see if it is of appropriate type, and grab module
- // name.
- NSScanner *scanner = [NSScanner scannerWithString:dataStr];
- BOOL goodScan = [scanner scanString:@"MODULE mac " intoString:nil];
- if (goodScan) {
- goodScan = ([scanner scanString:@"x86 " intoString:nil] ||
- [scanner scanString:@"x86_64 " intoString:nil] ||
- [scanner scanString:@"ppc " intoString:nil]);
- if (goodScan) {
- NSString *moduleID;
- goodScan = [scanner scanCharactersFromSet:hexSet
- intoString:&moduleID];
- if (goodScan) {
- // Module IDs are always 33 chars long
- goodScan = [moduleID length] == 33;
- if (goodScan) {
- NSString *moduleName;
- goodScan = [scanner scanUpToCharactersFromSet:newlineSet
- intoString:&moduleName];
- if (goodScan) {
- goodScan = [moduleName length] > 0;
- if (goodScan) {
- const char *moduleNameStr = [moduleName UTF8String];
- const char *filePathStr = [filePath fileSystemRepresentation];
- // Map our file
- module_file_map_[moduleNameStr] = filePathStr;
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }
-}
-
-SymbolSupplier::SymbolResult
-OnDemandSymbolSupplier::GetSymbolFile(const CodeModule *module,
- const SystemInfo *system_info,
- string *symbol_file) {
- string path(GetModuleSymbolFile(module));
-
- if (path.empty()) {
- if (!GenerateSymbolFile(module, system_info))
- return NOT_FOUND;
-
- path = GetModuleSymbolFile(module);
- }
-
- if (path.empty())
- return NOT_FOUND;
-
- *symbol_file = path;
- return FOUND;
-}
-
-SymbolSupplier::SymbolResult
-OnDemandSymbolSupplier::GetSymbolFile(const CodeModule *module,
- const SystemInfo *system_info,
- string *symbol_file,
- string *symbol_data) {
- SymbolSupplier::SymbolResult s = GetSymbolFile(module,
- system_info,
- symbol_file);
-
-
- if (s == FOUND) {
- std::ifstream in(symbol_file->c_str());
- getline(in, *symbol_data, std::string::traits_type::to_char_type(
- std::string::traits_type::eof()));
- in.close();
- }
-
- return s;
-}
-
-SymbolSupplier::SymbolResult
-OnDemandSymbolSupplier::GetCStringSymbolData(const CodeModule *module,
- const SystemInfo *system_info,
- string *symbol_file,
- char **symbol_data,
- size_t *symbol_data_size) {
- std::string symbol_data_string;
- SymbolSupplier::SymbolResult result = GetSymbolFile(module,
- system_info,
- symbol_file,
- &symbol_data_string);
- if (result == FOUND) {
- *symbol_data_size = symbol_data_string.size() + 1;
- *symbol_data = new char[*symbol_data_size];
- if (*symbol_data == NULL) {
- // Should return INTERRUPT on memory allocation failure.
- return INTERRUPT;
- }
- memcpy(*symbol_data, symbol_data_string.c_str(), symbol_data_string.size());
- (*symbol_data)[symbol_data_string.size()] = '\0';
- memory_buffers_.insert(make_pair(module->code_file(), *symbol_data));
- }
- return result;
-}
-
-void OnDemandSymbolSupplier::FreeSymbolData(const CodeModule *module) {
- map<string, char *>::iterator it = memory_buffers_.find(module->code_file());
- if (it != memory_buffers_.end()) {
- delete [] it->second;
- memory_buffers_.erase(it);
- }
-}
-
-string OnDemandSymbolSupplier::GetLocalModulePath(const CodeModule *module) {
- NSFileManager *mgr = [NSFileManager defaultManager];
- const char *moduleStr = module->code_file().c_str();
- NSString *modulePath =
- [mgr stringWithFileSystemRepresentation:moduleStr length:strlen(moduleStr)];
- const char *searchStr = search_dir_.c_str();
- NSString *searchDir =
- [mgr stringWithFileSystemRepresentation:searchStr length:strlen(searchStr)];
-
- if ([mgr fileExistsAtPath:modulePath])
- return module->code_file();
-
- // If the module is not found, try to start appending the components to the
- // search string and stop if a file (not dir) is found or all components
- // have been appended
- NSArray *pathComponents = [modulePath componentsSeparatedByString:@"/"];
- size_t count = [pathComponents count];
- NSMutableString *path = [NSMutableString string];
-
- for (size_t i = 0; i < count; ++i) {
- [path setString:searchDir];
-
- for (size_t j = 0; j < i + 1; ++j) {
- size_t idx = count - 1 - i + j;
- [path appendFormat:@"/%@", [pathComponents objectAtIndex:idx]];
- }
-
- BOOL isDir;
- if ([mgr fileExistsAtPath:path isDirectory:&isDir] && (!isDir)) {
- return [path fileSystemRepresentation];
- }
- }
-
- return "";
-}
-
-string OnDemandSymbolSupplier::GetModulePath(const CodeModule *module) {
- return module->code_file();
-}
-
-string OnDemandSymbolSupplier::GetNameForModule(const CodeModule *module) {
- return PathnameStripper::File(module->code_file());
-}
-
-string OnDemandSymbolSupplier::GetModuleSymbolFile(const CodeModule *module) {
- string name(GetNameForModule(module));
- map<string, string>::iterator result = module_file_map_.find(name);
-
- return (result == module_file_map_.end()) ? "" : (*result).second;
-}
-
-static float GetFileModificationTime(const char *path) {
- float result = 0;
- struct stat file_stat;
- if (stat(path, &file_stat) == 0)
- result = (float)file_stat.st_mtimespec.tv_sec +
- (float)file_stat.st_mtimespec.tv_nsec / 1.0e9f;
-
- return result;
-}
-
-bool OnDemandSymbolSupplier::GenerateSymbolFile(const CodeModule *module,
- const SystemInfo *system_info) {
- bool result = true;
- string name = GetNameForModule(module);
- string module_path = GetLocalModulePath(module);
- NSString *symbol_path = [NSString stringWithFormat:@"/tmp/%s.%s.sym",
- name.c_str(), system_info->cpu.c_str()];
-
- if (module_path.empty())
- return false;
-
- // Check if there's already a symbol file cached. Ensure that the file is
- // newer than the module. Otherwise, generate a new one.
- BOOL generate_file = YES;
- if ([[NSFileManager defaultManager] fileExistsAtPath:symbol_path]) {
- // Check if the module file is newer than the saved symbols
- float cache_time =
- GetFileModificationTime([symbol_path fileSystemRepresentation]);
- float module_time =
- GetFileModificationTime(module_path.c_str());
-
- if (cache_time > module_time)
- generate_file = NO;
- }
-
- if (generate_file) {
- DumpSymbols dump(ALL_SYMBOL_DATA, false);
- if (dump.Read(module_path)) {
- // What Breakpad calls "x86" should be given to the system as "i386".
- std::string architecture;
- if (system_info->cpu.compare("x86") == 0) {
- architecture = "i386";
- } else {
- architecture = system_info->cpu;
- }
-
- if (dump.SetArchitecture(architecture)) {
- std::fstream file([symbol_path fileSystemRepresentation],
- std::ios_base::out | std::ios_base::trunc);
- dump.WriteSymbolFile(file);
- } else {
- printf("Architecture %s not available for %s\n",
- system_info->cpu.c_str(), name.c_str());
- result = false;
- }
- } else {
- printf("Unable to open %s\n", module_path.c_str());
- result = false;
- }
- }
-
- // Add the mapping
- if (result)
- module_file_map_[name] = [symbol_path fileSystemRepresentation];
-
- return result;
-}
diff --git a/src/tools/mac/dump_syms/dump_syms_tool.cc b/src/tools/mac/dump_syms/dump_syms_tool.cc
index 6f68457b..2e05cbf3 100644
--- a/src/tools/mac/dump_syms/dump_syms_tool.cc
+++ b/src/tools/mac/dump_syms/dump_syms_tool.cc
@@ -1,7 +1,6 @@
// -*- mode: c++ -*-
-// Copyright (c) 2011, Google Inc.
-// All rights reserved.
+// Copyright 2011 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -13,7 +12,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -37,6 +36,8 @@
#include <algorithm>
#include <iostream>
+#include <memory>
+#include <utility>
#include <vector>
#include "common/mac/dump_syms.h"
@@ -51,8 +52,14 @@ using std::vector;
struct Options {
Options()
- : srcPath(), dsymPath(), arch(), header_only(false),
- cfi(true), handle_inter_cu_refs(true) {}
+ : srcPath(),
+ dsymPath(),
+ arch(),
+ header_only(false),
+ cfi(true),
+ handle_inter_cu_refs(true),
+ handle_inlines(false),
+ enable_multiple(false) {}
string srcPath;
string dsymPath;
@@ -60,6 +67,8 @@ struct Options {
bool header_only;
bool cfi;
bool handle_inter_cu_refs;
+ bool handle_inlines;
+ bool enable_multiple;
};
static bool StackFrameEntryComparator(const Module::StackFrameEntry* a,
@@ -101,14 +110,47 @@ static void CopyCFIDataBetweenModules(Module* to_module,
// If the entry does not overlap, then it is safe to copy to |to_module|.
if (to_it == to_data.end() || (from_entry->address < (*to_it)->address &&
from_entry_end < (*to_it)->address)) {
- to_module->AddStackFrameEntry(new Module::StackFrameEntry(*from_entry));
+ to_module->AddStackFrameEntry(
+ std::make_unique<Module::StackFrameEntry>(*from_entry));
}
}
}
-static bool Start(const Options &options) {
- SymbolData symbol_data = options.cfi ? ALL_SYMBOL_DATA : NO_CFI;
- DumpSymbols dump_symbols(symbol_data, options.handle_inter_cu_refs);
+static bool SetArchitecture(DumpSymbols& dump_symbols,
+ const NXArchInfo* arch,
+ const std::string& filename) {
+ if (!dump_symbols.SetArchitecture(arch->cputype, arch->cpusubtype)) {
+ fprintf(stderr, "%s: no architecture '%s' is present in file.\n",
+ filename.c_str(), arch->name);
+ size_t available_size;
+ const SuperFatArch* available =
+ dump_symbols.AvailableArchitectures(&available_size);
+ if (available_size == 1)
+ fprintf(stderr, "the file's architecture is: ");
+ else
+ fprintf(stderr, "architectures present in the file are:\n");
+ for (size_t i = 0; i < available_size; i++) {
+ const SuperFatArch* arch = &available[i];
+ const NXArchInfo* arch_info =
+ google_breakpad::BreakpadGetArchInfoFromCpuType(arch->cputype,
+ arch->cpusubtype);
+ if (arch_info)
+ fprintf(stderr, "%s (%s)\n", arch_info->name, arch_info->description);
+ else
+ fprintf(stderr, "unrecognized cpu type 0x%x, subtype 0x%x\n",
+ arch->cputype, arch->cpusubtype);
+ }
+ return false;
+ }
+ return true;
+}
+
+static bool Start(const Options& options) {
+ SymbolData symbol_data =
+ (options.handle_inlines ? INLINES : NO_DATA) |
+ (options.cfi ? CFI : NO_DATA) | SYMBOLS_AND_FILES;
+ DumpSymbols dump_symbols(symbol_data, options.handle_inter_cu_refs,
+ options.enable_multiple);
// For x86_64 binaries, the CFI data is in the __TEXT,__eh_frame of the
// Mach-O file, which is not copied into the dSYM. Whereas in i386, the CFI
@@ -126,31 +168,9 @@ static bool Start(const Options &options) {
if (!dump_symbols.Read(primary_file))
return false;
- if (options.arch) {
- if (!dump_symbols.SetArchitecture(options.arch->cputype,
- options.arch->cpusubtype)) {
- fprintf(stderr, "%s: no architecture '%s' is present in file.\n",
- primary_file.c_str(), options.arch->name);
- size_t available_size;
- const SuperFatArch *available =
- dump_symbols.AvailableArchitectures(&available_size);
- if (available_size == 1)
- fprintf(stderr, "the file's architecture is: ");
- else
- fprintf(stderr, "architectures present in the file are:\n");
- for (size_t i = 0; i < available_size; i++) {
- const SuperFatArch *arch = &available[i];
- const NXArchInfo *arch_info =
- google_breakpad::BreakpadGetArchInfoFromCpuType(
- arch->cputype, arch->cpusubtype);
- if (arch_info)
- fprintf(stderr, "%s (%s)\n", arch_info->name, arch_info->description);
- else
- fprintf(stderr, "unrecognized cpu type 0x%x, subtype 0x%x\n",
- arch->cputype, arch->cpusubtype);
- }
- return false;
- }
+ if (options.arch &&
+ !SetArchitecture(dump_symbols, options.arch, primary_file)) {
+ return false;
}
if (options.header_only)
@@ -168,6 +188,10 @@ static bool Start(const Options &options) {
if (!dump_symbols.Read(options.srcPath))
return false;
+ if (options.arch &&
+ !SetArchitecture(dump_symbols, options.arch, options.srcPath)) {
+ return false;
+ }
Module* cfi_module = NULL;
if (!dump_symbols.ReadSymbolData(&cfi_module))
return false;
@@ -201,6 +225,10 @@ static void Usage(int argc, const char *argv[]) {
"Mach-o file\n");
fprintf(stderr, "\t-c: Do not generate CFI section\n");
fprintf(stderr, "\t-r: Do not handle inter-compilation unit references\n");
+ fprintf(stderr, "\t-d: Generate INLINE and INLINE_ORIGIN records\n");
+ fprintf(stderr,
+ "\t-m: Enable writing the optional 'm' field on FUNC "
+ "and PUBLIC, denoting multiple symbols for the address.\n");
fprintf(stderr, "\t-h: Usage\n");
fprintf(stderr, "\t-?: Usage\n");
}
@@ -210,7 +238,7 @@ static void SetupOptions(int argc, const char *argv[], Options *options) {
extern int optind;
signed char ch;
- while ((ch = getopt(argc, (char * const *)argv, "ia:g:chr?")) != -1) {
+ while ((ch = getopt(argc, (char* const*)argv, "ia:g:crdm?h")) != -1) {
switch (ch) {
case 'i':
options->header_only = true;
@@ -235,6 +263,12 @@ static void SetupOptions(int argc, const char *argv[], Options *options) {
case 'r':
options->handle_inter_cu_refs = false;
break;
+ case 'd':
+ options->handle_inlines = true;
+ break;
+ case 'm':
+ options->enable_multiple = true;
+ break;
case '?':
case 'h':
Usage(argc, argv);
diff --git a/src/tools/mac/dump_syms/macho_dump.cc b/src/tools/mac/dump_syms/macho_dump.cc
index 6e784ca7..b724cc74 100644
--- a/src/tools/mac/dump_syms/macho_dump.cc
+++ b/src/tools/mac/dump_syms/macho_dump.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2010, Google Inc.
-// All rights reserved.
+// Copyright 2010 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -60,7 +59,7 @@ namespace mach_o = google_breakpad::mach_o;
string program_name;
-int check_syscall(int result, const char *operation, const char *filename) {
+int check_syscall(int result, const char* operation, const char* filename) {
if (result < 0) {
fprintf(stderr, "%s: %s '%s': %s\n",
program_name.c_str(), operation,
@@ -73,7 +72,7 @@ int check_syscall(int result, const char *operation, const char *filename) {
class DumpSection: public mach_o::Reader::SectionHandler {
public:
DumpSection() : index_(0) { }
- bool HandleSection(const mach_o::Section &section) {
+ bool HandleSection(const mach_o::Section& section) {
printf(" section %d '%s' in segment '%s'\n"
" address: 0x%llx\n"
" alignment: 1 << %d B\n"
@@ -92,13 +91,13 @@ class DumpSection: public mach_o::Reader::SectionHandler {
class DumpCommand: public mach_o::Reader::LoadCommandHandler {
public:
- DumpCommand(mach_o::Reader *reader) : reader_(reader), index_(0) { }
+ DumpCommand(mach_o::Reader* reader) : reader_(reader), index_(0) { }
bool UnknownCommand(mach_o::LoadCommandType type,
- const ByteBuffer &contents) {
+ const ByteBuffer& contents) {
printf(" load command %d: %d", index_++, type);
return true;
}
- bool SegmentCommand(const mach_o::Segment &segment) {
+ bool SegmentCommand(const mach_o::Segment& segment) {
printf(" load command %d: %s-bit segment '%s'\n"
" address: 0x%llx\n"
" memory size: 0x%llx\n"
@@ -115,24 +114,24 @@ class DumpCommand: public mach_o::Reader::LoadCommandHandler {
return reader_->WalkSegmentSections(segment, &dump_section);
}
private:
- mach_o::Reader *reader_;
+ mach_o::Reader* reader_;
int index_;
};
-void DumpFile(const char *filename) {
+void DumpFile(const char* filename) {
int fd = check_syscall(open(filename, O_RDONLY), "opening", filename);
struct stat attributes;
check_syscall(fstat(fd, &attributes),
"getting file attributes for", filename);
- void *mapping = mmap(NULL, attributes.st_size, PROT_READ,
+ void* mapping = mmap(NULL, attributes.st_size, PROT_READ,
MAP_PRIVATE, fd, 0);
close(fd);
- check_syscall(mapping == (void *)-1 ? -1 : 0,
+ check_syscall(mapping == (void*)-1 ? -1 : 0,
"mapping contents of", filename);
mach_o::FatReader::Reporter fat_reporter(filename);
mach_o::FatReader fat_reader(&fat_reporter);
- if (!fat_reader.Read(reinterpret_cast<uint8_t *>(mapping),
+ if (!fat_reader.Read(reinterpret_cast<uint8_t*>(mapping),
attributes.st_size)) {
exit(1);
}
@@ -140,14 +139,14 @@ void DumpFile(const char *filename) {
size_t object_files_size;
const SuperFatArch* super_fat_object_files =
fat_reader.object_files(&object_files_size);
- struct fat_arch *object_files;
+ struct fat_arch* object_files;
if (!super_fat_object_files->ConvertToFatArch(object_files)) {
exit(1);
}
printf(" object file count: %ld\n", object_files_size);
for (size_t i = 0; i < object_files_size; i++) {
- const struct fat_arch &file = object_files[i];
- const NXArchInfo *fat_arch_info =
+ const struct fat_arch& file = object_files[i];
+ const NXArchInfo* fat_arch_info =
google_breakpad::BreakpadGetArchInfoFromCpuType(
file.cputype, file.cpusubtype);
printf("\n object file %ld:\n"
@@ -162,7 +161,7 @@ void DumpFile(const char *filename) {
name << filename;
if (object_files_size > 1)
name << ", object file #" << i;
- ByteBuffer file_contents(reinterpret_cast<uint8_t *>(mapping)
+ ByteBuffer file_contents(reinterpret_cast<uint8_t*>(mapping)
+ file.offset, file.size);
mach_o::Reader::Reporter reporter(name.str());
mach_o::Reader reader(&reporter);
@@ -170,7 +169,7 @@ void DumpFile(const char *filename) {
exit(1);
}
- const NXArchInfo *macho_arch_info =
+ const NXArchInfo* macho_arch_info =
NXGetArchInfoFromCpuType(reader.cpu_type(),
reader.cpu_subtype());
printf(" Mach-O header:\n"
@@ -190,7 +189,7 @@ void DumpFile(const char *filename) {
} // namespace
-int main(int argc, char **argv) {
+int main(int argc, char** argv) {
program_name = google_breakpad::BaseName(argv[0]);
if (argc == 1) {
fprintf(stderr, "Usage: %s FILE ...\n"
diff --git a/src/tools/mac/symupload/symupload.m b/src/tools/mac/symupload/symupload.m
deleted file mode 100644
index a7cce7b0..00000000
--- a/src/tools/mac/symupload/symupload.m
+++ /dev/null
@@ -1,204 +0,0 @@
-// Copyright (c) 2006, Google Inc.
-// All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-// symupload.m: Upload a symbol file to a HTTP server. The upload is sent as
-// a multipart/form-data POST request with the following parameters:
-// code_file: the basename of the module, e.g. "app"
-// debug_file: the basename of the debugging file, e.g. "app"
-// debug_identifier: the debug file's identifier, usually consisting of
-// the guid and age embedded in the pdb, e.g.
-// "11111111BBBB3333DDDD555555555555F"
-// os: the operating system that the module was built for
-// cpu: the CPU that the module was built for (x86 or ppc)
-// symbol_file: the contents of the breakpad-format symbol file
-
-#include <fcntl.h>
-#include <sys/stat.h>
-#include <unistd.h>
-
-#include <Foundation/Foundation.h>
-#include "HTTPMultipartUpload.h"
-
-typedef struct {
- NSString *symbolsPath;
- NSString *uploadURLStr;
- BOOL success;
-} Options;
-
-//=============================================================================
-static NSArray *ModuleDataForSymbolFile(NSString *file) {
- NSFileHandle *fh = [NSFileHandle fileHandleForReadingAtPath:file];
- NSData *data = [fh readDataOfLength:1024];
- NSString *str = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
- NSScanner *scanner = [NSScanner scannerWithString:str];
- NSString *line;
- NSMutableArray *parts = nil;
- const int MODULE_ID_INDEX = 3;
-
- if ([scanner scanUpToString:@"\n" intoString:&line]) {
- parts = [[NSMutableArray alloc] init];
- NSScanner *moduleInfoScanner = [NSScanner scannerWithString:line];
- NSString *moduleInfo;
- // Get everything BEFORE the module name. None of these properties
- // can have spaces.
- for (int i = 0; i <= MODULE_ID_INDEX; i++) {
- [moduleInfoScanner scanUpToString:@" " intoString:&moduleInfo];
- [parts addObject:moduleInfo];
- }
-
- // Now get the module name. This can have a space so we scan to
- // the end of the line.
- [moduleInfoScanner scanUpToString:@"\n" intoString:&moduleInfo];
- [parts addObject:moduleInfo];
- }
-
- [str release];
-
- return parts;
-}
-
-//=============================================================================
-static void Start(Options *options) {
- NSURL *url = [NSURL URLWithString:options->uploadURLStr];
- HTTPMultipartUpload *ul = [[HTTPMultipartUpload alloc] initWithURL:url];
- NSMutableDictionary *parameters = [NSMutableDictionary dictionary];
- NSArray *moduleParts = ModuleDataForSymbolFile(options->symbolsPath);
- NSMutableString *compactedID =
- [NSMutableString stringWithString:[moduleParts objectAtIndex:3]];
- [compactedID replaceOccurrencesOfString:@"-" withString:@"" options:0
- range:NSMakeRange(0, [compactedID length])];
-
- // Add parameters
- [parameters setObject:compactedID forKey:@"debug_identifier"];
-
- // MODULE <os> <cpu> <uuid> <module-name>
- // 0 1 2 3 4
- [parameters setObject:[moduleParts objectAtIndex:1] forKey:@"os"];
- [parameters setObject:[moduleParts objectAtIndex:2] forKey:@"cpu"];
- [parameters setObject:[moduleParts objectAtIndex:4] forKey:@"debug_file"];
- [parameters setObject:[moduleParts objectAtIndex:4] forKey:@"code_file"];
- [ul setParameters:parameters];
-
- NSArray *keys = [parameters allKeys];
- int count = [keys count];
- for (int i = 0; i < count; ++i) {
- NSString *key = [keys objectAtIndex:i];
- NSString *value = [parameters objectForKey:key];
- fprintf(stdout, "'%s' = '%s'\n", [key UTF8String],
- [value UTF8String]);
- }
-
- // Add file
- [ul addFileAtPath:options->symbolsPath name:@"symbol_file"];
-
- // Send it
- NSError *error = nil;
- NSData *data = [ul send:&error];
- NSString *result = [[NSString alloc] initWithData:data
- encoding:NSUTF8StringEncoding];
- int status = [[ul response] statusCode];
-
- fprintf(stdout, "Send: %s\n", error ? [[error description] UTF8String] :
- "No Error");
- fprintf(stdout, "Response: %d\n", status);
- fprintf(stdout, "Result: %lu bytes\n%s\n",
- (unsigned long)[data length], [result UTF8String]);
-
- [result release];
- [ul release];
- options->success = !error && status==200;
-}
-
-//=============================================================================
-static void
-Usage(int argc, const char *argv[]) {
- fprintf(stderr, "Submit symbol information.\n");
- fprintf(stderr, "Usage: %s <symbols> <upload-URL>\n", argv[0]);
- fprintf(stderr, "<symbols> should be created by using the dump_syms tool.\n");
- fprintf(stderr, "<upload-URL> is the destination for the upload\n");
- fprintf(stderr, "\t-h: Usage\n");
- fprintf(stderr, "\t-?: Usage\n");
-}
-
-//=============================================================================
-static void
-SetupOptions(int argc, const char *argv[], Options *options) {
- extern int optind;
- char ch;
-
- while ((ch = getopt(argc, (char * const *)argv, "h?")) != -1) {
- switch (ch) {
- default:
- Usage(argc, argv);
- exit(0);
- break;
- }
- }
-
- if ((argc - optind) != 2) {
- fprintf(stderr, "%s: Missing symbols file and/or upload-URL\n", argv[0]);
- Usage(argc, argv);
- exit(1);
- }
-
- int fd = open(argv[optind], O_RDONLY);
- if (fd < 0) {
- fprintf(stderr, "%s: %s: %s\n", argv[0], argv[optind], strerror(errno));
- exit(1);
- }
-
- struct stat statbuf;
- if (fstat(fd, &statbuf) < 0) {
- fprintf(stderr, "%s: %s: %s\n", argv[0], argv[optind], strerror(errno));
- close(fd);
- exit(1);
- }
- close(fd);
-
- if (!S_ISREG(statbuf.st_mode)) {
- fprintf(stderr, "%s: %s: not a regular file\n", argv[0], argv[optind]);
- exit(1);
- }
-
- options->symbolsPath = [NSString stringWithUTF8String:argv[optind]];
- options->uploadURLStr = [NSString stringWithUTF8String:argv[optind + 1]];
-}
-
-//=============================================================================
-int main (int argc, const char * argv[]) {
- NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
- Options options;
-
- bzero(&options, sizeof(Options));
- SetupOptions(argc, argv, &options);
- Start(&options);
-
- [pool release];
- return options.success ? 0 : 1;
-}
diff --git a/src/tools/mac/symupload/symupload.mm b/src/tools/mac/symupload/symupload.mm
new file mode 100644
index 00000000..521b811f
--- /dev/null
+++ b/src/tools/mac/symupload/symupload.mm
@@ -0,0 +1,474 @@
+// Copyright 2006 Google LLC
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google LLC nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// symupload.mm: Upload a symbol file to a HTTP server. The upload is sent as
+// a multipart/form-data POST request with the following parameters:
+// code_file: the basename of the module, e.g. "app"
+// debug_file: the basename of the debugging file, e.g. "app"
+// debug_identifier: the debug file's identifier, usually consisting of
+// the guid and age embedded in the pdb, e.g.
+// "11111111BBBB3333DDDD555555555555F"
+// os: the operating system that the module was built for
+// cpu: the CPU that the module was built for (x86 or ppc)
+// symbol_file: the contents of the breakpad-format symbol file
+
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include <Foundation/Foundation.h>
+
+#include "HTTPMultipartUpload.h"
+#include "HTTPPutRequest.h"
+#include "SymbolCollectorClient.h"
+#include "common/mac/dump_syms.h"
+
+using google_breakpad::DumpSymbols;
+
+NSString* const kBreakpadSymbolType = @"BREAKPAD";
+NSString* const kMachOSymbolType = @"MACHO";
+NSString* const kDSYMSymbolType = @"DSYM";
+
+typedef enum { kSymUploadProtocolV1, kSymUploadProtocolV2 } SymUploadProtocol;
+
+typedef enum {
+ kResultSuccess = 0,
+ kResultFailure = 1,
+ kResultAlreadyExists = 2
+} Result;
+
+typedef struct {
+ NSString* symbolsPath;
+ NSString* uploadURLStr;
+ SymUploadProtocol symUploadProtocol;
+ NSString* apiKey;
+ BOOL force;
+ Result result;
+ NSString* type;
+ NSString* codeFile;
+ NSString* debugID;
+ NSString* productName;
+} Options;
+
+//=============================================================================
+static NSArray* ModuleDataForSymbolFile(NSString* file) {
+ NSFileHandle* fh = [NSFileHandle fileHandleForReadingAtPath:file];
+ NSData* data = [fh readDataOfLength:1024];
+ NSString* str = [[NSString alloc] initWithData:data
+ encoding:NSUTF8StringEncoding];
+ NSScanner* scanner = [NSScanner scannerWithString:str];
+ NSString* line;
+ NSMutableArray* parts = nil;
+ const int MODULE_ID_INDEX = 3;
+
+ if ([scanner scanUpToString:@"\n" intoString:&line]) {
+ parts = [[NSMutableArray alloc] init];
+ NSScanner* moduleInfoScanner = [NSScanner scannerWithString:line];
+ NSString* moduleInfo;
+ // Get everything BEFORE the module name. None of these properties
+ // can have spaces.
+ for (int i = 0; i <= MODULE_ID_INDEX; i++) {
+ [moduleInfoScanner scanUpToString:@" " intoString:&moduleInfo];
+ [parts addObject:moduleInfo];
+ }
+
+ // Now get the module name. This can have a space so we scan to
+ // the end of the line.
+ [moduleInfoScanner scanUpToString:@"\n" intoString:&moduleInfo];
+ [parts addObject:moduleInfo];
+ }
+
+ [str release];
+
+ return parts;
+}
+
+//=============================================================================
+static void StartSymUploadProtocolV1(Options* options,
+ NSString* OS,
+ NSString* CPU,
+ NSString* debugID,
+ NSString* debugFile) {
+ NSURL* url = [NSURL URLWithString:options->uploadURLStr];
+ HTTPMultipartUpload* ul = [[HTTPMultipartUpload alloc] initWithURL:url];
+ NSMutableDictionary* parameters = [NSMutableDictionary dictionary];
+
+ // Add parameters
+ [parameters setObject:debugID forKey:@"debug_identifier"];
+ [parameters setObject:OS forKey:@"os"];
+ [parameters setObject:CPU forKey:@"cpu"];
+ [parameters setObject:debugFile forKey:@"debug_file"];
+ [parameters setObject:debugFile forKey:@"code_file"];
+ [ul setParameters:parameters];
+
+ NSArray* keys = [parameters allKeys];
+ int count = [keys count];
+ for (int i = 0; i < count; ++i) {
+ NSString* key = [keys objectAtIndex:i];
+ NSString* value = [parameters objectForKey:key];
+ fprintf(stdout, "'%s' = '%s'\n", [key UTF8String], [value UTF8String]);
+ }
+
+ // Add file
+ [ul addFileAtPath:options->symbolsPath name:@"symbol_file"];
+
+ // Send it
+ NSError* error = nil;
+ NSData* data = [ul send:&error];
+ NSString* result = [[NSString alloc] initWithData:data
+ encoding:NSUTF8StringEncoding];
+ int status = [[ul response] statusCode];
+
+ fprintf(stdout, "Send: %s\n",
+ error ? [[error description] UTF8String] : "No Error");
+ fprintf(stdout, "Response: %d\n", status);
+ fprintf(stdout, "Result: %lu bytes\n%s\n", (unsigned long)[data length],
+ [result UTF8String]);
+
+ [result release];
+ [ul release];
+ options->result = (!error && status == 200) ? kResultSuccess : kResultFailure;
+}
+
+//=============================================================================
+static void StartSymUploadProtocolV2(Options* options,
+ NSString* debugID,
+ NSString* debugFile) {
+ options->result = kResultFailure;
+
+ // Only check status of BREAKPAD symbols, because the v2 protocol doesn't
+ // (yet) have a way to check status of other symbol types.
+ if (!options->force && [options->type isEqualToString:kBreakpadSymbolType]) {
+ SymbolStatus symbolStatus =
+ [SymbolCollectorClient checkSymbolStatusOnServer:options->uploadURLStr
+ withAPIKey:options->apiKey
+ withDebugFile:debugFile
+ withDebugID:debugID];
+ if (symbolStatus == SymbolStatusFound) {
+ fprintf(stdout, "Symbol file already exists, upload aborted."
+ " Use \"-f\" to overwrite.\n");
+ options->result = kResultAlreadyExists;
+ return;
+ } else if (symbolStatus == SymbolStatusUnknown) {
+ fprintf(stdout, "Failed to get check for existing symbol.\n");
+ return;
+ }
+ }
+
+ UploadURLResponse* URLResponse =
+ [SymbolCollectorClient createUploadURLOnServer:options->uploadURLStr
+ withAPIKey:options->apiKey];
+ if (URLResponse == nil) {
+ return;
+ }
+
+ NSURL* uploadURL = [NSURL URLWithString:[URLResponse uploadURL]];
+ HTTPPutRequest* putRequest = [[HTTPPutRequest alloc] initWithURL:uploadURL];
+ [putRequest setFile:options->symbolsPath];
+
+ NSError* error = nil;
+ NSData* data = [putRequest send:&error];
+ NSString* result = [[NSString alloc] initWithData:data
+ encoding:NSUTF8StringEncoding];
+ int responseCode = [[putRequest response] statusCode];
+ [putRequest release];
+
+ if (error || responseCode != 200) {
+ fprintf(stdout, "Failed to upload symbol file.\n");
+ fprintf(stdout, "Response code: %d\n", responseCode);
+ fprintf(stdout, "Response:\n");
+ fprintf(stdout, "%s\n", [result UTF8String]);
+ return;
+ }
+
+ CompleteUploadResult completeUploadResult =
+ [SymbolCollectorClient completeUploadOnServer:options->uploadURLStr
+ withAPIKey:options->apiKey
+ withUploadKey:[URLResponse uploadKey]
+ withDebugFile:debugFile
+ withDebugID:debugID
+ withType:options->type
+ withProductName:options->productName];
+ [URLResponse release];
+ if (completeUploadResult == CompleteUploadResultError) {
+ fprintf(stdout, "Failed to complete upload.\n");
+ return;
+ } else if (completeUploadResult == CompleteUploadResultDuplicateData) {
+ fprintf(stdout, "Uploaded file checksum matched existing file checksum,"
+ " no change necessary.\n");
+ } else {
+ fprintf(stdout, "Successfully sent the symbol file.\n");
+ }
+ options->result = kResultSuccess;
+}
+
+//=============================================================================
+static void Start(Options* options) {
+ // If non-BREAKPAD upload special-case.
+ if (![options->type isEqualToString:kBreakpadSymbolType]) {
+ StartSymUploadProtocolV2(options, options->debugID, options->codeFile);
+ return;
+ }
+
+ NSArray* moduleParts = ModuleDataForSymbolFile(options->symbolsPath);
+ // MODULE <os> <cpu> <uuid> <module-name>
+ // 0 1 2 3 4
+ NSString* OS = [moduleParts objectAtIndex:1];
+ NSString* CPU = [moduleParts objectAtIndex:2];
+ NSMutableString* debugID =
+ [NSMutableString stringWithString:[moduleParts objectAtIndex:3]];
+ [debugID replaceOccurrencesOfString:@"-"
+ withString:@""
+ options:0
+ range:NSMakeRange(0, [debugID length])];
+ NSString* debugFile = [moduleParts objectAtIndex:4];
+
+ if (options->symUploadProtocol == kSymUploadProtocolV1) {
+ StartSymUploadProtocolV1(options, OS, CPU, debugID, debugFile);
+ } else if (options->symUploadProtocol == kSymUploadProtocolV2) {
+ StartSymUploadProtocolV2(options, debugID, debugFile);
+ }
+}
+
+//=============================================================================
+static void Usage(int argc, const char* argv[]) {
+ fprintf(stderr, "Submit symbol information.\n");
+ fprintf(stderr, "Usage: %s [options] <symbol-file> <upload-URL>\n", argv[0]);
+ fprintf(stderr, "<symbol-file> should be created by using the dump_syms "
+ "tool.\n");
+ fprintf(stderr, "<upload-URL> is the destination for the upload.\n");
+ fprintf(stderr, "Options:\n");
+ fprintf(stderr, "\t-p <protocol>: protocol to use for upload, accepts "
+ "[\"sym-upload-v1\", \"sym-upload-v2\"]. Default is "
+ "\"sym-upload-v1\".\n");
+ fprintf(stderr, "\t-k <api-key>: secret for authentication with upload "
+ "server. [Only in sym-upload-v2 protocol mode]\n");
+ fprintf(stderr, "\t-f: Overwrite symbol file on server if already present. "
+ "[Only in sym-upload-v2 protocol mode]\n");
+ fprintf(
+ stderr,
+ "\t-t: <symbol-type> Explicitly set symbol upload type ("
+ "default is 'breakpad').\n"
+ "\t One of ['breakpad', 'elf', 'pe', 'macho', 'debug_only', 'dwp', "
+ "'dsym', 'pdb'].\n"
+ "\t Note: When this flag is set to anything other than 'breakpad', then "
+ "the '-c' and '-i' flags must also be set.\n");
+ fprintf(stderr, "\t-c: <code-file> Explicitly set 'code_file' for symbol "
+ "upload (basename of executable).\n");
+ fprintf(stderr, "\t-i: <debug-id> Explicitly set 'debug_id' for symbol "
+ "upload (typically build ID of executable). The debug-id for "
+ "symbol-types 'dsym' and 'macho' will be determined "
+ "automatically. \n");
+ fprintf(stderr, "\t-n: <product-name> Optionally set 'product_name' for "
+ "symbol upload\n");
+ fprintf(stderr, "\t-h: Usage\n");
+ fprintf(stderr, "\t-?: Usage\n");
+ fprintf(stderr, "\n");
+ fprintf(stderr, "Exit codes:\n");
+ fprintf(stderr, "\t%d: Success\n", kResultSuccess);
+ fprintf(stderr, "\t%d: Failure\n", kResultFailure);
+ fprintf(stderr,
+ "\t%d: Symbol file already exists on server (and -f was not "
+ "specified).\n",
+ kResultAlreadyExists);
+ fprintf(stderr,
+ "\t [This exit code will only be returned by the sym-upload-v2 "
+ "protocol.\n");
+ fprintf(stderr,
+ "\t The sym-upload-v1 protocol can return either Success or "
+ "Failure\n");
+ fprintf(stderr, "\t in this case, and the action taken by the server is "
+ "unspecified.]\n");
+ fprintf(stderr, "\n");
+ fprintf(stderr, "Examples:\n");
+ fprintf(stderr, " With 'sym-upload-v1':\n");
+ fprintf(stderr, " %s path/to/symbol_file http://myuploadserver\n",
+ argv[0]);
+ fprintf(stderr, " With 'sym-upload-v2':\n");
+ fprintf(stderr, " [Defaulting to symbol type 'BREAKPAD']\n");
+ fprintf(stderr,
+ " %s -p sym-upload-v2 -k mysecret123! "
+ "path/to/symbol_file http://myuploadserver\n",
+ argv[0]);
+ fprintf(stderr, " [Explicitly set symbol type to 'macho']\n");
+ fprintf(stderr,
+ " %s -p sym-upload-v2 -k mysecret123! -t macho "
+ "-c app -i 11111111BBBB3333DDDD555555555555F "
+ "path/to/symbol_file http://myuploadserver\n",
+ argv[0]);
+}
+
+//=============================================================================
+static void SetupOptions(int argc, const char* argv[], Options* options) {
+ // Set default options values.
+ options->symUploadProtocol = kSymUploadProtocolV1;
+ options->apiKey = nil;
+ options->type = kBreakpadSymbolType;
+ options->codeFile = nil;
+ options->debugID = nil;
+ options->force = NO;
+ options->productName = nil;
+
+ extern int optind;
+ int ch;
+
+ while ((ch = getopt(argc, (char* const*)argv, "p:k:t:c:i:n:hf?")) != -1) {
+ switch (ch) {
+ case 'p':
+ if (strcmp(optarg, "sym-upload-v2") == 0) {
+ options->symUploadProtocol = kSymUploadProtocolV2;
+ break;
+ } else if (strcmp(optarg, "sym-upload-v1") == 0) {
+ // This is already the default but leave in case that changes.
+ options->symUploadProtocol = kSymUploadProtocolV1;
+ break;
+ }
+ Usage(argc, argv);
+ exit(0);
+ break;
+ case 'k':
+ options->apiKey = [NSString stringWithCString:optarg
+ encoding:NSASCIIStringEncoding];
+ break;
+ case 't': {
+ // This is really an enum, so treat as upper-case for consistency with
+ // enum naming convention on server-side.
+ options->type = [[NSString stringWithCString:optarg
+ encoding:NSASCIIStringEncoding]
+ uppercaseString];
+ break;
+ }
+ case 'c':
+ options->codeFile = [NSString stringWithCString:optarg
+ encoding:NSASCIIStringEncoding];
+ break;
+ case 'i':
+ options->debugID = [NSString stringWithCString:optarg
+ encoding:NSASCIIStringEncoding];
+ break;
+ case 'n':
+ options->productName =
+ [NSString stringWithCString:optarg
+ encoding:NSASCIIStringEncoding];
+ break;
+ case 'f':
+ options->force = YES;
+ break;
+ default:
+ Usage(argc, argv);
+ exit(0);
+ break;
+ }
+ }
+
+ if ((argc - optind) != 2) {
+ fprintf(stderr, "%s: Missing symbols file and/or upload-URL\n", argv[0]);
+ Usage(argc, argv);
+ exit(1);
+ }
+
+ int fd = open(argv[optind], O_RDONLY);
+ if (fd < 0) {
+ fprintf(stderr, "%s: %s: %s\n", argv[0], argv[optind], strerror(errno));
+ exit(1);
+ }
+
+ struct stat statbuf;
+ if (fstat(fd, &statbuf) < 0) {
+ fprintf(stderr, "%s: %s: %s\n", argv[0], argv[optind], strerror(errno));
+ close(fd);
+ exit(1);
+ }
+ close(fd);
+
+ if (!S_ISREG(statbuf.st_mode)) {
+ fprintf(stderr, "%s: %s: not a regular file\n", argv[0], argv[optind]);
+ exit(1);
+ }
+
+ bool isBreakpadUpload = [options->type isEqualToString:kBreakpadSymbolType];
+ bool hasCodeFile = options->codeFile != nil;
+ bool hasDebugID = options->debugID != nil;
+ if (isBreakpadUpload && (hasCodeFile || hasDebugID)) {
+ fprintf(stderr, "\n");
+ fprintf(stderr,
+ "%s: -c and -i should only be specified for non-breakpad "
+ "symbol upload types.\n",
+ argv[0]);
+ fprintf(stderr, "\n");
+ Usage(argc, argv);
+ exit(1);
+ }
+
+ if (!isBreakpadUpload && hasCodeFile && !hasDebugID &&
+ ([options->type isEqualToString:kMachOSymbolType] ||
+ [options->type isEqualToString:kDSYMSymbolType])) {
+ DumpSymbols dump_symbols(SYMBOLS_AND_FILES | INLINES, false);
+ if (dump_symbols.Read(argv[optind])) {
+ std::string identifier = dump_symbols.Identifier();
+ if (identifier.empty()) {
+ fprintf(stderr, "\n");
+ fprintf(stderr,
+ "%s: Unable to determine debug-id. Please specify with '-i'.\n",
+ argv[0]);
+ fprintf(stderr, "\n");
+ Usage(argc, argv);
+ exit(1);
+ }
+ options->debugID = [NSString stringWithUTF8String:identifier.c_str()];
+ hasDebugID = true;
+ }
+ }
+
+ if (!isBreakpadUpload && (!hasCodeFile || !hasDebugID)) {
+ fprintf(stderr, "\n");
+ fprintf(stderr,
+ "%s: -c and -i must be specified for non-breakpad "
+ "symbol upload types.\n",
+ argv[0]);
+ fprintf(stderr, "\n");
+ Usage(argc, argv);
+ exit(1);
+ }
+
+ options->symbolsPath = [NSString stringWithUTF8String:argv[optind]];
+ options->uploadURLStr = [NSString stringWithUTF8String:argv[optind + 1]];
+}
+
+//=============================================================================
+int main(int argc, const char* argv[]) {
+ NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
+ Options options;
+
+ bzero(&options, sizeof(Options));
+ SetupOptions(argc, argv, &options);
+ Start(&options);
+
+ [pool release];
+ return options.result;
+}
diff --git a/src/tools/mac/symupload/symupload.xcodeproj/project.pbxproj b/src/tools/mac/symupload/symupload.xcodeproj/project.pbxproj
index a6a78dc5..903c66f1 100644
--- a/src/tools/mac/symupload/symupload.xcodeproj/project.pbxproj
+++ b/src/tools/mac/symupload/symupload.xcodeproj/project.pbxproj
@@ -7,9 +7,38 @@
objects = {
/* Begin PBXBuildFile section */
+ 5B6060BD222716FC0015F0A0 /* HTTPRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 5B6060BC222716FC0015F0A0 /* HTTPRequest.m */; };
+ 5B6060C02227201B0015F0A0 /* HTTPPutRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 5B6060BF2227201B0015F0A0 /* HTTPPutRequest.m */; };
+ 5B6060C7222735E50015F0A0 /* HTTPGetRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 5B6060C6222735E50015F0A0 /* HTTPGetRequest.m */; };
+ 5B6060CA2227374E0015F0A0 /* HTTPSimplePostRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 5B6060C92227374E0015F0A0 /* HTTPSimplePostRequest.m */; };
+ 5B6060D022273BDA0015F0A0 /* SymbolCollectorClient.m in Sources */ = {isa = PBXBuildFile; fileRef = 5B6060CF22273BDA0015F0A0 /* SymbolCollectorClient.m */; };
+ 5B97447524D0AA5F000C71F5 /* encoding_util.m in Sources */ = {isa = PBXBuildFile; fileRef = 5B97447424D0AA5F000C71F5 /* encoding_util.m */; };
8B31022C11F0CEBD00FCF3E4 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 08FB779EFE84155DC02AAC07 /* Foundation.framework */; };
- 8DD76F9A0486AA7600D96B5E /* symupload.m in Sources */ = {isa = PBXBuildFile; fileRef = 08FB7796FE84155DC02AAC07 /* symupload.m */; settings = {ATTRIBUTES = (); }; };
+ 8DD76F9A0486AA7600D96B5E /* symupload.mm in Sources */ = {isa = PBXBuildFile; fileRef = 08FB7796FE84155DC02AAC07 /* symupload.mm */; settings = {ATTRIBUTES = (); }; };
8DD76F9C0486AA7600D96B5E /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 08FB779EFE84155DC02AAC07 /* Foundation.framework */; };
+ 930DA19225ED543A008558E3 /* dump_syms.cc in Sources */ = {isa = PBXBuildFile; fileRef = 930DA19025ED543A008558E3 /* dump_syms.cc */; };
+ 930DA22C25ED55A9008558E3 /* module.cc in Sources */ = {isa = PBXBuildFile; fileRef = 930DA21F25ED55A8008558E3 /* module.cc */; };
+ 930DA22D25ED55A9008558E3 /* dwarf_cfi_to_module.cc in Sources */ = {isa = PBXBuildFile; fileRef = 930DA22325ED55A8008558E3 /* dwarf_cfi_to_module.cc */; };
+ 930DA22E25ED55A9008558E3 /* stabs_to_module.cc in Sources */ = {isa = PBXBuildFile; fileRef = 930DA22525ED55A8008558E3 /* stabs_to_module.cc */; };
+ 930DA22F25ED55A9008558E3 /* language.cc in Sources */ = {isa = PBXBuildFile; fileRef = 930DA22625ED55A9008558E3 /* language.cc */; };
+ 930DA23125ED55A9008558E3 /* dwarf_line_to_module.cc in Sources */ = {isa = PBXBuildFile; fileRef = 930DA22A25ED55A9008558E3 /* dwarf_line_to_module.cc */; };
+ 930DA23225ED55A9008558E3 /* dwarf_cu_to_module.cc in Sources */ = {isa = PBXBuildFile; fileRef = 930DA22B25ED55A9008558E3 /* dwarf_cu_to_module.cc */; };
+ 930DA23725ED55B6008558E3 /* stabs_reader.cc in Sources */ = {isa = PBXBuildFile; fileRef = 930DA23625ED55B6008558E3 /* stabs_reader.cc */; };
+ 930DA24225ED55BF008558E3 /* macho_id.cc in Sources */ = {isa = PBXBuildFile; fileRef = 930DA23A25ED55BF008558E3 /* macho_id.cc */; };
+ 930DA24325ED55BF008558E3 /* macho_utilities.cc in Sources */ = {isa = PBXBuildFile; fileRef = 930DA23C25ED55BF008558E3 /* macho_utilities.cc */; };
+ 930DA24425ED55BF008558E3 /* macho_reader.cc in Sources */ = {isa = PBXBuildFile; fileRef = 930DA23F25ED55BF008558E3 /* macho_reader.cc */; };
+ 930DA24525ED55BF008558E3 /* macho_walker.cc in Sources */ = {isa = PBXBuildFile; fileRef = 930DA24125ED55BF008558E3 /* macho_walker.cc */; };
+ 930DA25C25ED56DB008558E3 /* dwarf_range_list_handler.cc in Sources */ = {isa = PBXBuildFile; fileRef = 930DA24D25ED56DB008558E3 /* dwarf_range_list_handler.cc */; };
+ 930DA25D25ED56DB008558E3 /* cfi_assembler.cc in Sources */ = {isa = PBXBuildFile; fileRef = 930DA24E25ED56DB008558E3 /* cfi_assembler.cc */; };
+ 930DA25E25ED56DB008558E3 /* elf_reader.cc in Sources */ = {isa = PBXBuildFile; fileRef = 930DA25225ED56DB008558E3 /* elf_reader.cc */; };
+ 930DA25F25ED56DB008558E3 /* dwarf2diehandler.cc in Sources */ = {isa = PBXBuildFile; fileRef = 930DA25325ED56DB008558E3 /* dwarf2diehandler.cc */; };
+ 930DA26025ED56DB008558E3 /* dwarf2reader.cc in Sources */ = {isa = PBXBuildFile; fileRef = 930DA25625ED56DB008558E3 /* dwarf2reader.cc */; };
+ 930DA26125ED56DB008558E3 /* bytereader.cc in Sources */ = {isa = PBXBuildFile; fileRef = 930DA25925ED56DB008558E3 /* bytereader.cc */; };
+ 930DA26925ED56FF008558E3 /* test_assembler.cc in Sources */ = {isa = PBXBuildFile; fileRef = 930DA26825ED56FF008558E3 /* test_assembler.cc */; };
+ 930DA26E25ED571F008558E3 /* arch_utilities.cc in Sources */ = {isa = PBXBuildFile; fileRef = 930DA26D25ED571F008558E3 /* arch_utilities.cc */; };
+ 930DA27825ED572D008558E3 /* path_helper.cc in Sources */ = {isa = PBXBuildFile; fileRef = 930DA27125ED572C008558E3 /* path_helper.cc */; };
+ 930DA27925ED572D008558E3 /* file_id.cc in Sources */ = {isa = PBXBuildFile; fileRef = 930DA27525ED572C008558E3 /* file_id.cc */; };
+ 930DA27A25ED572D008558E3 /* md5.cc in Sources */ = {isa = PBXBuildFile; fileRef = 930DA27725ED572D008558E3 /* md5.cc */; };
9BC1D49E0B37427A00F2A2B4 /* minidump_upload.m in Sources */ = {isa = PBXBuildFile; fileRef = 9BD836000B0544BA0055103E /* minidump_upload.m */; };
9BD8336A0B03E4080055103E /* HTTPMultipartUpload.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 9BD833680B03E4080055103E /* HTTPMultipartUpload.h */; };
9BD8336B0B03E4080055103E /* HTTPMultipartUpload.m in Sources */ = {isa = PBXBuildFile; fileRef = 9BD833690B03E4080055103E /* HTTPMultipartUpload.m */; };
@@ -30,16 +59,78 @@
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
- 08FB7796FE84155DC02AAC07 /* symupload.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = symupload.m; sourceTree = "<group>"; };
+ 08FB7796FE84155DC02AAC07 /* symupload.mm */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.objcpp; path = symupload.mm; sourceTree = "<group>"; tabWidth = 2; };
08FB779EFE84155DC02AAC07 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
+ 5B6060BB222716FC0015F0A0 /* HTTPRequest.h */ = {isa = PBXFileReference; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = HTTPRequest.h; path = ../../../common/mac/HTTPRequest.h; sourceTree = "<group>"; tabWidth = 2; };
+ 5B6060BC222716FC0015F0A0 /* HTTPRequest.m */ = {isa = PBXFileReference; indentWidth = 2; lastKnownFileType = sourcecode.c.objc; name = HTTPRequest.m; path = ../../../common/mac/HTTPRequest.m; sourceTree = "<group>"; tabWidth = 2; };
+ 5B6060BE2227201B0015F0A0 /* HTTPPutRequest.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = HTTPPutRequest.h; path = ../../../common/mac/HTTPPutRequest.h; sourceTree = "<group>"; };
+ 5B6060BF2227201B0015F0A0 /* HTTPPutRequest.m */ = {isa = PBXFileReference; indentWidth = 2; lastKnownFileType = sourcecode.c.objc; name = HTTPPutRequest.m; path = ../../../common/mac/HTTPPutRequest.m; sourceTree = "<group>"; tabWidth = 2; };
+ 5B6060C22227303A0015F0A0 /* encoding_util.h */ = {isa = PBXFileReference; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = encoding_util.h; path = ../../../common/mac/encoding_util.h; sourceTree = "<group>"; tabWidth = 2; };
+ 5B6060C5222735E50015F0A0 /* HTTPGetRequest.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = HTTPGetRequest.h; path = ../../../common/mac/HTTPGetRequest.h; sourceTree = "<group>"; };
+ 5B6060C6222735E50015F0A0 /* HTTPGetRequest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = HTTPGetRequest.m; path = ../../../common/mac/HTTPGetRequest.m; sourceTree = "<group>"; };
+ 5B6060C82227374E0015F0A0 /* HTTPSimplePostRequest.h */ = {isa = PBXFileReference; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = HTTPSimplePostRequest.h; path = ../../../common/mac/HTTPSimplePostRequest.h; sourceTree = "<group>"; tabWidth = 2; };
+ 5B6060C92227374E0015F0A0 /* HTTPSimplePostRequest.m */ = {isa = PBXFileReference; indentWidth = 2; lastKnownFileType = sourcecode.c.objc; name = HTTPSimplePostRequest.m; path = ../../../common/mac/HTTPSimplePostRequest.m; sourceTree = "<group>"; tabWidth = 2; };
+ 5B6060CE22273BDA0015F0A0 /* SymbolCollectorClient.h */ = {isa = PBXFileReference; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = SymbolCollectorClient.h; path = ../../../common/mac/SymbolCollectorClient.h; sourceTree = "<group>"; tabWidth = 2; };
+ 5B6060CF22273BDA0015F0A0 /* SymbolCollectorClient.m */ = {isa = PBXFileReference; indentWidth = 2; lastKnownFileType = sourcecode.c.objc; name = SymbolCollectorClient.m; path = ../../../common/mac/SymbolCollectorClient.m; sourceTree = "<group>"; tabWidth = 2; };
+ 5B97447424D0AA5F000C71F5 /* encoding_util.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = encoding_util.m; path = ../../../common/mac/encoding_util.m; sourceTree = "<group>"; };
8B31022B11F0CE6900FCF3E4 /* Breakpad.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Breakpad.xcconfig; path = ../../../common/mac/Breakpad.xcconfig; sourceTree = SOURCE_ROOT; };
8B3102B611F0D5CE00FCF3E4 /* BreakpadDebug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = BreakpadDebug.xcconfig; path = ../../../common/mac/BreakpadDebug.xcconfig; sourceTree = SOURCE_ROOT; };
8B3102B711F0D5CE00FCF3E4 /* BreakpadRelease.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = BreakpadRelease.xcconfig; path = ../../../common/mac/BreakpadRelease.xcconfig; sourceTree = SOURCE_ROOT; };
8DD76FA10486AA7600D96B5E /* symupload */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = symupload; sourceTree = BUILT_PRODUCTS_DIR; };
- 9BD833680B03E4080055103E /* HTTPMultipartUpload.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = HTTPMultipartUpload.h; path = ../../../common/mac/HTTPMultipartUpload.h; sourceTree = "<group>"; };
- 9BD833690B03E4080055103E /* HTTPMultipartUpload.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = HTTPMultipartUpload.m; path = ../../../common/mac/HTTPMultipartUpload.m; sourceTree = "<group>"; };
+ 930DA19025ED543A008558E3 /* dump_syms.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = dump_syms.cc; path = ../../../common/mac/dump_syms.cc; sourceTree = "<group>"; };
+ 930DA19125ED543A008558E3 /* dump_syms.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dump_syms.h; path = ../../../common/mac/dump_syms.h; sourceTree = "<group>"; };
+ 930DA21F25ED55A8008558E3 /* module.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = module.cc; path = ../../../common/module.cc; sourceTree = "<group>"; };
+ 930DA22025ED55A8008558E3 /* module.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = module.h; path = ../../../common/module.h; sourceTree = "<group>"; };
+ 930DA22125ED55A8008558E3 /* dwarf_cfi_to_module.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dwarf_cfi_to_module.h; path = ../../../common/dwarf_cfi_to_module.h; sourceTree = "<group>"; };
+ 930DA22225ED55A8008558E3 /* dwarf_cu_to_module.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dwarf_cu_to_module.h; path = ../../../common/dwarf_cu_to_module.h; sourceTree = "<group>"; };
+ 930DA22325ED55A8008558E3 /* dwarf_cfi_to_module.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = dwarf_cfi_to_module.cc; path = ../../../common/dwarf_cfi_to_module.cc; sourceTree = "<group>"; };
+ 930DA22425ED55A8008558E3 /* language.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = language.h; path = ../../../common/language.h; sourceTree = "<group>"; };
+ 930DA22525ED55A8008558E3 /* stabs_to_module.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = stabs_to_module.cc; path = ../../../common/stabs_to_module.cc; sourceTree = "<group>"; };
+ 930DA22625ED55A9008558E3 /* language.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = language.cc; path = ../../../common/language.cc; sourceTree = "<group>"; };
+ 930DA22725ED55A9008558E3 /* dwarf_line_to_module.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dwarf_line_to_module.h; path = ../../../common/dwarf_line_to_module.h; sourceTree = "<group>"; };
+ 930DA22825ED55A9008558E3 /* stabs_to_module.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = stabs_to_module.h; path = ../../../common/stabs_to_module.h; sourceTree = "<group>"; };
+ 930DA22A25ED55A9008558E3 /* dwarf_line_to_module.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = dwarf_line_to_module.cc; path = ../../../common/dwarf_line_to_module.cc; sourceTree = "<group>"; };
+ 930DA22B25ED55A9008558E3 /* dwarf_cu_to_module.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = dwarf_cu_to_module.cc; path = ../../../common/dwarf_cu_to_module.cc; sourceTree = "<group>"; };
+ 930DA23525ED55B6008558E3 /* stabs_reader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = stabs_reader.h; path = ../../../common/stabs_reader.h; sourceTree = "<group>"; };
+ 930DA23625ED55B6008558E3 /* stabs_reader.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = stabs_reader.cc; path = ../../../common/stabs_reader.cc; sourceTree = "<group>"; };
+ 930DA23A25ED55BF008558E3 /* macho_id.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = macho_id.cc; path = ../../../common/mac/macho_id.cc; sourceTree = "<group>"; };
+ 930DA23B25ED55BF008558E3 /* macho_id.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = macho_id.h; path = ../../../common/mac/macho_id.h; sourceTree = "<group>"; };
+ 930DA23C25ED55BF008558E3 /* macho_utilities.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = macho_utilities.cc; path = ../../../common/mac/macho_utilities.cc; sourceTree = "<group>"; };
+ 930DA23D25ED55BF008558E3 /* macho_walker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = macho_walker.h; path = ../../../common/mac/macho_walker.h; sourceTree = "<group>"; };
+ 930DA23E25ED55BF008558E3 /* macho_reader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = macho_reader.h; path = ../../../common/mac/macho_reader.h; sourceTree = "<group>"; };
+ 930DA23F25ED55BF008558E3 /* macho_reader.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = macho_reader.cc; path = ../../../common/mac/macho_reader.cc; sourceTree = "<group>"; };
+ 930DA24025ED55BF008558E3 /* macho_utilities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = macho_utilities.h; path = ../../../common/mac/macho_utilities.h; sourceTree = "<group>"; };
+ 930DA24125ED55BF008558E3 /* macho_walker.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = macho_walker.cc; path = ../../../common/mac/macho_walker.cc; sourceTree = "<group>"; };
+ 930DA24C25ED56DB008558E3 /* line_state_machine.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = line_state_machine.h; path = ../../../common/dwarf/line_state_machine.h; sourceTree = "<group>"; };
+ 930DA24D25ED56DB008558E3 /* dwarf_range_list_handler.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = dwarf_range_list_handler.cc; path = ../../../common/dwarf_range_list_handler.cc; sourceTree = "<group>"; };
+ 930DA24E25ED56DB008558E3 /* cfi_assembler.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = cfi_assembler.cc; path = ../../../common/dwarf/cfi_assembler.cc; sourceTree = "<group>"; };
+ 930DA24F25ED56DB008558E3 /* dwarf2enums.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dwarf2enums.h; path = ../../../common/dwarf/dwarf2enums.h; sourceTree = "<group>"; };
+ 930DA25025ED56DB008558E3 /* bytereader-inl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "bytereader-inl.h"; path = "../../../common/dwarf/bytereader-inl.h"; sourceTree = "<group>"; };
+ 930DA25125ED56DB008558E3 /* dwarf_range_list_handler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dwarf_range_list_handler.h; path = ../../../common/dwarf_range_list_handler.h; sourceTree = "<group>"; };
+ 930DA25225ED56DB008558E3 /* elf_reader.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = elf_reader.cc; path = ../../../common/dwarf/elf_reader.cc; sourceTree = "<group>"; };
+ 930DA25325ED56DB008558E3 /* dwarf2diehandler.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = dwarf2diehandler.cc; path = ../../../common/dwarf/dwarf2diehandler.cc; sourceTree = "<group>"; };
+ 930DA25425ED56DB008558E3 /* elf_reader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = elf_reader.h; path = ../../../common/dwarf/elf_reader.h; sourceTree = "<group>"; };
+ 930DA25525ED56DB008558E3 /* bytereader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = bytereader.h; path = ../../../common/dwarf/bytereader.h; sourceTree = "<group>"; };
+ 930DA25625ED56DB008558E3 /* dwarf2reader.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = dwarf2reader.cc; path = ../../../common/dwarf/dwarf2reader.cc; sourceTree = "<group>"; };
+ 930DA25725ED56DB008558E3 /* dwarf2reader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dwarf2reader.h; path = ../../../common/dwarf/dwarf2reader.h; sourceTree = "<group>"; };
+ 930DA25825ED56DB008558E3 /* dwarf2diehandler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dwarf2diehandler.h; path = ../../../common/dwarf/dwarf2diehandler.h; sourceTree = "<group>"; };
+ 930DA25925ED56DB008558E3 /* bytereader.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = bytereader.cc; path = ../../../common/dwarf/bytereader.cc; sourceTree = "<group>"; };
+ 930DA25A25ED56DB008558E3 /* cfi_assembler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = cfi_assembler.h; path = ../../../common/dwarf/cfi_assembler.h; sourceTree = "<group>"; };
+ 930DA26725ED56FF008558E3 /* test_assembler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = test_assembler.h; path = ../../../common/test_assembler.h; sourceTree = "<group>"; };
+ 930DA26825ED56FF008558E3 /* test_assembler.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = test_assembler.cc; path = ../../../common/test_assembler.cc; sourceTree = "<group>"; };
+ 930DA26C25ED571F008558E3 /* arch_utilities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = arch_utilities.h; path = ../../../common/mac/arch_utilities.h; sourceTree = "<group>"; };
+ 930DA26D25ED571F008558E3 /* arch_utilities.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = arch_utilities.cc; path = ../../../common/mac/arch_utilities.cc; sourceTree = "<group>"; };
+ 930DA27125ED572C008558E3 /* path_helper.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = path_helper.cc; path = ../../../common/path_helper.cc; sourceTree = "<group>"; };
+ 930DA27225ED572C008558E3 /* byteswap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = byteswap.h; path = ../../../common/mac/byteswap.h; sourceTree = "<group>"; };
+ 930DA27325ED572C008558E3 /* path_helper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = path_helper.h; path = ../../../common/path_helper.h; sourceTree = "<group>"; };
+ 930DA27425ED572C008558E3 /* byte_cursor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = byte_cursor.h; path = ../../../common/byte_cursor.h; sourceTree = "<group>"; };
+ 930DA27525ED572C008558E3 /* file_id.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = file_id.cc; path = ../../../common/mac/file_id.cc; sourceTree = "<group>"; };
+ 930DA27625ED572C008558E3 /* file_id.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = file_id.h; path = ../../../common/mac/file_id.h; sourceTree = "<group>"; };
+ 930DA27725ED572D008558E3 /* md5.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = md5.cc; path = ../../../common/md5.cc; sourceTree = "<group>"; };
+ 9BD833680B03E4080055103E /* HTTPMultipartUpload.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = HTTPMultipartUpload.h; path = ../../../common/mac/HTTPMultipartUpload.h; sourceTree = "<group>"; tabWidth = 2; };
+ 9BD833690B03E4080055103E /* HTTPMultipartUpload.m */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.objc; name = HTTPMultipartUpload.m; path = ../../../common/mac/HTTPMultipartUpload.m; sourceTree = "<group>"; tabWidth = 2; };
9BD835FB0B0544950055103E /* minidump_upload */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = minidump_upload; sourceTree = BUILT_PRODUCTS_DIR; };
- 9BD836000B0544BA0055103E /* minidump_upload.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = minidump_upload.m; sourceTree = "<group>"; };
+ 9BD836000B0544BA0055103E /* minidump_upload.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = minidump_upload.m; path = ../../../common/mac/minidump_upload.m; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@@ -65,10 +156,23 @@
08FB7794FE84155DC02AAC07 /* symupload */ = {
isa = PBXGroup;
children = (
+ 930DA21E25ED5586008558E3 /* dump_syms */,
+ 5B6060CE22273BDA0015F0A0 /* SymbolCollectorClient.h */,
+ 5B6060CF22273BDA0015F0A0 /* SymbolCollectorClient.m */,
+ 5B6060C82227374E0015F0A0 /* HTTPSimplePostRequest.h */,
+ 5B6060C92227374E0015F0A0 /* HTTPSimplePostRequest.m */,
+ 5B6060C5222735E50015F0A0 /* HTTPGetRequest.h */,
+ 5B6060C6222735E50015F0A0 /* HTTPGetRequest.m */,
+ 5B6060C22227303A0015F0A0 /* encoding_util.h */,
+ 5B97447424D0AA5F000C71F5 /* encoding_util.m */,
+ 5B6060BE2227201B0015F0A0 /* HTTPPutRequest.h */,
+ 5B6060BF2227201B0015F0A0 /* HTTPPutRequest.m */,
+ 5B6060BB222716FC0015F0A0 /* HTTPRequest.h */,
+ 5B6060BC222716FC0015F0A0 /* HTTPRequest.m */,
8B31022B11F0CE6900FCF3E4 /* Breakpad.xcconfig */,
8B3102B611F0D5CE00FCF3E4 /* BreakpadDebug.xcconfig */,
8B3102B711F0D5CE00FCF3E4 /* BreakpadRelease.xcconfig */,
- 08FB7796FE84155DC02AAC07 /* symupload.m */,
+ 08FB7796FE84155DC02AAC07 /* symupload.mm */,
9BD836000B0544BA0055103E /* minidump_upload.m */,
9BD833680B03E4080055103E /* HTTPMultipartUpload.h */,
9BD833690B03E4080055103E /* HTTPMultipartUpload.m */,
@@ -95,6 +199,63 @@
name = Products;
sourceTree = "<group>";
};
+ 930DA21E25ED5586008558E3 /* dump_syms */ = {
+ isa = PBXGroup;
+ children = (
+ 930DA23A25ED55BF008558E3 /* macho_id.cc */,
+ 930DA23B25ED55BF008558E3 /* macho_id.h */,
+ 930DA23F25ED55BF008558E3 /* macho_reader.cc */,
+ 930DA23E25ED55BF008558E3 /* macho_reader.h */,
+ 930DA23C25ED55BF008558E3 /* macho_utilities.cc */,
+ 930DA24025ED55BF008558E3 /* macho_utilities.h */,
+ 930DA24125ED55BF008558E3 /* macho_walker.cc */,
+ 930DA23D25ED55BF008558E3 /* macho_walker.h */,
+ 930DA19025ED543A008558E3 /* dump_syms.cc */,
+ 930DA19125ED543A008558E3 /* dump_syms.h */,
+ 930DA23625ED55B6008558E3 /* stabs_reader.cc */,
+ 930DA23525ED55B6008558E3 /* stabs_reader.h */,
+ 930DA22325ED55A8008558E3 /* dwarf_cfi_to_module.cc */,
+ 930DA22125ED55A8008558E3 /* dwarf_cfi_to_module.h */,
+ 930DA22B25ED55A9008558E3 /* dwarf_cu_to_module.cc */,
+ 930DA22225ED55A8008558E3 /* dwarf_cu_to_module.h */,
+ 930DA22A25ED55A9008558E3 /* dwarf_line_to_module.cc */,
+ 930DA22725ED55A9008558E3 /* dwarf_line_to_module.h */,
+ 930DA22625ED55A9008558E3 /* language.cc */,
+ 930DA22425ED55A8008558E3 /* language.h */,
+ 930DA21F25ED55A8008558E3 /* module.cc */,
+ 930DA22025ED55A8008558E3 /* module.h */,
+ 930DA22525ED55A8008558E3 /* stabs_to_module.cc */,
+ 930DA22825ED55A9008558E3 /* stabs_to_module.h */,
+ 930DA25025ED56DB008558E3 /* bytereader-inl.h */,
+ 930DA25925ED56DB008558E3 /* bytereader.cc */,
+ 930DA25525ED56DB008558E3 /* bytereader.h */,
+ 930DA24E25ED56DB008558E3 /* cfi_assembler.cc */,
+ 930DA25A25ED56DB008558E3 /* cfi_assembler.h */,
+ 930DA24D25ED56DB008558E3 /* dwarf_range_list_handler.cc */,
+ 930DA25125ED56DB008558E3 /* dwarf_range_list_handler.h */,
+ 930DA25325ED56DB008558E3 /* dwarf2diehandler.cc */,
+ 930DA25825ED56DB008558E3 /* dwarf2diehandler.h */,
+ 930DA24F25ED56DB008558E3 /* dwarf2enums.h */,
+ 930DA25625ED56DB008558E3 /* dwarf2reader.cc */,
+ 930DA25725ED56DB008558E3 /* dwarf2reader.h */,
+ 930DA25225ED56DB008558E3 /* elf_reader.cc */,
+ 930DA25425ED56DB008558E3 /* elf_reader.h */,
+ 930DA24C25ED56DB008558E3 /* line_state_machine.h */,
+ 930DA26825ED56FF008558E3 /* test_assembler.cc */,
+ 930DA26725ED56FF008558E3 /* test_assembler.h */,
+ 930DA26D25ED571F008558E3 /* arch_utilities.cc */,
+ 930DA26C25ED571F008558E3 /* arch_utilities.h */,
+ 930DA27425ED572C008558E3 /* byte_cursor.h */,
+ 930DA27225ED572C008558E3 /* byteswap.h */,
+ 930DA27525ED572C008558E3 /* file_id.cc */,
+ 930DA27625ED572C008558E3 /* file_id.h */,
+ 930DA27725ED572D008558E3 /* md5.cc */,
+ 930DA27125ED572C008558E3 /* path_helper.cc */,
+ 930DA27325ED572C008558E3 /* path_helper.h */,
+ );
+ name = dump_syms;
+ sourceTree = "<group>";
+ };
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
@@ -137,9 +298,15 @@
/* Begin PBXProject section */
08FB7793FE84155DC02AAC07 /* Project object */ = {
isa = PBXProject;
+ attributes = {
+ };
buildConfigurationList = 1DEB927808733DD40010E9CD /* Build configuration list for PBXProject "symupload" */;
compatibilityVersion = "Xcode 3.1";
+ developmentRegion = en;
hasScannedForEncodings = 1;
+ knownRegions = (
+ en,
+ );
mainGroup = 08FB7794FE84155DC02AAC07 /* symupload */;
projectDirPath = "";
projectRoot = "";
@@ -155,8 +322,37 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
- 8DD76F9A0486AA7600D96B5E /* symupload.m in Sources */,
+ 8DD76F9A0486AA7600D96B5E /* symupload.mm in Sources */,
+ 930DA19225ED543A008558E3 /* dump_syms.cc in Sources */,
+ 930DA24525ED55BF008558E3 /* macho_walker.cc in Sources */,
+ 930DA22E25ED55A9008558E3 /* stabs_to_module.cc in Sources */,
+ 5B6060CA2227374E0015F0A0 /* HTTPSimplePostRequest.m in Sources */,
+ 930DA25F25ED56DB008558E3 /* dwarf2diehandler.cc in Sources */,
+ 930DA27825ED572D008558E3 /* path_helper.cc in Sources */,
+ 930DA27A25ED572D008558E3 /* md5.cc in Sources */,
+ 930DA22D25ED55A9008558E3 /* dwarf_cfi_to_module.cc in Sources */,
+ 930DA24425ED55BF008558E3 /* macho_reader.cc in Sources */,
+ 930DA24325ED55BF008558E3 /* macho_utilities.cc in Sources */,
+ 5B6060D022273BDA0015F0A0 /* SymbolCollectorClient.m in Sources */,
+ 5B6060C7222735E50015F0A0 /* HTTPGetRequest.m in Sources */,
+ 930DA27925ED572D008558E3 /* file_id.cc in Sources */,
+ 930DA26925ED56FF008558E3 /* test_assembler.cc in Sources */,
+ 930DA22F25ED55A9008558E3 /* language.cc in Sources */,
+ 930DA25E25ED56DB008558E3 /* elf_reader.cc in Sources */,
+ 930DA26E25ED571F008558E3 /* arch_utilities.cc in Sources */,
+ 930DA24225ED55BF008558E3 /* macho_id.cc in Sources */,
+ 5B6060C02227201B0015F0A0 /* HTTPPutRequest.m in Sources */,
+ 930DA25C25ED56DB008558E3 /* dwarf_range_list_handler.cc in Sources */,
+ 5B6060BD222716FC0015F0A0 /* HTTPRequest.m in Sources */,
+ 930DA25D25ED56DB008558E3 /* cfi_assembler.cc in Sources */,
+ 930DA23225ED55A9008558E3 /* dwarf_cu_to_module.cc in Sources */,
+ 930DA23125ED55A9008558E3 /* dwarf_line_to_module.cc in Sources */,
+ 930DA26125ED56DB008558E3 /* bytereader.cc in Sources */,
+ 930DA22C25ED55A9008558E3 /* module.cc in Sources */,
+ 5B97447524D0AA5F000C71F5 /* encoding_util.m in Sources */,
+ 930DA23725ED55B6008558E3 /* stabs_reader.cc in Sources */,
9BD8336B0B03E4080055103E /* HTTPMultipartUpload.m in Sources */,
+ 930DA26025ED56DB008558E3 /* dwarf2reader.cc in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -175,7 +371,13 @@
1DEB927508733DD40010E9CD /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
- HEADER_SEARCH_PATHS = ../../..;
+ CLANG_CXX_LANGUAGE_STANDARD = "c++0x";
+ GCC_PREPROCESSOR_DEFINITIONS = HAVE_MACH_O_NLIST_H;
+ HEADER_SEARCH_PATHS = (
+ ../../..,
+ ../../../common/mac/include,
+ ../../../third_party/musl/include/,
+ );
PRODUCT_NAME = symupload;
};
name = Debug;
@@ -183,7 +385,17 @@
1DEB927608733DD40010E9CD /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
- HEADER_SEARCH_PATHS = ../../..;
+ CLANG_CXX_LANGUAGE_STANDARD = "c++0x";
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "$(inherited)",
+ NDEBUG,
+ HAVE_MACH_O_NLIST_H,
+ );
+ HEADER_SEARCH_PATHS = (
+ ../../..,
+ ../../../common/mac/include,
+ ../../../third_party/musl/include/,
+ );
PRODUCT_NAME = symupload;
};
name = Release;
diff --git a/src/tools/mac/tools_mac.gypi b/src/tools/mac/tools_mac.gypi
deleted file mode 100644
index 7457573b..00000000
--- a/src/tools/mac/tools_mac.gypi
+++ /dev/null
@@ -1,116 +0,0 @@
-# Copyright 2014 Google Inc. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-# * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-# * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-{
- 'target_defaults': {
- 'include_dirs': [
- '../..',
- ],
- },
- 'targets': [
- {
- 'target_name': 'crash_report',
- 'type': 'executable',
- 'sources': [
- 'crash_report/crash_report.mm',
- 'crash_report/on_demand_symbol_supplier.h',
- 'crash_report/on_demand_symbol_supplier.mm',
- ],
- 'link_settings': {
- 'libraries': [
- '$(SDKROOT)/System/Library/Frameworks/Foundation.framework',
- ],
- },
- 'dependencies': [
- '../common/common.gyp:common',
- '../processor/processor.gyp:processor',
- ],
- },
- {
- 'target_name': 'dump_syms',
- 'type': 'executable',
- 'sources': [
- 'dump_syms/dump_syms_tool.cc',
- ],
- 'link_settings': {
- 'libraries': [
- '$(SDKROOT)/System/Library/Frameworks/Foundation.framework',
- ],
- },
- 'dependencies': [
- '../common/common.gyp:common',
- ],
- },
- {
- 'target_name': 'macho_dump',
- 'type': 'executable',
- 'sources': [
- 'dump_syms/macho_dump.cc',
- ],
- 'dependencies': [
- '../common/common.gyp:common',
- ],
- },
- {
- 'target_name': 'minidump_upload',
- 'type': 'executable',
- 'sources': [
- 'symupload/minidump_upload.m',
- ],
- 'include_dirs': [
- '../../common/mac',
- ],
- 'link_settings': {
- 'libraries': [
- '$(SDKROOT)/System/Library/Frameworks/Foundation.framework',
- ],
- },
- 'dependencies': [
- '../common/common.gyp:common',
- ],
- },
- {
- 'target_name': 'symupload',
- 'type': 'executable',
- 'sources': [
- 'symupload/symupload.m',
- ],
- 'include_dirs': [
- '../../common/mac',
- ],
- 'link_settings': {
- 'libraries': [
- '$(SDKROOT)/System/Library/Frameworks/Foundation.framework',
- ],
- },
- 'dependencies': [
- '../common/common.gyp:common',
- ],
- },
- ],
-}
diff --git a/src/tools/mac/upload_system_symbols/arch_constants.h b/src/tools/mac/upload_system_symbols/arch_constants.h
index e12e53e2..b6dbc89a 100644
--- a/src/tools/mac/upload_system_symbols/arch_constants.h
+++ b/src/tools/mac/upload_system_symbols/arch_constants.h
@@ -1,5 +1,4 @@
-/* Copyright 2014, Google Inc.
-All rights reserved.
+/* Copyright 2014 Google LLC
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@ notice, this list of conditions and the following disclaimer.
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
- * Neither the name of Google Inc. nor the names of its
+ * Neither the name of Google LLC nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
diff --git a/src/tools/mac/upload_system_symbols/arch_reader.go b/src/tools/mac/upload_system_symbols/arch_reader.go
index ed98fa60..03a76421 100644
--- a/src/tools/mac/upload_system_symbols/arch_reader.go
+++ b/src/tools/mac/upload_system_symbols/arch_reader.go
@@ -1,5 +1,4 @@
-/* Copyright 2014, Google Inc.
-All rights reserved.
+/* Copyright 2014 Google LLC
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@ notice, this list of conditions and the following disclaimer.
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
- * Neither the name of Google Inc. nor the names of its
+ * Neither the name of Google LLC nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
diff --git a/src/tools/mac/upload_system_symbols/go.mod b/src/tools/mac/upload_system_symbols/go.mod
new file mode 100644
index 00000000..ff21bba9
--- /dev/null
+++ b/src/tools/mac/upload_system_symbols/go.mod
@@ -0,0 +1,3 @@
+module upload_system_symbols
+
+go 1.17
diff --git a/src/tools/mac/upload_system_symbols/upload_system_symbols.go b/src/tools/mac/upload_system_symbols/upload_system_symbols.go
index 05a7764a..ba067276 100644
--- a/src/tools/mac/upload_system_symbols/upload_system_symbols.go
+++ b/src/tools/mac/upload_system_symbols/upload_system_symbols.go
@@ -1,5 +1,4 @@
-/* Copyright 2014, Google Inc.
-All rights reserved.
+/* Copyright 2014 Google LLC
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@ notice, this list of conditions and the following disclaimer.
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
- * Neither the name of Google Inc. nor the names of its
+ * Neither the name of Google LLC nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
@@ -64,12 +63,12 @@ var (
dumpOnlyPath = flag.String("dump-to", "", "Dump the symbols to the specified directory, but do not upload them.")
systemRoot = flag.String("system-root", "", "Path to the root of the Mac OS X system whose symbols will be dumped.")
dumpArchitecture = flag.String("arch", "", "The CPU architecture for which symbols should be dumped. If not specified, dumps all architectures.")
+ apiKey = flag.String("api-key", "", "API key to use. If this is present, the `sym-upload-v2` protocol is used.\nSee https://chromium.googlesource.com/breakpad/breakpad/+/HEAD/docs/sym_upload_v2_protocol.md or\n`symupload`'s help for more information.")
)
var (
// pathsToScan are the subpaths in the systemRoot that should be scanned for shared libraries.
pathsToScan = []string{
- "/System/Library/Components",
"/System/Library/Frameworks",
"/System/Library/PrivateFrameworks",
"/usr/lib",
@@ -79,13 +78,26 @@ var (
optionalPathsToScan = []string{
// Gone in 10.15.
"/Library/QuickTime",
+ // Not present in dumped dyld_shared_caches
+ "/System/Library/Components",
}
- // uploadServers are the list of servers to which symbols should be uploaded.
- uploadServers = []string{
+ // uploadServersV1 are the list of servers to which symbols should be
+ // uploaded when using the V1 protocol.
+ uploadServersV1 = []string{
"https://clients2.google.com/cr/symbol",
"https://clients2.google.com/cr/staging_symbol",
}
+ // uploadServersV2 are the list of servers to which symbols should be
+ // uploaded when using the V2 protocol.
+ uploadServersV2 = []string{
+ "https://staging-crashsymbolcollector-pa.googleapis.com",
+ "https://prod-crashsymbolcollector-pa.googleapis.com",
+ }
+
+ // uploadServers are the list of servers that should be used, accounting
+ // for whether v1 or v2 protocol is used.
+ uploadServers = uploadServersV1
// blacklistRegexps match paths that should be excluded from dumping.
blacklistRegexps = []*regexp.Regexp{
@@ -102,6 +114,11 @@ func main() {
flag.Parse()
log.SetFlags(0)
+ // If `apiKey` is set, we're using the v2 protocol.
+ if len(*apiKey) > 0 {
+ uploadServers = uploadServersV2
+ }
+
var uq *UploadQueue
if *uploadOnlyPath != "" {
@@ -195,17 +212,29 @@ func (uq *UploadQueue) Done() {
close(uq.queue)
}
-func (uq *UploadQueue) worker() {
+func (uq *UploadQueue) runSymUpload(symfile, server string) *exec.Cmd {
symUpload := path.Join(*breakpadTools, "symupload")
+ args := []string{symfile, server}
+ if len(*apiKey) > 0 {
+ args = append([]string{"-p", "sym-upload-v2", "-k", *apiKey}, args...)
+ }
+ return exec.Command(symUpload, args...)
+}
+func (uq *UploadQueue) worker() {
for symfile := range uq.queue {
for _, server := range uploadServers {
for i := 0; i < 3; i++ { // Give each upload 3 attempts to succeed.
- cmd := exec.Command(symUpload, symfile, server)
+ cmd := uq.runSymUpload(symfile, server)
if output, err := cmd.Output(); err == nil {
// Success. No retry needed.
fmt.Printf("Uploaded %s to %s\n", symfile, server)
break
+ } else if exitError, ok := err.(*exec.ExitError); ok && exitError.ExitCode() == 2 && *apiKey != "" {
+ // Exit code 2 in protocol v2 means the file already exists on the server.
+ // No point retrying.
+ fmt.Printf("File %s already exists on %s\n", symfile, server)
+ break
} else {
log.Printf("Error running symupload(%s, %s), attempt %d: %v: %s\n", symfile, server, i, err, output)
time.Sleep(1 * time.Second)
diff --git a/src/tools/python/deps-to-manifest.py b/src/tools/python/deps-to-manifest.py
index b4562854..2fcaf771 100755
--- a/src/tools/python/deps-to-manifest.py
+++ b/src/tools/python/deps-to-manifest.py
@@ -1,6 +1,5 @@
#!/usr/bin/python
-# Copyright 2016 Google Inc.
-# All rights reserved.
+# Copyright 2016 Google LLC
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
@@ -12,7 +11,7 @@
# copyright notice, this list of conditions and the following disclaimer
# in the documentation and/or other materials provided with the
# distribution.
-# * Neither the name of Google Inc. nor the names of its
+# * Neither the name of Google LLC nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
@@ -49,7 +48,7 @@ MANIFEST_HEAD = """<?xml version='1.0' encoding='UTF-8'?>
<!-- AUTOGENERATED BY %(prog)s; DO NOT EDIT -->
<manifest>
- <default revision='refs/heads/master'
+ <default revision='refs/heads/main'
remote='chromium'
sync-c='true'
sync-j='8' />
@@ -100,7 +99,7 @@ def ConvertDepsToManifest(deps, manifest):
data = {
'path': 'src',
'name': 'breakpad/breakpad',
- 'revision': 'refs/heads/master',
+ 'revision': 'refs/heads/main',
'remote': 'chromium',
}
new_contents += MANIFEST_PROJECT % data
diff --git a/src/tools/python/filter_syms.py b/src/tools/python/filter_syms.py
index abddf789..caf3693a 100644
--- a/src/tools/python/filter_syms.py
+++ b/src/tools/python/filter_syms.py
@@ -1,6 +1,5 @@
#!/usr/bin/env python
-# Copyright (c) 2012 Google Inc.
-# All rights reserved.
+# Copyright 2012 Google LLC
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
@@ -12,7 +11,7 @@
# copyright notice, this list of conditions and the following disclaimer
# in the documentation and/or other materials provided with the
# distribution.
-# * Neither the name of Google Inc. nor the names of its
+# * Neither the name of Google LLC nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
diff --git a/src/tools/python/tests/filter_syms_unittest.py b/src/tools/python/tests/filter_syms_unittest.py
index b111f349..1081fc73 100644
--- a/src/tools/python/tests/filter_syms_unittest.py
+++ b/src/tools/python/tests/filter_syms_unittest.py
@@ -1,6 +1,5 @@
#!/usr/bin/env python
-# Copyright (c) 2012 Google Inc.
-# All rights reserved.
+# Copyright 2012 Google LLC
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
@@ -12,7 +11,7 @@
# copyright notice, this list of conditions and the following disclaimer
# in the documentation and/or other materials provided with the
# distribution.
-# * Neither the name of Google Inc. nor the names of its
+# * Neither the name of Google LLC nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
diff --git a/src/tools/solaris/dump_syms/Makefile b/src/tools/solaris/dump_syms/Makefile
index ff77105c..c5f48240 100644
--- a/src/tools/solaris/dump_syms/Makefile
+++ b/src/tools/solaris/dump_syms/Makefile
@@ -1,5 +1,4 @@
-# Copyright (c) 2007, Google Inc.
-# All rights reserved.
+# Copyright 2007 Google LLC
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
# copyright notice, this list of conditions and the following disclaimer
# in the documentation and/or other materials provided with the
# distribution.
-# * Neither the name of Google Inc. nor the names of its
+# * Neither the name of Google LLC nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
diff --git a/src/tools/solaris/dump_syms/dump_syms.cc b/src/tools/solaris/dump_syms/dump_syms.cc
index 54cea57e..fc331c21 100644
--- a/src/tools/solaris/dump_syms/dump_syms.cc
+++ b/src/tools/solaris/dump_syms/dump_syms.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2007, Google Inc.
-// All rights reserved.
+// Copyright 2007 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -36,13 +35,13 @@
using namespace google_breakpad;
-int main(int argc, char **argv) {
+int main(int argc, char** argv) {
if (argc != 2) {
fprintf(stderr, "Usage: %s <binary-with-stab-symbol>\n", argv[0]);
return 1;
}
- const char *binary = argv[1];
+ const char* binary = argv[1];
DumpSymbols dumper;
if (!dumper.WriteSymbolFile(binary, fileno(stdout))) {
diff --git a/src/tools/solaris/dump_syms/run_regtest.sh b/src/tools/solaris/dump_syms/run_regtest.sh
index ffb34330..27710d9a 100644
--- a/src/tools/solaris/dump_syms/run_regtest.sh
+++ b/src/tools/solaris/dump_syms/run_regtest.sh
@@ -1,7 +1,6 @@
#!/bin/sh
-# Copyright (c) 2007, Google Inc.
-# All rights reserved.
+# Copyright 2007 Google LLC
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
@@ -13,7 +12,7 @@
# copyright notice, this list of conditions and the following disclaimer
# in the documentation and/or other materials provided with the
# distribution.
-# * Neither the name of Google Inc. nor the names of its
+# * Neither the name of Google LLC nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
diff --git a/src/tools/solaris/dump_syms/testdata/dump_syms_regtest.cc b/src/tools/solaris/dump_syms/testdata/dump_syms_regtest.cc
index e617a23b..b4d191bd 100644
--- a/src/tools/solaris/dump_syms/testdata/dump_syms_regtest.cc
+++ b/src/tools/solaris/dump_syms/testdata/dump_syms_regtest.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2007, Google Inc.
-// All rights reserved.
+// Copyright 2007 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -41,7 +40,7 @@ class C {
void f() { member_ = g(); }
virtual int g() { return 2; }
- static char* h(const C &that) { return 0; }
+ static char* h(const C& that) { return 0; }
private:
int member_;
@@ -53,12 +52,12 @@ static int i() {
} // namespace google_breakpad
-int main(int argc, char **argv) {
+int main(int argc, char** argv) {
google_breakpad::C object;
object.set_member(google_breakpad::i());
object.f();
int value = object.g();
- char *nothing = object.h(object);
+ char* nothing = object.h(object);
return 0;
}
diff --git a/src/tools/tools.gyp b/src/tools/tools.gyp
deleted file mode 100644
index e6a4210f..00000000
--- a/src/tools/tools.gyp
+++ /dev/null
@@ -1,38 +0,0 @@
-# Copyright 2014 Google Inc. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-# * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-# * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-{
- 'conditions': [
- ['OS=="mac"', {
- 'includes': ['mac/tools_mac.gypi'],
- }],
- ['OS=="linux"', {
- 'includes': ['linux/tools_linux.gypi'],
- }],
- ],
-}
diff --git a/src/tools/windows/converter/ms_symbol_server_converter.cc b/src/tools/windows/converter/ms_symbol_server_converter.cc
index 2b40faee..bfe46925 100644
--- a/src/tools/windows/converter/ms_symbol_server_converter.cc
+++ b/src/tools/windows/converter/ms_symbol_server_converter.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2007, Google Inc.
-// All rights reserved.
+// Copyright 2007 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -92,7 +91,7 @@ namespace google_breakpad {
#endif // _MSC_VER >= 1400
bool GUIDOrSignatureIdentifier::InitializeFromString(
- const string &identifier) {
+ const string& identifier) {
type_ = TYPE_NONE;
size_t length = identifier.length();
@@ -128,11 +127,15 @@ bool GUIDOrSignatureIdentifier::InitializeFromString(
#undef SSCANF
MSSymbolServerConverter::MSSymbolServerConverter(
- const string &local_cache, const vector<string> &symbol_servers)
+ const string& local_cache,
+ const vector<string>& symbol_servers,
+ bool trace_symsrv)
: symbol_path_(),
fail_dns_(false),
fail_timeout_(false),
- fail_not_found_(false) {
+ fail_http_https_redir_(false),
+ fail_not_found_(false),
+ trace_symsrv_(trace_symsrv) {
// Setting local_cache can be done without verifying that it exists because
// SymSrv will create it if it is missing - any creation failures will occur
// at that time, so there's nothing to check here, making it safe to
@@ -184,7 +187,7 @@ class AutoSymSrv {
}
}
- bool Initialize(HANDLE process, char *path, bool invade_process) {
+ bool Initialize(HANDLE process, char* path, bool invade_process) {
process_ = process;
// TODO(nbilling): Figure out why dbghelp.dll is being loaded from
@@ -240,7 +243,7 @@ class AutoSymSrv {
// are supported by calling Delete().
class AutoDeleter {
public:
- explicit AutoDeleter(const string &path) : path_(path) {}
+ explicit AutoDeleter(const string& path) : path_(path) {}
~AutoDeleter() {
int error;
@@ -270,10 +273,10 @@ class AutoDeleter {
};
MSSymbolServerConverter::LocateResult
-MSSymbolServerConverter::LocateFile(const string &debug_or_code_file,
- const string &debug_or_code_id,
- const string &version,
- string *file_name) {
+MSSymbolServerConverter::LocateFile(const string& debug_or_code_file,
+ const string& debug_or_code_id,
+ const string& version,
+ string* file_name) {
assert(file_name);
file_name->clear();
@@ -290,7 +293,7 @@ MSSymbolServerConverter::LocateFile(const string &debug_or_code_file,
HANDLE process = GetCurrentProcess(); // CloseHandle is not needed.
AutoSymSrv symsrv;
if (!symsrv.Initialize(process,
- const_cast<char *>(symbol_path_.c_str()),
+ const_cast<char*>(symbol_path_.c_str()),
false)) {
fprintf(stderr, "LocateFile: SymInitialize: error %lu for %s %s %s\n",
GetLastError(),
@@ -326,8 +329,8 @@ MSSymbolServerConverter::LocateFile(const string &debug_or_code_file,
char path[MAX_PATH];
if (!SymFindFileInPath(
process, NULL,
- const_cast<char *>(debug_or_code_file.c_str()),
- const_cast<void *>(identifier.guid_or_signature_pointer()),
+ const_cast<char*>(debug_or_code_file.c_str()),
+ const_cast<void*>(identifier.guid_or_signature_pointer()),
identifier.age(), 0,
identifier.type() == GUIDOrSignatureIdentifier::TYPE_GUID ?
SSRVOPT_GUIDPTR : SSRVOPT_DWORDPTR,
@@ -342,6 +345,10 @@ MSSymbolServerConverter::LocateFile(const string &debug_or_code_file,
return LOCATE_RETRY;
}
+ if (fail_http_https_redir_) {
+ return LOCATE_HTTP_HTTPS_REDIR;
+ }
+
// This is an authoritiative file-not-found message.
if (fail_not_found_) {
fprintf(stderr,
@@ -393,15 +400,15 @@ MSSymbolServerConverter::LocateFile(const string &debug_or_code_file,
MSSymbolServerConverter::LocateResult
-MSSymbolServerConverter::LocatePEFile(const MissingSymbolInfo &missing,
- string *pe_file) {
+MSSymbolServerConverter::LocatePEFile(const MissingSymbolInfo& missing,
+ string* pe_file) {
return LocateFile(missing.code_file, missing.code_identifier,
missing.version, pe_file);
}
MSSymbolServerConverter::LocateResult
-MSSymbolServerConverter::LocateSymbolFile(const MissingSymbolInfo &missing,
- string *symbol_file) {
+MSSymbolServerConverter::LocateSymbolFile(const MissingSymbolInfo& missing,
+ string* symbol_file) {
return LocateFile(missing.debug_file, missing.debug_identifier,
missing.version, symbol_file);
}
@@ -412,51 +419,58 @@ BOOL CALLBACK MSSymbolServerConverter::SymCallback(HANDLE process,
ULONG action,
ULONG64 data,
ULONG64 context) {
- MSSymbolServerConverter *self =
- reinterpret_cast<MSSymbolServerConverter *>(context);
+ MSSymbolServerConverter* self =
+ reinterpret_cast<MSSymbolServerConverter*>(context);
switch (action) {
case CBA_EVENT: {
- IMAGEHLP_CBA_EVENT *cba_event =
- reinterpret_cast<IMAGEHLP_CBA_EVENT *>(data);
+ IMAGEHLP_CBA_EVENT* cba_event =
+ reinterpret_cast<IMAGEHLP_CBA_EVENT*>(data);
// Put the string into a string object to be able to use string::find
// for substring matching. This is important because the not-found
// message does not use the entire string but is appended to the URL
// that SymSrv attempted to retrieve.
string desc(cba_event->desc);
+ if (self->trace_symsrv_) {
+ fprintf(stderr, "LocateFile: SymCallback: action desc '%s'\n",
+ desc.c_str());
+ }
// desc_action maps strings (in desc) to boolean pointers that are to
// be set to true if the string matches.
struct desc_action {
- const char *desc; // The substring to match.
- bool *action; // On match, this pointer will be set to true.
+ const char* desc; // The substring to match.
+ bool* action; // On match, this pointer will be set to true.
};
static const desc_action desc_actions[] = {
- // When a DNS error occurs, it could be indiciative of network
- // problems.
- { "SYMSRV: The server name or address could not be resolved\n",
- &self->fail_dns_ },
-
- // This message is produced if no connection is opened.
- { "SYMSRV: A connection with the server could not be established\n",
- &self->fail_timeout_ },
-
- // This message is produced if a connection is established but the
- // server fails to respond to the HTTP request.
- { "SYMSRV: The operation timed out\n",
- &self->fail_timeout_ },
-
- // This message is produced when the requested file is not found,
- // even if one or more of the above messages are also produced.
- // It's trapped to distinguish between not-found and unknown-failure
- // conditions. Note that this message will not be produced if a
- // connection is established and the server begins to respond to the
- // HTTP request but does not finish transmitting the file.
- { " not found\n",
- &self->fail_not_found_ }
- };
+ // When a DNS error occurs, it could be indiciative of network
+ // problems.
+ {"SYMSRV: The server name or address could not be resolved\n",
+ &self->fail_dns_},
+
+ // This message is produced if no connection is opened.
+ {"SYMSRV: A connection with the server could not be established\n",
+ &self->fail_timeout_},
+
+ // This message is produced if a connection is established but the
+ // server fails to respond to the HTTP request.
+ {"SYMSRV: The operation timed out\n", &self->fail_timeout_},
+
+ // This message is produced if the server is redirecting us from http
+ // to https. When this happens SymSrv will fail and we need to use
+ // the https URL in our call-- we've made a mistake.
+ {"ERROR_INTERNET_HTTP_TO_HTTPS_ON_REDIR\n",
+ &self->fail_http_https_redir_},
+
+ // This message is produced when the requested file is not found,
+ // even if one or more of the above messages are also produced.
+ // It's trapped to distinguish between not-found and unknown-failure
+ // conditions. Note that this message will not be produced if a
+ // connection is established and the server begins to respond to the
+ // HTTP request but does not finish transmitting the file.
+ {" not found\n", &self->fail_not_found_}};
for (int desc_action_index = 0;
desc_action_index <
@@ -478,7 +492,7 @@ BOOL CALLBACK MSSymbolServerConverter::SymCallback(HANDLE process,
// static
BOOL CALLBACK MSSymbolServerConverter::SymFindFileInPathCallback(
- const char *filename, void *context) {
+ const char* filename, void* context) {
// FALSE ends the search, indicating that the located symbol file is
// satisfactory.
return FALSE;
@@ -486,12 +500,12 @@ BOOL CALLBACK MSSymbolServerConverter::SymFindFileInPathCallback(
MSSymbolServerConverter::LocateResult
MSSymbolServerConverter::LocateAndConvertSymbolFile(
- const MissingSymbolInfo &missing,
+ const MissingSymbolInfo& missing,
bool keep_symbol_file,
bool keep_pe_file,
- string *converted_symbol_file,
- string *symbol_file,
- string *out_pe_file) {
+ string* converted_symbol_file,
+ string* symbol_file,
+ string* out_pe_file) {
assert(converted_symbol_file);
converted_symbol_file->clear();
if (symbol_file) {
@@ -580,7 +594,7 @@ MSSymbolServerConverter::LocateAndConvertSymbolFile(
*converted_symbol_file = pdb_file.substr(0, pdb_file.length() - 4) + ".sym";
- FILE *converted_output = NULL;
+ FILE* converted_output = NULL;
#if _MSC_VER >= 1400 // MSVC 2005/8
errno_t err;
if ((err = fopen_s(&converted_output, converted_symbol_file->c_str(), "w"))
@@ -634,10 +648,10 @@ MSSymbolServerConverter::LocateAndConvertSymbolFile(
MSSymbolServerConverter::LocateResult
MSSymbolServerConverter::LocateAndConvertPEFile(
- const MissingSymbolInfo &missing,
+ const MissingSymbolInfo& missing,
bool keep_pe_file,
- string *converted_symbol_file,
- string *out_pe_file) {
+ string* converted_symbol_file,
+ string* out_pe_file) {
assert(converted_symbol_file);
converted_symbol_file->clear();
@@ -676,7 +690,7 @@ MSSymbolServerConverter::LocateAndConvertPEFile(
*converted_symbol_file = pe_file.substr(0, pe_file.length() - 4) + ".sym";
- FILE *converted_output = NULL;
+ FILE* converted_output = NULL;
#if _MSC_VER >= 1400 // MSVC 2005/8
errno_t err;
if ((err = fopen_s(&converted_output, converted_symbol_file->c_str(), "w"))
diff --git a/src/tools/windows/converter/ms_symbol_server_converter.gyp b/src/tools/windows/converter/ms_symbol_server_converter.gyp
deleted file mode 100644
index 57ec7906..00000000
--- a/src/tools/windows/converter/ms_symbol_server_converter.gyp
+++ /dev/null
@@ -1,46 +0,0 @@
-# Copyright 2013 Google Inc. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-# * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-# * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-{
- 'includes': [
- '../../../build/common.gypi',
- ],
- 'targets': [
- {
- 'target_name': 'ms_symbol_server_converter',
- 'type': 'static_library',
- 'msvs_guid': '1463C4CD-23FC-4DE9-BFDE-283338200157',
- 'sources': [
- 'ms_symbol_server_converter.cc',
- ],
- 'dependencies': [
- '../../../common/windows/common_windows.gyp:common_windows_lib',
- ],
- },
- ],
-}
diff --git a/src/tools/windows/converter/ms_symbol_server_converter.h b/src/tools/windows/converter/ms_symbol_server_converter.h
index 401f7c34..ffdea7c0 100644
--- a/src/tools/windows/converter/ms_symbol_server_converter.h
+++ b/src/tools/windows/converter/ms_symbol_server_converter.h
@@ -1,5 +1,4 @@
-// Copyright (c) 2007, Google Inc.
-// All rights reserved.
+// Copyright 2007 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -101,13 +100,13 @@ class GUIDOrSignatureIdentifier {
// component fields: either a GUID and age, or signature and age. If
// successful, sets the relevant fields in the object, including the type
// field, and returns true. On error, returns false.
- bool InitializeFromString(const string &identifier);
+ bool InitializeFromString(const string& identifier);
GUIDOrSignatureType type() const { return type_; }
GUID guid() const { return guid_; }
DWORD signature() const { return signature_; }
int age() const { return age_; }
- const void *guid_or_signature_pointer() const { return &guid_; }
+ const void* guid_or_signature_pointer() const { return &guid_; }
private:
GUIDOrSignatureType type_;
@@ -127,9 +126,10 @@ class MSSymbolServerConverter {
public:
enum LocateResult {
LOCATE_FAILURE = 0,
- LOCATE_NOT_FOUND, // Authoritative: the file is not present.
- LOCATE_RETRY, // Transient (network?) error, try again later.
- LOCATE_SUCCESS
+ LOCATE_NOT_FOUND, // Authoritative: the file is not present.
+ LOCATE_RETRY, // Transient (network?) error, try again later.
+ LOCATE_SUCCESS,
+ LOCATE_HTTP_HTTPS_REDIR
};
// Create a new object. local_cache is the location (pathname) of a local
@@ -141,23 +141,26 @@ class MSSymbolServerConverter {
// store to try. The vector must contain at least one string. None of the
// strings passed to this constructor may contain asterisk ('*') or semicolon
// (';') characters, as the symbol engine uses these characters as separators.
- MSSymbolServerConverter(const string &local_cache,
- const vector<string> &symbol_servers);
+ // If |trace_symsrv| is set then callbacks from SymSrv will be logged to
+ // stderr.
+ MSSymbolServerConverter(const string& local_cache,
+ const vector<string>& symbol_servers,
+ bool trace_symsrv);
// Locates the PE file (DLL or EXE) specified by the identifying information
// in |missing|, by checking the symbol stores identified when the object
// was created. When returning LOCATE_SUCCESS, pe_file is set to
// the pathname of the decompressed PE file as it is stored in the
// local cache.
- LocateResult LocatePEFile(const MissingSymbolInfo &missing, string *pe_file);
+ LocateResult LocatePEFile(const MissingSymbolInfo& missing, string* pe_file);
// Locates the symbol file specified by the identifying information in
// |missing|, by checking the symbol stores identified when the object
// was created. When returning LOCATE_SUCCESS, symbol_file is set to
// the pathname of the decompressed symbol file as it is stored in the
// local cache.
- LocateResult LocateSymbolFile(const MissingSymbolInfo &missing,
- string *symbol_file);
+ LocateResult LocateSymbolFile(const MissingSymbolInfo& missing,
+ string* symbol_file);
// Calls LocateSymbolFile and converts the returned symbol file to the
// dumped-symbol format, storing it adjacent to the symbol file. The
@@ -170,12 +173,12 @@ class MSSymbolServerConverter {
// is desired, set |keep_symbol_file| and |keep_pe_file| to false to indicate
// that the original symbol file (pdb) and executable file (exe, dll) should
// be deleted after conversion.
- LocateResult LocateAndConvertSymbolFile(const MissingSymbolInfo &missing,
+ LocateResult LocateAndConvertSymbolFile(const MissingSymbolInfo& missing,
bool keep_symbol_file,
bool keep_pe_file,
- string *converted_symbol_file,
- string *symbol_file,
- string *pe_file);
+ string* converted_symbol_file,
+ string* symbol_file,
+ string* pe_file);
// Calls LocatePEFile and converts the returned PE file to the
// dumped-symbol format, storing it adjacent to the PE file. The
@@ -188,10 +191,10 @@ class MSSymbolServerConverter {
// to false to indicate that the executable file (exe, dll) should be deleted
// after conversion.
// NOTE: Currrently only supports x64 PEs.
- LocateResult LocateAndConvertPEFile(const MissingSymbolInfo &missing,
- bool keep_pe_file,
- string *converted_symbol_file,
- string *pe_file);
+ LocateResult LocateAndConvertPEFile(const MissingSymbolInfo& missing,
+ bool keep_pe_file,
+ string* converted_symbol_file,
+ string* pe_file);
private:
// Locates the PDB or PE file (DLL or EXE) specified by the identifying
@@ -199,9 +202,9 @@ class MSSymbolServerConverter {
// the symbol stores identified when the object was created. When
// returning LOCATE_SUCCESS, file_name is set to the pathname of the
// decompressed PDB or PE file file as it is stored in the local cache.
- LocateResult LocateFile(const string &debug_or_code_file,
- const string &debug_or_code_id,
- const string &version, string *file_name);
+ LocateResult LocateFile(const string& debug_or_code_file,
+ const string& debug_or_code_id,
+ const string& version, string* file_name);
// Called by various SymSrv functions to report status as progress is made
// and to allow the callback to influence processing. Messages sent to this
@@ -215,8 +218,8 @@ class MSSymbolServerConverter {
// SymFindFileInPath actually seems to accept NULL for a callback function
// and behave properly for our needs in that case, but the documentation
// doesn't mention it, so this little callback is provided.
- static BOOL CALLBACK SymFindFileInPathCallback(const char *filename,
- void *context);
+ static BOOL CALLBACK SymFindFileInPathCallback(const char* filename,
+ void* context);
// The search path used by SymSrv, built based on the arguments to the
// constructor.
@@ -226,8 +229,12 @@ class MSSymbolServerConverter {
// SymFindFileInPath fails for an expected reason.
bool fail_dns_; // DNS failures (fail_not_found_ will also be set).
bool fail_timeout_; // Timeouts (fail_not_found_ will also be set).
+ bool fail_http_https_redir_; // Bad URL-- we should be using HTTPS.
bool fail_not_found_; // The file could not be found. If this is the only
// fail_* member set, then it is authoritative.
+
+ // If set then callbacks from SymSrv will be logged to stderr.
+ bool trace_symsrv_;
};
} // namespace google_breakpad
diff --git a/src/tools/windows/converter_exe/converter.cc b/src/tools/windows/converter_exe/converter.cc
index 5b70903a..75ec55b0 100644
--- a/src/tools/windows/converter_exe/converter.cc
+++ b/src/tools/windows/converter_exe/converter.cc
@@ -1,807 +1,904 @@
-// Copyright 2019 Google Inc. All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-#pragma comment(lib, "winhttp.lib")
-#pragma comment(lib, "wininet.lib")
-#pragma comment(lib, "diaguids.lib")
-#pragma comment(lib, "imagehlp.lib")
-
-#include <cassert>
-#include <cstdio>
-#include <ctime>
-#include <map>
-#include <regex>
-#include <string>
-#include <vector>
-
-#include "tools/windows/converter_exe/escaping.h"
-#include "tools/windows/converter_exe/http_download.h"
-#include "tools/windows/converter_exe/tokenizer.h"
-#include "common/windows/http_upload.h"
-#include "common/windows/string_utils-inl.h"
-#include "tools/windows/converter/ms_symbol_server_converter.h"
-
-using strings::WebSafeBase64Unescape;
-using strings::WebSafeBase64Escape;
-
-namespace {
-
-using std::map;
-using std::string;
-using std::vector;
-using std::wstring;
-using crash::HTTPDownload;
-using crash::Tokenizer;
-using google_breakpad::HTTPUpload;
-using google_breakpad::MissingSymbolInfo;
-using google_breakpad::MSSymbolServerConverter;
-using google_breakpad::WindowsStringUtils;
-
-const char *kMissingStringDelimiters = "|";
-const char *kLocalCachePath = "c:\\symbols";
-const char *kNoExeMSSSServer = "http://msdl.microsoft.com/download/symbols/";
-
-// Windows stdio doesn't do line buffering. Use this function to flush after
-// writing to stdout and stderr so that a log will be available if the
-// converter crashes.
-static int FprintfFlush(FILE *file, const char *format, ...) {
- va_list arguments;
- va_start(arguments, format);
- int retval = vfprintf(file, format, arguments);
- va_end(arguments);
- fflush(file);
- return retval;
-}
-
-static string CurrentDateAndTime() {
- const string kUnknownDateAndTime = R"(????-??-?? ??:??:??)";
-
- time_t current_time;
- time(&current_time);
-
- // localtime_s is safer but is only available in MSVC8. Use localtime
- // in earlier environments.
- struct tm *time_pointer;
-#if _MSC_VER >= 1400 // MSVC 2005/8
- struct tm time_struct;
- time_pointer = &time_struct;
- if (localtime_s(time_pointer, &current_time) != 0) {
- return kUnknownDateAndTime;
- }
-#else // _MSC_VER >= 1400
- time_pointer = localtime(&current_time);
- if (!time_pointer) {
- return kUnknownDateAndTime;
- }
-#endif // _MSC_VER >= 1400
-
- char buffer[256];
- if (!strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", time_pointer)) {
- return kUnknownDateAndTime;
- }
-
- return string(buffer);
-}
-
-// ParseMissingString turns |missing_string| into a MissingSymbolInfo
-// structure. It returns true on success, and false if no such conversion
-// is possible.
-static bool ParseMissingString(const string &missing_string,
- MissingSymbolInfo *missing_info) {
- assert(missing_info);
-
- vector<string> tokens;
- Tokenizer::Tokenize(kMissingStringDelimiters, missing_string, &tokens);
- if (tokens.size() != 5) {
- return false;
- }
-
- missing_info->debug_file = tokens[0];
- missing_info->debug_identifier = tokens[1];
- missing_info->version = tokens[2];
- missing_info->code_file = tokens[3];
- missing_info->code_identifier = tokens[4];
-
- return true;
-}
-
-// StringMapToWStringMap takes each element in a map that associates
-// (narrow) strings to strings and converts the keys and values to wstrings.
-// Returns true on success and false on failure, printing an error message.
-static bool StringMapToWStringMap(const map<string, string> &smap,
- map<wstring, wstring> *wsmap) {
- assert(wsmap);
- wsmap->clear();
-
- for (map<string, string>::const_iterator iterator = smap.begin();
- iterator != smap.end();
- ++iterator) {
- wstring key;
- if (!WindowsStringUtils::safe_mbstowcs(iterator->first, &key)) {
- FprintfFlush(stderr,
- "StringMapToWStringMap: safe_mbstowcs failed for key %s\n",
- iterator->first.c_str());
- return false;
- }
-
- wstring value;
- if (!WindowsStringUtils::safe_mbstowcs(iterator->second, &value)) {
- FprintfFlush(stderr, "StringMapToWStringMap: safe_mbstowcs failed "
- "for value %s\n",
- iterator->second.c_str());
- return false;
- }
-
- wsmap->insert(make_pair(key, value));
- }
-
- return true;
-}
-
-// MissingSymbolInfoToParameters turns a MissingSymbolInfo structure into a
-// map of parameters suitable for passing to HTTPDownload or HTTPUpload.
-// Returns true on success and false on failure, printing an error message.
-static bool MissingSymbolInfoToParameters(const MissingSymbolInfo &missing_info,
- map<wstring, wstring> *wparameters) {
- assert(wparameters);
-
- map<string, string> parameters;
- string encoded_param;
- // Indicate the params are encoded.
- parameters["encoded"] = "true"; // The string value here does not matter.
-
- WebSafeBase64Escape(missing_info.code_file, &encoded_param);
- parameters["code_file"] = encoded_param;
-
- WebSafeBase64Escape(missing_info.code_identifier, &encoded_param);
- parameters["code_identifier"] = encoded_param;
-
- WebSafeBase64Escape(missing_info.debug_file, &encoded_param);
- parameters["debug_file"] = encoded_param;
-
- WebSafeBase64Escape(missing_info.debug_identifier, &encoded_param);
- parameters["debug_identifier"] = encoded_param;
-
- if (!missing_info.version.empty()) {
- // The version is optional.
- WebSafeBase64Escape(missing_info.version, &encoded_param);
- parameters["version"] = encoded_param;
- }
-
- WebSafeBase64Escape("WinSymConv", &encoded_param);
- parameters["product"] = encoded_param;
-
- if (!StringMapToWStringMap(parameters, wparameters)) {
- // StringMapToWStringMap will have printed an error.
- return false;
- }
-
- return true;
-}
-
-// UploadSymbolFile sends |converted_file| as identified by |missing_info|
-// to the symbol server rooted at |upload_symbol_url|. Returns true on
-// success and false on failure, printing an error message.
-static bool UploadSymbolFile(const wstring &upload_symbol_url,
- const MissingSymbolInfo &missing_info,
- const string &converted_file) {
- map<wstring, wstring> parameters;
- if (!MissingSymbolInfoToParameters(missing_info, &parameters)) {
- // MissingSymbolInfoToParameters or a callee will have printed an error.
- return false;
- }
-
- wstring converted_file_w;
-
- if (!WindowsStringUtils::safe_mbstowcs(converted_file, &converted_file_w)) {
- FprintfFlush(stderr, "UploadSymbolFile: safe_mbstowcs failed for %s\n",
- converted_file.c_str());
- return false;
- }
- map<wstring, wstring> files;
- files[L"symbol_file"] = converted_file_w;
-
- FprintfFlush(stderr, "Uploading %s\n", converted_file.c_str());
- if (!HTTPUpload::SendMultipartPostRequest(
- upload_symbol_url, parameters,
- files, NULL, NULL, NULL)) {
- FprintfFlush(stderr, "UploadSymbolFile: HTTPUpload::SendRequest failed "
- "for %s %s %s\n",
- missing_info.debug_file.c_str(),
- missing_info.debug_identifier.c_str(),
- missing_info.version.c_str());
- return false;
- }
-
- return true;
-}
-
-// SendFetchFailedPing informs the symbol server based at
-// |fetch_symbol_failure_url| that the symbol file identified by
-// |missing_info| could authoritatively not be located. Returns
-// true on success and false on failure.
-static bool SendFetchFailedPing(const wstring &fetch_symbol_failure_url,
- const MissingSymbolInfo &missing_info) {
- map<wstring, wstring> parameters;
- if (!MissingSymbolInfoToParameters(missing_info, &parameters)) {
- // MissingSymbolInfoToParameters or a callee will have printed an error.
- return false;
- }
-
- string content;
- if (!HTTPDownload::Download(fetch_symbol_failure_url,
- &parameters,
- &content,
- NULL)) {
- FprintfFlush(stderr, "SendFetchFailedPing: HTTPDownload::Download failed "
- "for %s %s %s\n",
- missing_info.debug_file.c_str(),
- missing_info.debug_identifier.c_str(),
- missing_info.version.c_str());
- return false;
- }
-
- return true;
-}
-
-// Returns true if it's safe to make an external request for the symbol
-// file described in missing_info. It's considered safe to make an
-// external request unless the symbol file's debug_file string matches
-// the given blacklist regular expression.
-// The debug_file name is used from the MissingSymbolInfo struct,
-// matched against the blacklist_regex.
-static bool SafeToMakeExternalRequest(const MissingSymbolInfo &missing_info,
- std::regex blacklist_regex) {
- string file_name = missing_info.debug_file;
- // Use regex_search because we want to match substrings.
- if (std::regex_search(file_name, blacklist_regex)) {
- FprintfFlush(stderr, "Not safe to make external request for file %s\n",
- file_name.c_str());
- return false;
- }
-
- return true;
-}
-
-// Converter options derived from command line parameters.
-struct ConverterOptions {
- ConverterOptions()
- : report_fetch_failures(true) {
- }
-
- ~ConverterOptions() {
- }
-
- // Names of MS Symbol Supplier Servers that are internal to Google, and may
- // have symbols for any request.
- vector<string> full_internal_msss_servers;
-
- // Names of MS Symbol Supplier Servers that are internal to Google, and
- // shouldn't be checked for symbols for any .exe files.
- vector<string> full_external_msss_servers;
-
- // Names of MS Symbol Supplier Servers that are external to Google, and may
- // have symbols for any request.
- vector<string> no_exe_internal_msss_servers;
-
- // Names of MS Symbol Supplier Servers that are external to Google, and
- // shouldn't be checked for symbols for any .exe files.
- vector<string> no_exe_external_msss_servers;
-
- // Temporary local storage for symbols.
- string local_cache_path;
-
- // URL for uploading symbols.
- wstring upload_symbols_url;
-
- // URL to fetch list of missing symbols.
- wstring missing_symbols_url;
-
- // URL to report symbol fetch failure.
- wstring fetch_symbol_failure_url;
-
- // Are symbol fetch failures reported.
- bool report_fetch_failures;
-
- // File containing the list of missing symbols. Fetch failures are not
- // reported if such file is provided.
- string missing_symbols_file;
-
- // Regex used to blacklist files to prevent external symbol requests.
- // Owned and cleaned up by this struct.
- std::regex blacklist_regex;
-
- private:
- // DISABLE_COPY_AND_ASSIGN
- ConverterOptions(const ConverterOptions&);
- ConverterOptions& operator=(const ConverterOptions&);
-};
-
-// ConverMissingSymbolFile takes a single MissingSymbolInfo structure and
-// attempts to locate it from the symbol servers provided in the
-// |options.*_msss_servers| arguments. "Full" servers are those that will be
-// queried for all symbol files; "No-EXE" servers will only be queried for
-// modules whose missing symbol data indicates are not main program executables.
-// Results will be sent to the |options.upload_symbols_url| on success or
-// |options.fetch_symbol_failure_url| on failure, and the local cache will be
-// stored at |options.local_cache_path|. Because nothing can be done even in
-// the event of a failure, this function returns no value, although it
-// may result in error messages being printed.
-static void ConvertMissingSymbolFile(const MissingSymbolInfo &missing_info,
- const ConverterOptions &options) {
- string time_string = CurrentDateAndTime();
- FprintfFlush(stdout, "converter: %s: attempting %s %s %s\n",
- time_string.c_str(),
- missing_info.debug_file.c_str(),
- missing_info.debug_identifier.c_str(),
- missing_info.version.c_str());
-
- // The first lookup is always to internal symbol servers.
- // Always ask the symbol servers identified as "full."
- vector<string> msss_servers = options.full_internal_msss_servers;
-
- // If the file is not an .exe file, also ask an additional set of symbol
- // servers, such as Microsoft's public symbol server.
- bool is_exe = false;
-
- if (missing_info.code_file.length() >= 4) {
- string code_extension =
- missing_info.code_file.substr(missing_info.code_file.size() - 4);
-
- // Firefox is a special case: .dll-only servers should be consulted for
- // its symbols. This enables us to get its symbols from Mozilla's
- // symbol server when crashes occur in Google extension code hosted by a
- // Firefox process.
- if (_stricmp(code_extension.c_str(), ".exe") == 0 &&
- _stricmp(missing_info.code_file.c_str(), "firefox.exe") != 0) {
- is_exe = true;
- }
- }
-
- if (!is_exe) {
- msss_servers.insert(msss_servers.end(),
- options.no_exe_internal_msss_servers.begin(),
- options.no_exe_internal_msss_servers.end());
- }
-
- // If there are any suitable internal symbol servers, make a request.
- MSSymbolServerConverter::LocateResult located =
- MSSymbolServerConverter::LOCATE_FAILURE;
- string converted_file;
- if (msss_servers.size() > 0) {
- // Attempt to fetch the symbol file and convert it.
- FprintfFlush(stderr, "Making internal request for %s (%s)\n",
- missing_info.debug_file.c_str(),
- missing_info.debug_identifier.c_str());
- MSSymbolServerConverter converter(options.local_cache_path, msss_servers);
- located = converter.LocateAndConvertSymbolFile(missing_info,
- false, // keep_symbol_file
- false, // keep_pe_file
- &converted_file,
- NULL, // symbol_file
- NULL); // pe_file
- switch (located) {
- case MSSymbolServerConverter::LOCATE_SUCCESS:
- FprintfFlush(stderr, "LocateResult = LOCATE_SUCCESS\n");
- // Upload it. Don't bother checking the return value. If this
- // succeeds, it should disappear from the missing symbol list.
- // If it fails, something will print an error message indicating
- // the cause of the failure, and the item will remain on the
- // missing symbol list.
- UploadSymbolFile(options.upload_symbols_url, missing_info,
- converted_file);
- remove(converted_file.c_str());
-
- // Note: this does leave some directories behind that could be
- // cleaned up. The directories inside options.local_cache_path for
- // debug_file/debug_identifier can be removed at this point.
- break;
-
- case MSSymbolServerConverter::LOCATE_NOT_FOUND:
- FprintfFlush(stderr, "LocateResult = LOCATE_NOT_FOUND\n");
- // The symbol file definitively did not exist. Fall through,
- // so we can attempt an external query if it's safe to do so.
- break;
-
- case MSSymbolServerConverter::LOCATE_RETRY:
- FprintfFlush(stderr, "LocateResult = LOCATE_RETRY\n");
- // Fall through in case we should make an external request.
- // If not, or if an external request fails in the same way,
- // we'll leave the entry in the symbol file list and
- // try again on a future pass. Print a message so that there's
- // a record.
- break;
-
- case MSSymbolServerConverter::LOCATE_FAILURE:
- FprintfFlush(stderr, "LocateResult = LOCATE_FAILURE\n");
- // LocateAndConvertSymbolFile printed an error message.
- break;
-
- default:
- FprintfFlush(
- stderr,
- "FATAL: Unexpected return value '%d' from "
- "LocateAndConvertSymbolFile()\n",
- located);
- assert(0);
- break;
- }
- } else {
- // No suitable internal symbol servers. This is fine because the converter
- // is mainly used for downloading and converting of external symbols.
- }
-
- // Make a request to an external server if the internal request didn't
- // succeed, and it's safe to do so.
- if (located != MSSymbolServerConverter::LOCATE_SUCCESS &&
- SafeToMakeExternalRequest(missing_info, options.blacklist_regex)) {
- msss_servers = options.full_external_msss_servers;
- if (!is_exe) {
- msss_servers.insert(msss_servers.end(),
- options.no_exe_external_msss_servers.begin(),
- options.no_exe_external_msss_servers.end());
- }
- if (msss_servers.size() > 0) {
- FprintfFlush(stderr, "Making external request for %s (%s)\n",
- missing_info.debug_file.c_str(),
- missing_info.debug_identifier.c_str());
- MSSymbolServerConverter external_converter(options.local_cache_path,
- msss_servers);
- located = external_converter.LocateAndConvertSymbolFile(
- missing_info,
- false, // keep_symbol_file
- false, // keep_pe_file
- &converted_file,
- NULL, // symbol_file
- NULL); // pe_file
- } else {
- FprintfFlush(stderr, "ERROR: No suitable external symbol servers.\n");
- }
- }
-
- // Final handling for this symbol file is based on the result from the
- // external request (if performed above), or on the result from the
- // previous internal lookup.
- switch (located) {
- case MSSymbolServerConverter::LOCATE_SUCCESS:
- FprintfFlush(stderr, "LocateResult = LOCATE_SUCCESS\n");
- // Upload it. Don't bother checking the return value. If this
- // succeeds, it should disappear from the missing symbol list.
- // If it fails, something will print an error message indicating
- // the cause of the failure, and the item will remain on the
- // missing symbol list.
- UploadSymbolFile(options.upload_symbols_url, missing_info,
- converted_file);
- remove(converted_file.c_str());
-
- // Note: this does leave some directories behind that could be
- // cleaned up. The directories inside options.local_cache_path for
- // debug_file/debug_identifier can be removed at this point.
- break;
-
- case MSSymbolServerConverter::LOCATE_NOT_FOUND:
- // The symbol file definitively didn't exist. Inform the server.
- // If this fails, something will print an error message indicating
- // the cause of the failure, but there's really nothing more to
- // do. If this succeeds, the entry should be removed from the
- // missing symbols list.
- if (!options.report_fetch_failures) {
- FprintfFlush(stderr, "SendFetchFailedPing skipped\n");
- } else if (SendFetchFailedPing(options.fetch_symbol_failure_url,
- missing_info)) {
- FprintfFlush(stderr, "SendFetchFailedPing succeeded\n");
- } else {
- FprintfFlush(stderr, "SendFetchFailedPing failed\n");
- }
- break;
-
- case MSSymbolServerConverter::LOCATE_RETRY:
- FprintfFlush(stderr, "LocateResult = LOCATE_RETRY\n");
- // Nothing to do but leave the entry in the symbol file list and
- // try again on a future pass. Print a message so that there's
- // a record.
- FprintfFlush(stderr, "ConvertMissingSymbolFile: deferring retry "
- "for %s %s %s\n",
- missing_info.debug_file.c_str(),
- missing_info.debug_identifier.c_str(),
- missing_info.version.c_str());
- break;
-
- case MSSymbolServerConverter::LOCATE_FAILURE:
- FprintfFlush(stderr, "LocateResult = LOCATE_FAILURE\n");
- // LocateAndConvertSymbolFile printed an error message.
-
- // This is due to a bad debug file name, so fetch failed.
- if (!options.report_fetch_failures) {
- FprintfFlush(stderr, "SendFetchFailedPing skipped\n");
- } else if (SendFetchFailedPing(options.fetch_symbol_failure_url,
- missing_info)) {
- FprintfFlush(stderr, "SendFetchFailedPing succeeded\n");
- } else {
- FprintfFlush(stderr, "SendFetchFailedPing failed\n");
- }
- break;
-
- default:
- FprintfFlush(
- stderr,
- "FATAL: Unexpected return value '%d' from "
- "LocateAndConvertSymbolFile()\n",
- located);
- assert(0);
- break;
- }
-}
-
-
-// Reads the contents of file |file_name| and populates |contents|.
-// Returns true on success.
-static bool ReadFile(string file_name, string *contents) {
- char buffer[1024 * 8];
- FILE *fp = fopen(file_name.c_str(), "rt");
- if (!fp) {
- return false;
- }
- contents->clear();
- while (fgets(buffer, sizeof(buffer), fp) != NULL) {
- contents->append(buffer);
- }
- fclose(fp);
- return true;
-}
-
-// ConvertMissingSymbolsList obtains a missing symbol list from
-// |options.missing_symbols_url| or |options.missing_symbols_file| and calls
-// ConvertMissingSymbolFile for each missing symbol file in the list.
-static bool ConvertMissingSymbolsList(const ConverterOptions &options) {
- // Set param to indicate requesting for encoded response.
- map<wstring, wstring> parameters;
- parameters[L"product"] = L"WinSymConv";
- parameters[L"encoded"] = L"true";
- // Get the missing symbol list.
- string missing_symbol_list;
- if (!options.missing_symbols_file.empty()) {
- if (!ReadFile(options.missing_symbols_file, &missing_symbol_list)) {
- return false;
- }
- } else if (!HTTPDownload::Download(options.missing_symbols_url, &parameters,
- &missing_symbol_list, NULL)) {
- return false;
- }
-
- // Tokenize the content into a vector.
- vector<string> missing_symbol_lines;
- Tokenizer::Tokenize("\n", missing_symbol_list, &missing_symbol_lines);
-
- FprintfFlush(stderr, "Found %d missing symbol files in list.\n",
- missing_symbol_lines.size() - 1); // last line is empty.
- int convert_attempts = 0;
- for (vector<string>::const_iterator iterator = missing_symbol_lines.begin();
- iterator != missing_symbol_lines.end();
- ++iterator) {
- // Decode symbol line.
- const string &encoded_line = *iterator;
- // Skip lines that are blank.
- if (encoded_line.empty()) {
- continue;
- }
-
- string line;
- if (!WebSafeBase64Unescape(encoded_line, &line)) {
- // If decoding fails, assume the line is not encoded.
- // This is helpful when the program connects to a debug server without
- // encoding.
- line = encoded_line;
- }
-
- FprintfFlush(stderr, "\nLine: %s\n", line.c_str());
-
- // Turn each element into a MissingSymbolInfo structure.
- MissingSymbolInfo missing_info;
- if (!ParseMissingString(line, &missing_info)) {
- FprintfFlush(stderr, "ConvertMissingSymbols: ParseMissingString failed "
- "for %s from %ws\n",
- line.c_str(), options.missing_symbols_url.c_str());
- continue;
- }
-
- ++convert_attempts;
- ConvertMissingSymbolFile(missing_info, options);
- }
-
- // Say something reassuring, since ConvertMissingSymbolFile was never called
- // and therefore never reported any progress.
- if (convert_attempts == 0) {
- string current_time = CurrentDateAndTime();
- FprintfFlush(stdout, "converter: %s: nothing to convert\n",
- current_time.c_str());
- }
-
- return true;
-}
-
-// usage prints the usage message. It returns 1 as a convenience, to be used
-// as a return value from main.
-static int usage(const char *program_name) {
- FprintfFlush(stderr,
- "usage: %s [options]\n"
- " -f <full_msss_server> MS servers to ask for all symbols\n"
- " -n <no_exe_msss_server> same, but prevent asking for EXEs\n"
- " -l <local_cache_path> Temporary local storage for symbols\n"
- " -s <upload_url> URL for uploading symbols\n"
- " -m <missing_symbols_url> URL to fetch list of missing symbols\n"
- " -mf <missing_symbols_file> File containing the list of missing\n"
- " symbols. Fetch failures are not\n"
- " reported if such file is provided.\n"
- " -t <fetch_failure_url> URL to report symbol fetch failure\n"
- " -b <regex> Regex used to blacklist files to\n"
- " prevent external symbol requests\n"
- " Note that any server specified by -f or -n that starts with \\filer\n"
- " will be treated as internal, and all others as external.\n",
- program_name);
-
- return 1;
-}
-
-// "Internal" servers consist only of those whose names start with
-// the literal string "\\filer\".
-static bool IsInternalServer(const string &server_name) {
- if (server_name.find("\\\\filer\\") == 0) {
- return true;
- }
- return false;
-}
-
-// Adds a server with the given name to the list of internal or external
-// servers, as appropriate.
-static void AddServer(const string &server_name,
- vector<string> *internal_servers,
- vector<string> *external_servers) {
- if (IsInternalServer(server_name)) {
- internal_servers->push_back(server_name);
- } else {
- external_servers->push_back(server_name);
- }
-}
-
-} // namespace
-
-int main(int argc, char **argv) {
- string time_string = CurrentDateAndTime();
- FprintfFlush(stdout, "converter: %s: starting\n", time_string.c_str());
-
- ConverterOptions options;
- options.report_fetch_failures = true;
-
- // All arguments are paired.
- if (argc % 2 != 1) {
- return usage(argv[0]);
- }
-
- string blacklist_regex_str;
- bool have_any_msss_servers = false;
- for (int argi = 1; argi < argc; argi += 2) {
- string option = argv[argi];
- string value = argv[argi + 1];
-
- if (option == "-f") {
- AddServer(value, &options.full_internal_msss_servers,
- &options.full_external_msss_servers);
- have_any_msss_servers = true;
- } else if (option == "-n") {
- AddServer(value, &options.no_exe_internal_msss_servers,
- &options.no_exe_external_msss_servers);
- have_any_msss_servers = true;
- } else if (option == "-l") {
- if (!options.local_cache_path.empty()) {
- return usage(argv[0]);
- }
- options.local_cache_path = value;
- } else if (option == "-s") {
- if (!WindowsStringUtils::safe_mbstowcs(value,
- &options.upload_symbols_url)) {
- FprintfFlush(stderr, "main: safe_mbstowcs failed for %s\n",
- value.c_str());
- return 1;
- }
- } else if (option == "-m") {
- if (!WindowsStringUtils::safe_mbstowcs(value,
- &options.missing_symbols_url)) {
- FprintfFlush(stderr, "main: safe_mbstowcs failed for %s\n",
- value.c_str());
- return 1;
- }
- } else if (option == "-mf") {
- options.missing_symbols_file = value;
- printf("Getting the list of missing symbols from a file. Fetch failures"
- " will not be reported.\n");
- options.report_fetch_failures = false;
- } else if (option == "-t") {
- if (!WindowsStringUtils::safe_mbstowcs(
- value,
- &options.fetch_symbol_failure_url)) {
- FprintfFlush(stderr, "main: safe_mbstowcs failed for %s\n",
- value.c_str());
- return 1;
- }
- } else if (option == "-b") {
- blacklist_regex_str = value;
- } else {
- return usage(argv[0]);
- }
- }
-
- if (blacklist_regex_str.empty()) {
- FprintfFlush(stderr, "No blacklist specified.\n");
- return usage(argv[0]);
- }
-
- // Compile the blacklist regular expression for later use.
- options.blacklist_regex = std::regex(blacklist_regex_str.c_str(),
- std::regex_constants::icase);
-
- // Set the defaults. If the user specified any MSSS servers, don't use
- // any default.
- if (!have_any_msss_servers) {
- AddServer(kNoExeMSSSServer, &options.no_exe_internal_msss_servers,
- &options.no_exe_external_msss_servers);
- }
-
- if (options.local_cache_path.empty()) {
- options.local_cache_path = kLocalCachePath;
- }
-
- if (options.upload_symbols_url.empty()) {
- FprintfFlush(stderr, "No upload symbols URL specified.\n");
- return usage(argv[0]);
- }
- if (options.missing_symbols_url.empty() &&
- options.missing_symbols_file.empty()) {
- FprintfFlush(stderr, "No missing symbols URL or file specified.\n");
- return usage(argv[0]);
- }
- if (options.fetch_symbol_failure_url.empty()) {
- FprintfFlush(stderr, "No fetch symbol failure URL specified.\n");
- return usage(argv[0]);
- }
-
- FprintfFlush(stdout,
- "# of Symbol Servers (int/ext): %d/%d full, %d/%d no_exe\n",
- options.full_internal_msss_servers.size(),
- options.full_external_msss_servers.size(),
- options.no_exe_internal_msss_servers.size(),
- options.no_exe_external_msss_servers.size());
-
- if (!ConvertMissingSymbolsList(options)) {
- return 1;
- }
-
- time_string = CurrentDateAndTime();
- FprintfFlush(stdout, "converter: %s: finished\n", time_string.c_str());
- return 0;
-}
+// Copyright 2019 Google LLC
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google LLC nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#pragma comment(lib, "winhttp.lib")
+#pragma comment(lib, "wininet.lib")
+#pragma comment(lib, "diaguids.lib")
+#pragma comment(lib, "imagehlp.lib")
+
+#include <cassert>
+#include <cstdio>
+#include <ctime>
+#include <map>
+#include <regex>
+#include <string>
+#include <vector>
+
+#include "common/windows/http_upload.h"
+#include "common/windows/string_utils-inl.h"
+#include "common/windows/sym_upload_v2_protocol.h"
+#include "tools/windows/converter/ms_symbol_server_converter.h"
+#include "tools/windows/converter_exe/escaping.h"
+#include "tools/windows/converter_exe/http_download.h"
+#include "tools/windows/converter_exe/tokenizer.h"
+
+using strings::WebSafeBase64Unescape;
+using strings::WebSafeBase64Escape;
+
+namespace {
+
+using std::map;
+using std::string;
+using std::vector;
+using std::wstring;
+using crash::HTTPDownload;
+using crash::Tokenizer;
+using google_breakpad::HTTPUpload;
+using google_breakpad::MissingSymbolInfo;
+using google_breakpad::MSSymbolServerConverter;
+using google_breakpad::WindowsStringUtils;
+
+const char* kMissingStringDelimiters = "|";
+const char* kLocalCachePath = "c:\\symbols";
+const char* kNoExeMSSSServer = "http://msdl.microsoft.com/download/symbols/";
+const wchar_t* kSymbolUploadTypeBreakpad = L"BREAKPAD";
+const wchar_t* kSymbolUploadTypePE = L"PE";
+const wchar_t* kSymbolUploadTypePDB = L"PDB";
+const wchar_t* kConverterProductName = L"WinSymConv";
+
+// Windows stdio doesn't do line buffering. Use this function to flush after
+// writing to stdout and stderr so that a log will be available if the
+// converter crashes.
+static int FprintfFlush(FILE* file, const char* format, ...) {
+ va_list arguments;
+ va_start(arguments, format);
+ int retval = vfprintf(file, format, arguments);
+ va_end(arguments);
+ fflush(file);
+ return retval;
+}
+
+static string CurrentDateAndTime() {
+ const string kUnknownDateAndTime = R"(????-??-?? ??:??:??)";
+
+ time_t current_time;
+ time(&current_time);
+
+ // localtime_s is safer but is only available in MSVC8. Use localtime
+ // in earlier environments.
+ struct tm* time_pointer;
+#if _MSC_VER >= 1400 // MSVC 2005/8
+ struct tm time_struct;
+ time_pointer =& time_struct;
+ if (localtime_s(time_pointer,& current_time) != 0) {
+ return kUnknownDateAndTime;
+ }
+#else // _MSC_VER >= 1400
+ time_pointer = localtime(&current_time);
+ if (!time_pointer) {
+ return kUnknownDateAndTime;
+ }
+#endif // _MSC_VER >= 1400
+
+ char buffer[256];
+ if (!strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", time_pointer)) {
+ return kUnknownDateAndTime;
+ }
+
+ return string(buffer);
+}
+
+// ParseMissingString turns |missing_string| into a MissingSymbolInfo
+// structure. It returns true on success, and false if no such conversion
+// is possible.
+static bool ParseMissingString(const string& missing_string,
+ MissingSymbolInfo* missing_info) {
+ assert(missing_info);
+
+ vector<string> tokens;
+ Tokenizer::Tokenize(kMissingStringDelimiters, missing_string,& tokens);
+ if (tokens.size() != 5) {
+ return false;
+ }
+
+ missing_info->debug_file = tokens[0];
+ missing_info->debug_identifier = tokens[1];
+ missing_info->version = tokens[2];
+ missing_info->code_file = tokens[3];
+ missing_info->code_identifier = tokens[4];
+
+ return true;
+}
+
+// StringMapToWStringMap takes each element in a map that associates
+// (narrow) strings to strings and converts the keys and values to wstrings.
+// Returns true on success and false on failure, printing an error message.
+static bool StringMapToWStringMap(const map<string, string>& smap,
+ map<wstring, wstring>* wsmap) {
+ assert(wsmap);
+ wsmap->clear();
+
+ for (map<string, string>::const_iterator iterator = smap.begin();
+ iterator != smap.end();
+ ++iterator) {
+ wstring key;
+ if (!WindowsStringUtils::safe_mbstowcs(iterator->first,& key)) {
+ FprintfFlush(stderr,
+ "StringMapToWStringMap: safe_mbstowcs failed for key %s\n",
+ iterator->first.c_str());
+ return false;
+ }
+
+ wstring value;
+ if (!WindowsStringUtils::safe_mbstowcs(iterator->second,& value)) {
+ FprintfFlush(stderr, "StringMapToWStringMap: safe_mbstowcs failed "
+ "for value %s\n",
+ iterator->second.c_str());
+ return false;
+ }
+
+ wsmap->insert(make_pair(key, value));
+ }
+
+ return true;
+}
+
+// MissingSymbolInfoToParameters turns a MissingSymbolInfo structure into a
+// map of parameters suitable for passing to HTTPDownload or HTTPUpload.
+// Returns true on success and false on failure, printing an error message.
+static bool MissingSymbolInfoToParameters(const MissingSymbolInfo& missing_info,
+ map<wstring, wstring>* wparameters) {
+ assert(wparameters);
+
+ map<string, string> parameters;
+ string encoded_param;
+ // Indicate the params are encoded.
+ parameters["encoded"] = "true"; // The string value here does not matter.
+
+ WebSafeBase64Escape(missing_info.code_file,& encoded_param);
+ parameters["code_file"] = encoded_param;
+
+ WebSafeBase64Escape(missing_info.code_identifier,& encoded_param);
+ parameters["code_identifier"] = encoded_param;
+
+ WebSafeBase64Escape(missing_info.debug_file,& encoded_param);
+ parameters["debug_file"] = encoded_param;
+
+ WebSafeBase64Escape(missing_info.debug_identifier,& encoded_param);
+ parameters["debug_identifier"] = encoded_param;
+
+ if (!missing_info.version.empty()) {
+ // The version is optional.
+ WebSafeBase64Escape(missing_info.version,& encoded_param);
+ parameters["version"] = encoded_param;
+ }
+
+ WebSafeBase64Escape("WinSymConv",& encoded_param);
+ parameters["product"] = encoded_param;
+
+ if (!StringMapToWStringMap(parameters, wparameters)) {
+ // StringMapToWStringMap will have printed an error.
+ return false;
+ }
+
+ return true;
+}
+
+// UploadSymbolFile sends |converted_file| as identified by |debug_file| and
+// |debug_identifier|, to the symbol server rooted at |upload_symbol_url|.
+// Returns true on success and false on failure, printing an error message.
+static bool UploadSymbolFile(const wstring& upload_symbol_url,
+ const wstring& api_key,
+ const string& debug_file,
+ const string& debug_identifier,
+ const string& symbol_file,
+ const wstring& symbol_type) {
+ wstring debug_file_w;
+ if (!WindowsStringUtils::safe_mbstowcs(debug_file, &debug_file_w)) {
+ FprintfFlush(stderr, "UploadSymbolFile: safe_mbstowcs failed for %s\n",
+ symbol_file.c_str());
+ return false;
+ }
+
+ wstring debug_id_w;
+ if (!WindowsStringUtils::safe_mbstowcs(debug_identifier, &debug_id_w)) {
+ FprintfFlush(stderr, "UploadSymbolFile: safe_mbstowcs failed for %s\n",
+ symbol_file.c_str());
+ return false;
+ }
+
+ wstring symbol_file_w;
+ if (!WindowsStringUtils::safe_mbstowcs(symbol_file, &symbol_file_w)) {
+ FprintfFlush(stderr, "UploadSymbolFile: safe_mbstowcs failed for %s\n",
+ symbol_file.c_str());
+ return false;
+ }
+
+ int timeout_ms = 60 * 1000;
+ FprintfFlush(stderr, "Uploading %s\n", symbol_file.c_str());
+ if (!google_breakpad::SymUploadV2ProtocolSend(
+ upload_symbol_url.c_str(), api_key.c_str(), &timeout_ms, debug_file_w,
+ debug_id_w, symbol_file_w, symbol_type, kConverterProductName,
+ /*force=*/true)) {
+ FprintfFlush(stderr,
+ "UploadSymbolFile: HTTPUpload::SendRequest failed "
+ "for %s %s\n",
+ debug_file.c_str(), debug_identifier.c_str());
+ return false;
+ }
+
+ return true;
+}
+
+// SendFetchFailedPing informs the symbol server based at
+// |fetch_symbol_failure_url| that the symbol file identified by
+// |missing_info| could authoritatively not be located. Returns
+// true on success and false on failure.
+static bool SendFetchFailedPing(const wstring& fetch_symbol_failure_url,
+ const MissingSymbolInfo& missing_info) {
+ map<wstring, wstring> parameters;
+ if (!MissingSymbolInfoToParameters(missing_info,& parameters)) {
+ // MissingSymbolInfoToParameters or a callee will have printed an error.
+ return false;
+ }
+
+ string content;
+ if (!HTTPDownload::Download(fetch_symbol_failure_url,
+ & parameters,
+ & content,
+ NULL)) {
+ FprintfFlush(stderr, "SendFetchFailedPing: HTTPDownload::Download failed "
+ "for %s %s %s\n",
+ missing_info.debug_file.c_str(),
+ missing_info.debug_identifier.c_str(),
+ missing_info.version.c_str());
+ return false;
+ }
+
+ return true;
+}
+
+// Returns true if it's safe to make an external request for the symbol
+// file described in missing_info. It's considered safe to make an
+// external request unless the symbol file's debug_file string matches
+// the given blacklist regular expression.
+// The debug_file name is used from the MissingSymbolInfo struct,
+// matched against the blacklist_regex.
+static bool SafeToMakeExternalRequest(const MissingSymbolInfo& missing_info,
+ std::regex blacklist_regex) {
+ string file_name = missing_info.debug_file;
+ // Use regex_search because we want to match substrings.
+ if (std::regex_search(file_name, blacklist_regex)) {
+ FprintfFlush(stderr, "Not safe to make external request for file %s\n",
+ file_name.c_str());
+ return false;
+ }
+
+ return true;
+}
+
+// Converter options derived from command line parameters.
+struct ConverterOptions {
+ ConverterOptions()
+ : report_fetch_failures(true), trace_symsrv(false), keep_files(false) {}
+
+ ~ConverterOptions() {
+ }
+
+ // Names of MS Symbol Supplier Servers that are internal to Google, and may
+ // have symbols for any request.
+ vector<string> full_internal_msss_servers;
+
+ // Names of MS Symbol Supplier Servers that are internal to Google, and
+ // shouldn't be checked for symbols for any .exe files.
+ vector<string> full_external_msss_servers;
+
+ // Names of MS Symbol Supplier Servers that are external to Google, and may
+ // have symbols for any request.
+ vector<string> no_exe_internal_msss_servers;
+
+ // Names of MS Symbol Supplier Servers that are external to Google, and
+ // shouldn't be checked for symbols for any .exe files.
+ vector<string> no_exe_external_msss_servers;
+
+ // Temporary local storage for symbols.
+ string local_cache_path;
+
+ // URL for uploading symbols.
+ wstring upload_symbols_url;
+
+ // API key to use when uploading symbols.
+ wstring api_key;
+
+ // URL to fetch list of missing symbols.
+ wstring missing_symbols_url;
+
+ // URL to report symbol fetch failure.
+ wstring fetch_symbol_failure_url;
+
+ // Are symbol fetch failures reported.
+ bool report_fetch_failures;
+
+ // File containing the list of missing symbols. Fetch failures are not
+ // reported if such file is provided.
+ string missing_symbols_file;
+
+ // Regex used to blacklist files to prevent external symbol requests.
+ // Owned and cleaned up by this struct.
+ std::regex blacklist_regex;
+
+ // If set then SymSrv callbacks are logged to stderr.
+ bool trace_symsrv;
+
+ // If set then Breakpad/PE/PDB files won't be deleted after processing.
+ bool keep_files;
+
+ private:
+ // DISABLE_COPY_AND_ASSIGN
+ ConverterOptions(const ConverterOptions&);
+ ConverterOptions& operator=(const ConverterOptions&);
+};
+
+// ConverMissingSymbolFile takes a single MissingSymbolInfo structure and
+// attempts to locate it from the symbol servers provided in the
+// |options.*_msss_servers| arguments. "Full" servers are those that will be
+// queried for all symbol files; "No-EXE" servers will only be queried for
+// modules whose missing symbol data indicates are not main program executables.
+// Results will be sent to the |options.upload_symbols_url| on success or
+// |options.fetch_symbol_failure_url| on failure, and the local cache will be
+// stored at |options.local_cache_path|. Because nothing can be done even in
+// the event of a failure, this function returns no value, although it
+// may result in error messages being printed.
+static void ConvertMissingSymbolFile(const MissingSymbolInfo& missing_info,
+ const ConverterOptions& options) {
+ string time_string = CurrentDateAndTime();
+ FprintfFlush(stdout, "converter: %s: attempting %s %s %s\n",
+ time_string.c_str(),
+ missing_info.debug_file.c_str(),
+ missing_info.debug_identifier.c_str(),
+ missing_info.version.c_str());
+
+ // The first lookup is always to internal symbol servers.
+ // Always ask the symbol servers identified as "full."
+ vector<string> msss_servers = options.full_internal_msss_servers;
+
+ // If the file is not an .exe file, also ask an additional set of symbol
+ // servers, such as Microsoft's public symbol server.
+ bool is_exe = false;
+
+ if (missing_info.code_file.length() >= 4) {
+ string code_extension =
+ missing_info.code_file.substr(missing_info.code_file.size() - 4);
+
+ // Firefox is a special case: .dll-only servers should be consulted for
+ // its symbols. This enables us to get its symbols from Mozilla's
+ // symbol server when crashes occur in Google extension code hosted by a
+ // Firefox process.
+ if (_stricmp(code_extension.c_str(), ".exe") == 0 &&
+ _stricmp(missing_info.code_file.c_str(), "firefox.exe") != 0) {
+ is_exe = true;
+ }
+ }
+
+ if (!is_exe) {
+ msss_servers.insert(msss_servers.end(),
+ options.no_exe_internal_msss_servers.begin(),
+ options.no_exe_internal_msss_servers.end());
+ }
+
+ // If there are any suitable internal symbol servers, make a request.
+ MSSymbolServerConverter::LocateResult located =
+ MSSymbolServerConverter::LOCATE_FAILURE;
+ string converted_file;
+ string symbol_file;
+ string pe_file;
+ if (msss_servers.size() > 0) {
+ // Attempt to fetch the symbol file and convert it.
+ FprintfFlush(stderr, "Making internal request for %s (%s)\n",
+ missing_info.debug_file.c_str(),
+ missing_info.debug_identifier.c_str());
+ MSSymbolServerConverter converter(options.local_cache_path, msss_servers,
+ options.trace_symsrv);
+ located = converter.LocateAndConvertSymbolFile(
+ missing_info,
+ /*keep_symbol_file=*/true,
+ /*keep_pe_file=*/true, &converted_file, &symbol_file, &pe_file);
+ switch (located) {
+ case MSSymbolServerConverter::LOCATE_SUCCESS:
+ FprintfFlush(stderr, "LocateResult = LOCATE_SUCCESS\n");
+ // Upload it. Don't bother checking the return value. If this
+ // succeeds, it should disappear from the missing symbol list.
+ // If it fails, something will print an error message indicating
+ // the cause of the failure, and the item will remain on the
+ // missing symbol list.
+ UploadSymbolFile(options.upload_symbols_url, options.api_key,
+ missing_info.debug_file, missing_info.debug_identifier,
+ converted_file, kSymbolUploadTypeBreakpad);
+ if (!options.keep_files)
+ remove(converted_file.c_str());
+
+ // Upload PDB/PE if we have them
+ if (!symbol_file.empty()) {
+ UploadSymbolFile(options.upload_symbols_url, options.api_key,
+ missing_info.debug_file,
+ missing_info.debug_identifier, symbol_file,
+ kSymbolUploadTypePDB);
+ if (!options.keep_files)
+ remove(symbol_file.c_str());
+ }
+ if (!pe_file.empty()) {
+ UploadSymbolFile(options.upload_symbols_url, options.api_key,
+ missing_info.code_file,
+ missing_info.debug_identifier, pe_file,
+ kSymbolUploadTypePE);
+ if (!options.keep_files)
+ remove(pe_file.c_str());
+ }
+
+ // Note: this does leave some directories behind that could be
+ // cleaned up. The directories inside options.local_cache_path for
+ // debug_file/debug_identifier can be removed at this point.
+ break;
+
+ case MSSymbolServerConverter::LOCATE_NOT_FOUND:
+ FprintfFlush(stderr, "LocateResult = LOCATE_NOT_FOUND\n");
+ // The symbol file definitively did not exist. Fall through,
+ // so we can attempt an external query if it's safe to do so.
+ break;
+
+ case MSSymbolServerConverter::LOCATE_RETRY:
+ FprintfFlush(stderr, "LocateResult = LOCATE_RETRY\n");
+ // Fall through in case we should make an external request.
+ // If not, or if an external request fails in the same way,
+ // we'll leave the entry in the symbol file list and
+ // try again on a future pass. Print a message so that there's
+ // a record.
+ break;
+
+ case MSSymbolServerConverter::LOCATE_HTTP_HTTPS_REDIR:
+ FprintfFlush(
+ stderr,
+ "LocateResult = LOCATE_HTTP_HTTPS_REDIR\n"
+ "One of the specified URLs is using HTTP, which causes a redirect "
+ "from the server to HTTPS, which causes the SymSrv lookup to "
+ "fail.\n"
+ "This URL must be replaced with the correct HTTPS URL.\n");
+ break;
+
+ case MSSymbolServerConverter::LOCATE_FAILURE:
+ FprintfFlush(stderr, "LocateResult = LOCATE_FAILURE\n");
+ // LocateAndConvertSymbolFile printed an error message.
+ break;
+
+ default:
+ FprintfFlush(
+ stderr,
+ "FATAL: Unexpected return value '%d' from "
+ "LocateAndConvertSymbolFile()\n",
+ located);
+ assert(0);
+ break;
+ }
+ } else {
+ // No suitable internal symbol servers. This is fine because the converter
+ // is mainly used for downloading and converting of external symbols.
+ }
+
+ // Make a request to an external server if the internal request didn't
+ // succeed, and it's safe to do so.
+ if (located != MSSymbolServerConverter::LOCATE_SUCCESS &&
+ SafeToMakeExternalRequest(missing_info, options.blacklist_regex)) {
+ msss_servers = options.full_external_msss_servers;
+ if (!is_exe) {
+ msss_servers.insert(msss_servers.end(),
+ options.no_exe_external_msss_servers.begin(),
+ options.no_exe_external_msss_servers.end());
+ }
+ if (msss_servers.size() > 0) {
+ FprintfFlush(stderr, "Making external request for %s (%s)\n",
+ missing_info.debug_file.c_str(),
+ missing_info.debug_identifier.c_str());
+ MSSymbolServerConverter external_converter(
+ options.local_cache_path, msss_servers, options.trace_symsrv);
+ located = external_converter.LocateAndConvertSymbolFile(
+ missing_info,
+ /*keep_symbol_file=*/true,
+ /*keep_pe_file=*/true, &converted_file, &symbol_file, &pe_file);
+ } else {
+ FprintfFlush(stderr, "ERROR: No suitable external symbol servers.\n");
+ }
+ }
+
+ // Final handling for this symbol file is based on the result from the
+ // external request (if performed above), or on the result from the
+ // previous internal lookup.
+ switch (located) {
+ case MSSymbolServerConverter::LOCATE_SUCCESS:
+ FprintfFlush(stderr, "LocateResult = LOCATE_SUCCESS\n");
+ // Upload it. Don't bother checking the return value. If this
+ // succeeds, it should disappear from the missing symbol list.
+ // If it fails, something will print an error message indicating
+ // the cause of the failure, and the item will remain on the
+ // missing symbol list.
+ UploadSymbolFile(options.upload_symbols_url, options.api_key,
+ missing_info.debug_file, missing_info.debug_identifier,
+ converted_file, kSymbolUploadTypeBreakpad);
+ if (!options.keep_files)
+ remove(converted_file.c_str());
+
+ // Upload PDB/PE if we have them
+ if (!symbol_file.empty()) {
+ UploadSymbolFile(options.upload_symbols_url, options.api_key,
+ missing_info.debug_file, missing_info.debug_identifier,
+ symbol_file, kSymbolUploadTypePDB);
+ if (!options.keep_files)
+ remove(symbol_file.c_str());
+ }
+ if (!pe_file.empty()) {
+ UploadSymbolFile(options.upload_symbols_url, options.api_key,
+ missing_info.code_file, missing_info.debug_identifier,
+ pe_file, kSymbolUploadTypePE);
+ if (!options.keep_files)
+ remove(pe_file.c_str());
+ }
+
+ // Note: this does leave some directories behind that could be
+ // cleaned up. The directories inside options.local_cache_path for
+ // debug_file/debug_identifier can be removed at this point.
+ break;
+
+ case MSSymbolServerConverter::LOCATE_NOT_FOUND:
+ // The symbol file definitively didn't exist. Inform the server.
+ // If this fails, something will print an error message indicating
+ // the cause of the failure, but there's really nothing more to
+ // do. If this succeeds, the entry should be removed from the
+ // missing symbols list.
+ if (!options.report_fetch_failures) {
+ FprintfFlush(stderr, "SendFetchFailedPing skipped\n");
+ } else if (SendFetchFailedPing(options.fetch_symbol_failure_url,
+ missing_info)) {
+ FprintfFlush(stderr, "SendFetchFailedPing succeeded\n");
+ } else {
+ FprintfFlush(stderr, "SendFetchFailedPing failed\n");
+ }
+ break;
+
+ case MSSymbolServerConverter::LOCATE_RETRY:
+ FprintfFlush(stderr, "LocateResult = LOCATE_RETRY\n");
+ // Nothing to do but leave the entry in the symbol file list and
+ // try again on a future pass. Print a message so that there's
+ // a record.
+ FprintfFlush(stderr, "ConvertMissingSymbolFile: deferring retry "
+ "for %s %s %s\n",
+ missing_info.debug_file.c_str(),
+ missing_info.debug_identifier.c_str(),
+ missing_info.version.c_str());
+ break;
+
+ case MSSymbolServerConverter::LOCATE_HTTP_HTTPS_REDIR:
+ FprintfFlush(
+ stderr,
+ "LocateResult = LOCATE_HTTP_HTTPS_REDIR\n"
+ "One of the specified URLs is using HTTP, which causes a redirect "
+ "from the server to HTTPS, which causes the SymSrv lookup to fail.\n"
+ "This URL must be replaced with the correct HTTPS URL.\n");
+ break;
+
+ case MSSymbolServerConverter::LOCATE_FAILURE:
+ FprintfFlush(stderr, "LocateResult = LOCATE_FAILURE\n");
+ // LocateAndConvertSymbolFile printed an error message.
+
+ // This is due to a bad debug file name, so fetch failed.
+ if (!options.report_fetch_failures) {
+ FprintfFlush(stderr, "SendFetchFailedPing skipped\n");
+ } else if (SendFetchFailedPing(options.fetch_symbol_failure_url,
+ missing_info)) {
+ FprintfFlush(stderr, "SendFetchFailedPing succeeded\n");
+ } else {
+ FprintfFlush(stderr, "SendFetchFailedPing failed\n");
+ }
+ break;
+
+ default:
+ FprintfFlush(
+ stderr,
+ "FATAL: Unexpected return value '%d' from "
+ "LocateAndConvertSymbolFile()\n",
+ located);
+ assert(0);
+ break;
+ }
+}
+
+
+// Reads the contents of file |file_name| and populates |contents|.
+// Returns true on success.
+static bool ReadFile(string file_name, string* contents) {
+ char buffer[1024 * 8];
+ FILE* fp = fopen(file_name.c_str(), "rt");
+ if (!fp) {
+ return false;
+ }
+ contents->clear();
+ while (fgets(buffer, sizeof(buffer), fp) != NULL) {
+ contents->append(buffer);
+ }
+ fclose(fp);
+ return true;
+}
+
+// ConvertMissingSymbolsList obtains a missing symbol list from
+// |options.missing_symbols_url| or |options.missing_symbols_file| and calls
+// ConvertMissingSymbolFile for each missing symbol file in the list.
+static bool ConvertMissingSymbolsList(const ConverterOptions& options) {
+ // Set param to indicate requesting for encoded response.
+ map<wstring, wstring> parameters;
+ parameters[L"product"] = kConverterProductName;
+ parameters[L"encoded"] = L"true";
+ // Get the missing symbol list.
+ string missing_symbol_list;
+ if (!options.missing_symbols_file.empty()) {
+ if (!ReadFile(options.missing_symbols_file,& missing_symbol_list)) {
+ return false;
+ }
+ } else if (!HTTPDownload::Download(options.missing_symbols_url,& parameters,
+ & missing_symbol_list, NULL)) {
+ return false;
+ }
+
+ // Tokenize the content into a vector.
+ vector<string> missing_symbol_lines;
+ Tokenizer::Tokenize("\n", missing_symbol_list,& missing_symbol_lines);
+
+ FprintfFlush(stderr, "Found %d missing symbol files in list.\n",
+ missing_symbol_lines.size() - 1); // last line is empty.
+ int convert_attempts = 0;
+ for (vector<string>::const_iterator iterator = missing_symbol_lines.begin();
+ iterator != missing_symbol_lines.end();
+ ++iterator) {
+ // Decode symbol line.
+ const string& encoded_line = *iterator;
+ // Skip lines that are blank.
+ if (encoded_line.empty()) {
+ continue;
+ }
+
+ string line;
+ if (!WebSafeBase64Unescape(encoded_line,& line)) {
+ // If decoding fails, assume the line is not encoded.
+ // This is helpful when the program connects to a debug server without
+ // encoding.
+ line = encoded_line;
+ }
+
+ FprintfFlush(stderr, "\nLine: %s\n", line.c_str());
+
+ // Turn each element into a MissingSymbolInfo structure.
+ MissingSymbolInfo missing_info;
+ if (!ParseMissingString(line,& missing_info)) {
+ FprintfFlush(stderr, "ConvertMissingSymbols: ParseMissingString failed "
+ "for %s from %ws\n",
+ line.c_str(), options.missing_symbols_url.c_str());
+ continue;
+ }
+
+ ++convert_attempts;
+ ConvertMissingSymbolFile(missing_info, options);
+ }
+
+ // Say something reassuring, since ConvertMissingSymbolFile was never called
+ // and therefore never reported any progress.
+ if (convert_attempts == 0) {
+ string current_time = CurrentDateAndTime();
+ FprintfFlush(stdout, "converter: %s: nothing to convert\n",
+ current_time.c_str());
+ }
+
+ return true;
+}
+
+// usage prints the usage message. It returns 1 as a convenience, to be used
+// as a return value from main.
+static int usage(const char* program_name) {
+ FprintfFlush(
+ stderr,
+ "usage: %s [options]\n"
+ " -f <full_msss_server> MS servers to ask for all symbols\n"
+ " -n <no_exe_msss_server> same, but prevent asking for EXEs\n"
+ " -l <local_cache_path> Temporary local storage for symbols\n"
+ " -s <upload_url> URL for uploading symbols\n"
+ " -k <api_key> API key to use when uploading symbols\n"
+ " -m <missing_symbols_url> URL to fetch list of missing symbols\n"
+ " -mf <missing_symbols_file> File containing the list of missing\n"
+ " symbols. Fetch failures are not\n"
+ " reported if such file is provided.\n"
+ " -t <fetch_failure_url> URL to report symbol fetch failure\n"
+ " -b <regex> Regex used to blacklist files to\n"
+ " prevent external symbol requests\n"
+ " -tss If set then SymSrv callbacks will be\n"
+ " traced to stderr.\n"
+ " -keep-files If set then don't delete Breakpad/PE/\n"
+ " PDB files after conversion.\n"
+ " Note that any server specified by -f or -n that starts with \\filer\n"
+ " will be treated as internal, and all others as external.\n",
+ program_name);
+
+ return 1;
+}
+
+// "Internal" servers consist only of those whose names start with
+// the literal string "\\filer\".
+static bool IsInternalServer(const string& server_name) {
+ if (server_name.find("\\\\filer\\") == 0) {
+ return true;
+ }
+ return false;
+}
+
+// Adds a server with the given name to the list of internal or external
+// servers, as appropriate.
+static void AddServer(const string& server_name,
+ vector<string>* internal_servers,
+ vector<string>* external_servers) {
+ if (IsInternalServer(server_name)) {
+ internal_servers->push_back(server_name);
+ } else {
+ external_servers->push_back(server_name);
+ }
+}
+
+} // namespace
+
+int main(int argc, char** argv) {
+ string time_string = CurrentDateAndTime();
+ FprintfFlush(stdout, "converter: %s: starting\n", time_string.c_str());
+
+ ConverterOptions options;
+ options.report_fetch_failures = true;
+
+ string blacklist_regex_str;
+ bool have_any_msss_servers = false;
+ for (int argi = 1; argi < argc; argi++) {
+ string option = argv[argi];
+ if (option == "-tss") {
+ printf("Tracing SymSrv callbacks to stderr.\n");
+ options.trace_symsrv = true;
+ continue;
+ } else if (option == "-keep-files") {
+ printf("Keeping Breakpad/PE/PDB files after conversion.\n");
+ options.keep_files = true;
+ continue;
+ }
+
+ string value = argv[++argi];
+ if (option == "-f") {
+ AddServer(value,& options.full_internal_msss_servers,
+ & options.full_external_msss_servers);
+ have_any_msss_servers = true;
+ } else if (option == "-n") {
+ AddServer(value,& options.no_exe_internal_msss_servers,
+ & options.no_exe_external_msss_servers);
+ have_any_msss_servers = true;
+ } else if (option == "-l") {
+ if (!options.local_cache_path.empty()) {
+ return usage(argv[0]);
+ }
+ options.local_cache_path = value;
+ } else if (option == "-s") {
+ if (!WindowsStringUtils::safe_mbstowcs(value,
+ & options.upload_symbols_url)) {
+ FprintfFlush(stderr, "main: safe_mbstowcs failed for %s\n",
+ value.c_str());
+ return 1;
+ }
+ } else if (option == "-k") {
+ if (!WindowsStringUtils::safe_mbstowcs(value, &options.api_key)) {
+ FprintfFlush(stderr, "main: safe_mbstowcs failed for %s\n",
+ value.c_str());
+ return 1;
+ }
+ } else if (option == "-m") {
+ if (!WindowsStringUtils::safe_mbstowcs(value,
+ & options.missing_symbols_url)) {
+ FprintfFlush(stderr, "main: safe_mbstowcs failed for %s\n",
+ value.c_str());
+ return 1;
+ }
+ } else if (option == "-mf") {
+ options.missing_symbols_file = value;
+ printf("Getting the list of missing symbols from a file. Fetch failures"
+ " will not be reported.\n");
+ options.report_fetch_failures = false;
+ } else if (option == "-t") {
+ if (!WindowsStringUtils::safe_mbstowcs(
+ value,
+ & options.fetch_symbol_failure_url)) {
+ FprintfFlush(stderr, "main: safe_mbstowcs failed for %s\n",
+ value.c_str());
+ return 1;
+ }
+ } else if (option == "-b") {
+ blacklist_regex_str = value;
+ } else {
+ return usage(argv[0]);
+ }
+ }
+
+ if (blacklist_regex_str.empty()) {
+ FprintfFlush(stderr, "No blacklist specified.\n");
+ return usage(argv[0]);
+ }
+
+ // Compile the blacklist regular expression for later use.
+ options.blacklist_regex = std::regex(blacklist_regex_str.c_str(),
+ std::regex_constants::icase);
+
+ // Set the defaults. If the user specified any MSSS servers, don't use
+ // any default.
+ if (!have_any_msss_servers) {
+ AddServer(kNoExeMSSSServer,& options.no_exe_internal_msss_servers,
+ & options.no_exe_external_msss_servers);
+ }
+
+ if (options.local_cache_path.empty()) {
+ options.local_cache_path = kLocalCachePath;
+ }
+
+ if (options.upload_symbols_url.empty()) {
+ FprintfFlush(stderr, "No upload symbols URL specified.\n");
+ return usage(argv[0]);
+ }
+ if (options.api_key.empty()) {
+ FprintfFlush(stderr, "No API key specified.\n");
+ return usage(argv[0]);
+ }
+ if (options.missing_symbols_url.empty() &&
+ options.missing_symbols_file.empty()) {
+ FprintfFlush(stderr, "No missing symbols URL or file specified.\n");
+ return usage(argv[0]);
+ }
+ if (options.fetch_symbol_failure_url.empty()) {
+ FprintfFlush(stderr, "No fetch symbol failure URL specified.\n");
+ return usage(argv[0]);
+ }
+
+ FprintfFlush(stdout,
+ "# of Symbol Servers (int/ext): %d/%d full, %d/%d no_exe\n",
+ options.full_internal_msss_servers.size(),
+ options.full_external_msss_servers.size(),
+ options.no_exe_internal_msss_servers.size(),
+ options.no_exe_external_msss_servers.size());
+
+ if (!ConvertMissingSymbolsList(options)) {
+ return 1;
+ }
+
+ time_string = CurrentDateAndTime();
+ FprintfFlush(stdout, "converter: %s: finished\n", time_string.c_str());
+ return 0;
+}
diff --git a/src/tools/windows/converter_exe/converter.gyp b/src/tools/windows/converter_exe/converter.gyp
deleted file mode 100644
index fe443d1b..00000000
--- a/src/tools/windows/converter_exe/converter.gyp
+++ /dev/null
@@ -1,57 +0,0 @@
-# Copyright 2013 Google Inc. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-# * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-# * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-{
- 'includes': [
- '../../../build/common.gypi',
- ],
- 'targets': [
- {
- 'target_name': 'converter_exe',
- 'type': 'executable',
- 'sources': [
- 'converter.cc',
- 'escaping.cc',
- 'escaping.h',
- 'http_client.h',
- 'http_download.cc',
- 'http_download.h',
- 'tokenizer.cc',
- 'tokenizer.h',
- 'winhttp_client.cc',
- 'winhttp_client.h',
- 'wininet_client.cc',
- 'wininet_client.h',
- ],
- 'dependencies': [
- '../../../common/windows/common_windows.gyp:common_windows_lib',
- '../converter/ms_symbol_server_converter.gyp:ms_symbol_server_converter',
- ],
- },
- ],
-}
diff --git a/src/tools/windows/converter_exe/escaping.cc b/src/tools/windows/converter_exe/escaping.cc
index 74a7203a..de074298 100644
--- a/src/tools/windows/converter_exe/escaping.cc
+++ b/src/tools/windows/converter_exe/escaping.cc
@@ -1,757 +1,757 @@
-// Copyright 2019 Google Inc. All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-#include "tools/windows/converter_exe/escaping.h"
-
-#include <assert.h>
-
-#define kApb kAsciiPropertyBits
-
-const unsigned char kAsciiPropertyBits[256] = {
- 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, // 0x00
- 0x40, 0x68, 0x48, 0x48, 0x48, 0x48, 0x40, 0x40,
- 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, // 0x10
- 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
- 0x28, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, // 0x20
- 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
- 0x84, 0x84, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
- 0x10, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x05, // 0x40
- 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
- 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, // 0x50
- 0x05, 0x05, 0x05, 0x10, 0x10, 0x10, 0x10, 0x10,
- 0x10, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x05, // 0x60
- 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
- 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, // 0x70
- 0x05, 0x05, 0x05, 0x10, 0x10, 0x10, 0x10, 0x40,
-};
-
-// Use !! to suppress the warning C4800 of forcing 'int' to 'bool'.
-static inline bool ascii_isspace(unsigned char c) { return !!(kApb[c] & 0x08); }
-
-///////////////////////////////////
-// scoped_array
-///////////////////////////////////
-// scoped_array<C> is like scoped_ptr<C>, except that the caller must allocate
-// with new [] and the destructor deletes objects with delete [].
-//
-// As with scoped_ptr<C>, a scoped_array<C> either points to an object
-// or is NULL. A scoped_array<C> owns the object that it points to.
-// scoped_array<T> is thread-compatible, and once you index into it,
-// the returned objects have only the threadsafety guarantees of T.
-//
-// Size: sizeof(scoped_array<C>) == sizeof(C*)
-template <class C>
-class scoped_array {
- public:
-
- // The element type
- typedef C element_type;
-
- // Constructor. Defaults to intializing with NULL.
- // There is no way to create an uninitialized scoped_array.
- // The input parameter must be allocated with new [].
- explicit scoped_array(C* p = NULL) : array_(p) { }
-
- // Destructor. If there is a C object, delete it.
- // We don't need to test ptr_ == NULL because C++ does that for us.
- ~scoped_array() {
- enum { type_must_be_complete = sizeof(C) };
- delete[] array_;
- }
-
- // Reset. Deletes the current owned object, if any.
- // Then takes ownership of a new object, if given.
- // this->reset(this->get()) works.
- void reset(C* p = NULL) {
- if (p != array_) {
- enum { type_must_be_complete = sizeof(C) };
- delete[] array_;
- array_ = p;
- }
- }
-
- // Get one element of the current object.
- // Will assert() if there is no current object, or index i is negative.
- C& operator[](std::ptrdiff_t i) const {
- assert(i >= 0);
- assert(array_ != NULL);
- return array_[i];
- }
-
- // Get a pointer to the zeroth element of the current object.
- // If there is no current object, return NULL.
- C* get() const {
- return array_;
- }
-
- // Comparison operators.
- // These return whether a scoped_array and a raw pointer refer to
- // the same array, not just to two different but equal arrays.
- bool operator==(const C* p) const { return array_ == p; }
- bool operator!=(const C* p) const { return array_ != p; }
-
- // Swap two scoped arrays.
- void swap(scoped_array& p2) {
- C* tmp = array_;
- array_ = p2.array_;
- p2.array_ = tmp;
- }
-
- // Release an array.
- // The return value is the current pointer held by this object.
- // If this object holds a NULL pointer, the return value is NULL.
- // After this operation, this object will hold a NULL pointer,
- // and will not own the object any more.
- C* release() {
- C* retVal = array_;
- array_ = NULL;
- return retVal;
- }
-
- private:
- C* array_;
-
- // Forbid comparison of different scoped_array types.
- template <class C2> bool operator==(scoped_array<C2> const& p2) const;
- template <class C2> bool operator!=(scoped_array<C2> const& p2) const;
-
- // Disallow evil constructors
- scoped_array(const scoped_array&);
- void operator=(const scoped_array&);
-};
-
-
-///////////////////////////////////
-// Escape methods
-///////////////////////////////////
-
-namespace strings {
-
-// Return a mutable char* pointing to a string's internal buffer,
-// which may not be null-terminated. Writing through this pointer will
-// modify the string.
-//
-// string_as_array(&str)[i] is valid for 0 <= i < str.size() until the
-// next call to a string method that invalidates iterators.
-//
-// As of 2006-04, there is no standard-blessed way of getting a
-// mutable reference to a string's internal buffer. However, issue 530
-// (http://www.open-std.org/JTC1/SC22/WG21/docs/lwg-active.html#530)
-// proposes this as the method. According to Matt Austern, this should
-// already work on all current implementations.
-inline char* string_as_array(string* str) {
- // DO NOT USE const_cast<char*>(str->data())! See the unittest for why.
- return str->empty() ? NULL : &*str->begin();
-}
-
-int CalculateBase64EscapedLen(int input_len, bool do_padding) {
- // these formulae were copied from comments that used to go with the base64
- // encoding functions
- int intermediate_result = 8 * input_len + 5;
- assert(intermediate_result > 0); // make sure we didn't overflow
- int len = intermediate_result / 6;
- if (do_padding) len = ((len + 3) / 4) * 4;
- return len;
-}
-
-// Base64Escape does padding, so this calculation includes padding.
-int CalculateBase64EscapedLen(int input_len) {
- return CalculateBase64EscapedLen(input_len, true);
-}
-
-// ----------------------------------------------------------------------
-// int Base64Unescape() - base64 decoder
-// int Base64Escape() - base64 encoder
-// int WebSafeBase64Unescape() - Google's variation of base64 decoder
-// int WebSafeBase64Escape() - Google's variation of base64 encoder
-//
-// Check out
-// http://www.cis.ohio-state.edu/htbin/rfc/rfc2045.html for formal
-// description, but what we care about is that...
-// Take the encoded stuff in groups of 4 characters and turn each
-// character into a code 0 to 63 thus:
-// A-Z map to 0 to 25
-// a-z map to 26 to 51
-// 0-9 map to 52 to 61
-// +(- for WebSafe) maps to 62
-// /(_ for WebSafe) maps to 63
-// There will be four numbers, all less than 64 which can be represented
-// by a 6 digit binary number (aaaaaa, bbbbbb, cccccc, dddddd respectively).
-// Arrange the 6 digit binary numbers into three bytes as such:
-// aaaaaabb bbbbcccc ccdddddd
-// Equals signs (one or two) are used at the end of the encoded block to
-// indicate that the text was not an integer multiple of three bytes long.
-// ----------------------------------------------------------------------
-
-int Base64UnescapeInternal(const char *src, int szsrc,
- char *dest, int szdest,
- const signed char* unbase64) {
- static const char kPad64 = '=';
-
- int decode = 0;
- int destidx = 0;
- int state = 0;
- unsigned int ch = 0;
- unsigned int temp = 0;
-
- // The GET_INPUT macro gets the next input character, skipping
- // over any whitespace, and stopping when we reach the end of the
- // string or when we read any non-data character. The arguments are
- // an arbitrary identifier (used as a label for goto) and the number
- // of data bytes that must remain in the input to avoid aborting the
- // loop.
-#define GET_INPUT(label, remain) \
- label: \
- --szsrc; \
- ch = *src++; \
- decode = unbase64[ch]; \
- if (decode < 0) { \
- if (ascii_isspace((char)ch) && szsrc >= remain) \
- goto label; \
- state = 4 - remain; \
- break; \
- }
-
- // if dest is null, we're just checking to see if it's legal input
- // rather than producing output. (I suspect this could just be done
- // with a regexp...). We duplicate the loop so this test can be
- // outside it instead of in every iteration.
-
- if (dest) {
- // This loop consumes 4 input bytes and produces 3 output bytes
- // per iteration. We can't know at the start that there is enough
- // data left in the string for a full iteration, so the loop may
- // break out in the middle; if so 'state' will be set to the
- // number of input bytes read.
-
- while (szsrc >= 4) {
- // We'll start by optimistically assuming that the next four
- // bytes of the string (src[0..3]) are four good data bytes
- // (that is, no nulls, whitespace, padding chars, or illegal
- // chars). We need to test src[0..2] for nulls individually
- // before constructing temp to preserve the property that we
- // never read past a null in the string (no matter how long
- // szsrc claims the string is).
-
- if (!src[0] || !src[1] || !src[2] ||
- (temp = ((unbase64[static_cast<int>(src[0])] << 18) |
- (unbase64[static_cast<int>(src[1])] << 12) |
- (unbase64[static_cast<int>(src[2])] << 6) |
- (unbase64[static_cast<int>(src[3])]))) & 0x80000000) {
- // Iff any of those four characters was bad (null, illegal,
- // whitespace, padding), then temp's high bit will be set
- // (because unbase64[] is -1 for all bad characters).
- //
- // We'll back up and resort to the slower decoder, which knows
- // how to handle those cases.
-
- GET_INPUT(first, 4);
- temp = decode;
- GET_INPUT(second, 3);
- temp = (temp << 6) | decode;
- GET_INPUT(third, 2);
- temp = (temp << 6) | decode;
- GET_INPUT(fourth, 1);
- temp = (temp << 6) | decode;
- } else {
- // We really did have four good data bytes, so advance four
- // characters in the string.
-
- szsrc -= 4;
- src += 4;
- decode = -1;
- ch = '\0';
- }
-
- // temp has 24 bits of input, so write that out as three bytes.
-
- if (destidx+3 > szdest) return -1;
- dest[destidx+2] = (char)temp;
- temp >>= 8;
- dest[destidx+1] = (char)temp;
- temp >>= 8;
- dest[destidx] = (char)temp;
- destidx += 3;
- }
- } else {
- while (szsrc >= 4) {
- if (!src[0] || !src[1] || !src[2] ||
- (temp = ((unbase64[static_cast<int>(src[0])] << 18) |
- (unbase64[static_cast<int>(src[1])] << 12) |
- (unbase64[static_cast<int>(src[2])] << 6) |
- (unbase64[static_cast<int>(src[3])]))) & 0x80000000) {
- GET_INPUT(first_no_dest, 4);
- GET_INPUT(second_no_dest, 3);
- GET_INPUT(third_no_dest, 2);
- GET_INPUT(fourth_no_dest, 1);
- } else {
- szsrc -= 4;
- src += 4;
- decode = -1;
- ch = '\0';
- }
- destidx += 3;
- }
- }
-
-#undef GET_INPUT
-
- // if the loop terminated because we read a bad character, return
- // now.
- if (decode < 0 && ch != '\0' && ch != kPad64 && !ascii_isspace((char)ch))
- return -1;
-
- if (ch == kPad64) {
- // if we stopped by hitting an '=', un-read that character -- we'll
- // look at it again when we count to check for the proper number of
- // equals signs at the end.
- ++szsrc;
- --src;
- } else {
- // This loop consumes 1 input byte per iteration. It's used to
- // clean up the 0-3 input bytes remaining when the first, faster
- // loop finishes. 'temp' contains the data from 'state' input
- // characters read by the first loop.
- while (szsrc > 0) {
- --szsrc;
- ch = *src++;
- decode = unbase64[ch];
- if (decode < 0) {
- if (ascii_isspace((char)ch)) {
- continue;
- } else if (ch == '\0') {
- break;
- } else if (ch == kPad64) {
- // back up one character; we'll read it again when we check
- // for the correct number of equals signs at the end.
- ++szsrc;
- --src;
- break;
- } else {
- return -1;
- }
- }
-
- // Each input character gives us six bits of output.
- temp = (temp << 6) | decode;
- ++state;
- if (state == 4) {
- // If we've accumulated 24 bits of output, write that out as
- // three bytes.
- if (dest) {
- if (destidx+3 > szdest) return -1;
- dest[destidx+2] = (char)temp;
- temp >>= 8;
- dest[destidx+1] = (char)temp;
- temp >>= 8;
- dest[destidx] = (char)temp;
- }
- destidx += 3;
- state = 0;
- temp = 0;
- }
- }
- }
-
- // Process the leftover data contained in 'temp' at the end of the input.
- int expected_equals = 0;
- switch (state) {
- case 0:
- // Nothing left over; output is a multiple of 3 bytes.
- break;
-
- case 1:
- // Bad input; we have 6 bits left over.
- return -1;
-
- case 2:
- // Produce one more output byte from the 12 input bits we have left.
- if (dest) {
- if (destidx+1 > szdest) return -1;
- temp >>= 4;
- dest[destidx] = (char)temp;
- }
- ++destidx;
- expected_equals = 2;
- break;
-
- case 3:
- // Produce two more output bytes from the 18 input bits we have left.
- if (dest) {
- if (destidx+2 > szdest) return -1;
- temp >>= 2;
- dest[destidx+1] = (char)temp;
- temp >>= 8;
- dest[destidx] = (char)temp;
- }
- destidx += 2;
- expected_equals = 1;
- break;
-
- default:
- // state should have no other values at this point.
- fprintf(stdout, "This can't happen; base64 decoder state = %d", state);
- }
-
- // The remainder of the string should be all whitespace, mixed with
- // exactly 0 equals signs, or exactly 'expected_equals' equals
- // signs. (Always accepting 0 equals signs is a google extension
- // not covered in the RFC.)
-
- int equals = 0;
- while (szsrc > 0 && *src) {
- if (*src == kPad64)
- ++equals;
- else if (!ascii_isspace(*src))
- return -1;
- --szsrc;
- ++src;
- }
-
- return (equals == 0 || equals == expected_equals) ? destidx : -1;
-}
-
-int Base64Unescape(const char *src, int szsrc, char *dest, int szdest) {
- static const signed char UnBase64[] = {
- -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, 62/*+*/, -1, -1, -1, 63/*/ */,
- 52/*0*/, 53/*1*/, 54/*2*/, 55/*3*/, 56/*4*/, 57/*5*/, 58/*6*/, 59/*7*/,
- 60/*8*/, 61/*9*/, -1, -1, -1, -1, -1, -1,
- -1, 0/*A*/, 1/*B*/, 2/*C*/, 3/*D*/, 4/*E*/, 5/*F*/, 6/*G*/,
- 7/*H*/, 8/*I*/, 9/*J*/, 10/*K*/, 11/*L*/, 12/*M*/, 13/*N*/, 14/*O*/,
- 15/*P*/, 16/*Q*/, 17/*R*/, 18/*S*/, 19/*T*/, 20/*U*/, 21/*V*/, 22/*W*/,
- 23/*X*/, 24/*Y*/, 25/*Z*/, -1, -1, -1, -1, -1,
- -1, 26/*a*/, 27/*b*/, 28/*c*/, 29/*d*/, 30/*e*/, 31/*f*/, 32/*g*/,
- 33/*h*/, 34/*i*/, 35/*j*/, 36/*k*/, 37/*l*/, 38/*m*/, 39/*n*/, 40/*o*/,
- 41/*p*/, 42/*q*/, 43/*r*/, 44/*s*/, 45/*t*/, 46/*u*/, 47/*v*/, 48/*w*/,
- 49/*x*/, 50/*y*/, 51/*z*/, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1
- };
- // The above array was generated by the following code
- // #include <sys/time.h>
- // #include <stdlib.h>
- // #include <string.h>
- // main()
- // {
- // static const char Base64[] =
- // "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
- // char *pos;
- // int idx, i, j;
- // printf(" ");
- // for (i = 0; i < 255; i += 8) {
- // for (j = i; j < i + 8; j++) {
- // pos = strchr(Base64, j);
- // if ((pos == NULL) || (j == 0))
- // idx = -1;
- // else
- // idx = pos - Base64;
- // if (idx == -1)
- // printf(" %2d, ", idx);
- // else
- // printf(" %2d/*%c*/,", idx, j);
- // }
- // printf("\n ");
- // }
- // }
-
- return Base64UnescapeInternal(src, szsrc, dest, szdest, UnBase64);
-}
-
-bool Base64Unescape(const char *src, int slen, string* dest) {
- // Determine the size of the output string. Base64 encodes every 3 bytes into
- // 4 characters. any leftover chars are added directly for good measure.
- // This is documented in the base64 RFC: http://www.ietf.org/rfc/rfc3548.txt
- const int dest_len = 3 * (slen / 4) + (slen % 4);
-
- dest->resize(dest_len);
-
- // We are getting the destination buffer by getting the beginning of the
- // string and converting it into a char *.
- const int len = Base64Unescape(src, slen,
- string_as_array(dest), dest->size());
- if (len < 0) {
- return false;
- }
-
- // could be shorter if there was padding
- assert(len <= dest_len);
- dest->resize(len);
-
- return true;
-}
-
-// Base64Escape
-//
-// NOTE: We have to use an unsigned type for src because code built
-// in the the /google tree treats characters as signed unless
-// otherwised specified.
-//
-// TODO(who?): Move this function to use the char* type for "src"
-int Base64EscapeInternal(const unsigned char *src, int szsrc,
- char *dest, int szdest, const char *base64,
- bool do_padding) {
- static const char kPad64 = '=';
-
- if (szsrc <= 0) return 0;
-
- char *cur_dest = dest;
- const unsigned char *cur_src = src;
-
- // Three bytes of data encodes to four characters of cyphertext.
- // So we can pump through three-byte chunks atomically.
- while (szsrc > 2) { /* keep going until we have less than 24 bits */
- if ((szdest -= 4) < 0) return 0;
- cur_dest[0] = base64[cur_src[0] >> 2];
- cur_dest[1] = base64[((cur_src[0] & 0x03) << 4) + (cur_src[1] >> 4)];
- cur_dest[2] = base64[((cur_src[1] & 0x0f) << 2) + (cur_src[2] >> 6)];
- cur_dest[3] = base64[cur_src[2] & 0x3f];
-
- cur_dest += 4;
- cur_src += 3;
- szsrc -= 3;
- }
-
- /* now deal with the tail (<=2 bytes) */
- switch (szsrc) {
- case 0:
- // Nothing left; nothing more to do.
- break;
- case 1:
- // One byte left: this encodes to two characters, and (optionally)
- // two pad characters to round out the four-character cypherblock.
- if ((szdest -= 2) < 0) return 0;
- cur_dest[0] = base64[cur_src[0] >> 2];
- cur_dest[1] = base64[(cur_src[0] & 0x03) << 4];
- cur_dest += 2;
- if (do_padding) {
- if ((szdest -= 2) < 0) return 0;
- cur_dest[0] = kPad64;
- cur_dest[1] = kPad64;
- cur_dest += 2;
- }
- break;
- case 2:
- // Two bytes left: this encodes to three characters, and (optionally)
- // one pad character to round out the four-character cypherblock.
- if ((szdest -= 3) < 0) return 0;
- cur_dest[0] = base64[cur_src[0] >> 2];
- cur_dest[1] = base64[((cur_src[0] & 0x03) << 4) + (cur_src[1] >> 4)];
- cur_dest[2] = base64[(cur_src[1] & 0x0f) << 2];
- cur_dest += 3;
- if (do_padding) {
- if ((szdest -= 1) < 0) return 0;
- cur_dest[0] = kPad64;
- cur_dest += 1;
- }
- break;
- default:
- // Should not be reached: blocks of 3 bytes are handled
- // in the while loop before this switch statement.
- fprintf(stderr, "Logic problem? szsrc = %d", szsrc);
- assert(false);
- break;
- }
- return (cur_dest - dest);
-}
-
-static const char kBase64Chars[] =
-"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
-
-static const char kWebSafeBase64Chars[] =
-"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
-
-int Base64Escape(const unsigned char *src, int szsrc, char *dest, int szdest) {
- return Base64EscapeInternal(src, szsrc, dest, szdest, kBase64Chars, true);
-}
-
-void Base64Escape(const unsigned char *src, int szsrc,
- string* dest, bool do_padding) {
- const int max_escaped_size =
- CalculateBase64EscapedLen(szsrc, do_padding);
- dest->clear();
- dest->resize(max_escaped_size + 1, '\0');
- const int escaped_len = Base64EscapeInternal(src, szsrc,
- &*dest->begin(), dest->size(),
- kBase64Chars,
- do_padding);
- assert(max_escaped_size <= escaped_len);
- dest->resize(escaped_len);
-}
-
-void Base64Escape(const string& src, string* dest) {
- Base64Escape(reinterpret_cast<const unsigned char*>(src.c_str()),
- src.size(), dest, true);
-}
-
-////////////////////////////////////////////////////
-// WebSafe methods
-////////////////////////////////////////////////////
-
-int WebSafeBase64Unescape(const char *src, int szsrc, char *dest, int szdest) {
- static const signed char UnBase64[] = {
- -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, 62/*-*/, -1, -1,
- 52/*0*/, 53/*1*/, 54/*2*/, 55/*3*/, 56/*4*/, 57/*5*/, 58/*6*/, 59/*7*/,
- 60/*8*/, 61/*9*/, -1, -1, -1, -1, -1, -1,
- -1, 0/*A*/, 1/*B*/, 2/*C*/, 3/*D*/, 4/*E*/, 5/*F*/, 6/*G*/,
- 7/*H*/, 8/*I*/, 9/*J*/, 10/*K*/, 11/*L*/, 12/*M*/, 13/*N*/, 14/*O*/,
- 15/*P*/, 16/*Q*/, 17/*R*/, 18/*S*/, 19/*T*/, 20/*U*/, 21/*V*/, 22/*W*/,
- 23/*X*/, 24/*Y*/, 25/*Z*/, -1, -1, -1, -1, 63/*_*/,
- -1, 26/*a*/, 27/*b*/, 28/*c*/, 29/*d*/, 30/*e*/, 31/*f*/, 32/*g*/,
- 33/*h*/, 34/*i*/, 35/*j*/, 36/*k*/, 37/*l*/, 38/*m*/, 39/*n*/, 40/*o*/,
- 41/*p*/, 42/*q*/, 43/*r*/, 44/*s*/, 45/*t*/, 46/*u*/, 47/*v*/, 48/*w*/,
- 49/*x*/, 50/*y*/, 51/*z*/, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1
- };
- // The above array was generated by the following code
- // #include <sys/time.h>
- // #include <stdlib.h>
- // #include <string.h>
- // main()
- // {
- // static const char Base64[] =
- // "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
- // char *pos;
- // int idx, i, j;
- // printf(" ");
- // for (i = 0; i < 255; i += 8) {
- // for (j = i; j < i + 8; j++) {
- // pos = strchr(Base64, j);
- // if ((pos == NULL) || (j == 0))
- // idx = -1;
- // else
- // idx = pos - Base64;
- // if (idx == -1)
- // printf(" %2d, ", idx);
- // else
- // printf(" %2d/*%c*/,", idx, j);
- // }
- // printf("\n ");
- // }
- // }
-
- return Base64UnescapeInternal(src, szsrc, dest, szdest, UnBase64);
-}
-
-bool WebSafeBase64Unescape(const char *src, int slen, string* dest) {
- int dest_len = 3 * (slen / 4) + (slen % 4);
- dest->clear();
- dest->resize(dest_len);
- int len = WebSafeBase64Unescape(src, slen, &*dest->begin(), dest->size());
- if (len < 0) {
- dest->clear();
- return false;
- }
- // could be shorter if there was padding
- assert(len <= dest_len);
- dest->resize(len);
- return true;
-}
-
-bool WebSafeBase64Unescape(const string& src, string* dest) {
- return WebSafeBase64Unescape(src.data(), src.size(), dest);
-}
-
-int WebSafeBase64Escape(const unsigned char *src, int szsrc, char *dest,
- int szdest, bool do_padding) {
- return Base64EscapeInternal(src, szsrc, dest, szdest,
- kWebSafeBase64Chars, do_padding);
-}
-
-void WebSafeBase64Escape(const unsigned char *src, int szsrc,
- string *dest, bool do_padding) {
- const int max_escaped_size =
- CalculateBase64EscapedLen(szsrc, do_padding);
- dest->clear();
- dest->resize(max_escaped_size + 1, '\0');
- const int escaped_len = Base64EscapeInternal(src, szsrc,
- &*dest->begin(), dest->size(),
- kWebSafeBase64Chars,
- do_padding);
- assert(max_escaped_size <= escaped_len);
- dest->resize(escaped_len);
-}
-
-void WebSafeBase64EscapeInternal(const string& src,
- string* dest,
- bool do_padding) {
- int encoded_len = CalculateBase64EscapedLen(src.size());
- scoped_array<char> buf(new char[encoded_len]);
- int len = WebSafeBase64Escape(reinterpret_cast<const unsigned char*>(src.c_str()),
- src.size(), buf.get(),
- encoded_len, do_padding);
- dest->assign(buf.get(), len);
-}
-
-void WebSafeBase64Escape(const string& src, string* dest) {
- WebSafeBase64EscapeInternal(src, dest, false);
-}
-
-void WebSafeBase64EscapeWithPadding(const string& src, string* dest) {
- WebSafeBase64EscapeInternal(src, dest, true);
-}
-
-} // namespace strings
+// Copyright 2019 Google LLC
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google LLC nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "tools/windows/converter_exe/escaping.h"
+
+#include <assert.h>
+
+#define kApb kAsciiPropertyBits
+
+const unsigned char kAsciiPropertyBits[256] = {
+ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, // 0x00
+ 0x40, 0x68, 0x48, 0x48, 0x48, 0x48, 0x40, 0x40,
+ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, // 0x10
+ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
+ 0x28, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, // 0x20
+ 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
+ 0x84, 0x84, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
+ 0x10, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x05, // 0x40
+ 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
+ 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, // 0x50
+ 0x05, 0x05, 0x05, 0x10, 0x10, 0x10, 0x10, 0x10,
+ 0x10, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x05, // 0x60
+ 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
+ 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, // 0x70
+ 0x05, 0x05, 0x05, 0x10, 0x10, 0x10, 0x10, 0x40,
+};
+
+// Use !! to suppress the warning C4800 of forcing 'int' to 'bool'.
+static inline bool ascii_isspace(unsigned char c) { return !!(kApb[c] & 0x08); }
+
+///////////////////////////////////
+// scoped_array
+///////////////////////////////////
+// scoped_array<C> is like scoped_ptr<C>, except that the caller must allocate
+// with new [] and the destructor deletes objects with delete [].
+//
+// As with scoped_ptr<C>, a scoped_array<C> either points to an object
+// or is NULL. A scoped_array<C> owns the object that it points to.
+// scoped_array<T> is thread-compatible, and once you index into it,
+// the returned objects have only the threadsafety guarantees of T.
+//
+// Size: sizeof(scoped_array<C>) == sizeof(C*)
+template <class C>
+class scoped_array {
+ public:
+
+ // The element type
+ typedef C element_type;
+
+ // Constructor. Defaults to intializing with NULL.
+ // There is no way to create an uninitialized scoped_array.
+ // The input parameter must be allocated with new [].
+ explicit scoped_array(C* p = NULL) : array_(p) { }
+
+ // Destructor. If there is a C object, delete it.
+ // We don't need to test ptr_ == NULL because C++ does that for us.
+ ~scoped_array() {
+ enum { type_must_be_complete = sizeof(C) };
+ delete[] array_;
+ }
+
+ // Reset. Deletes the current owned object, if any.
+ // Then takes ownership of a new object, if given.
+ // this->reset(this->get()) works.
+ void reset(C* p = NULL) {
+ if (p != array_) {
+ enum { type_must_be_complete = sizeof(C) };
+ delete[] array_;
+ array_ = p;
+ }
+ }
+
+ // Get one element of the current object.
+ // Will assert() if there is no current object, or index i is negative.
+ C& operator[](std::ptrdiff_t i) const {
+ assert(i >= 0);
+ assert(array_ != NULL);
+ return array_[i];
+ }
+
+ // Get a pointer to the zeroth element of the current object.
+ // If there is no current object, return NULL.
+ C* get() const {
+ return array_;
+ }
+
+ // Comparison operators.
+ // These return whether a scoped_array and a raw pointer refer to
+ // the same array, not just to two different but equal arrays.
+ bool operator==(const C* p) const { return array_ == p; }
+ bool operator!=(const C* p) const { return array_ != p; }
+
+ // Swap two scoped arrays.
+ void swap(scoped_array& p2) {
+ C* tmp = array_;
+ array_ = p2.array_;
+ p2.array_ = tmp;
+ }
+
+ // Release an array.
+ // The return value is the current pointer held by this object.
+ // If this object holds a NULL pointer, the return value is NULL.
+ // After this operation, this object will hold a NULL pointer,
+ // and will not own the object any more.
+ C* release() {
+ C* retVal = array_;
+ array_ = NULL;
+ return retVal;
+ }
+
+ private:
+ C* array_;
+
+ // Forbid comparison of different scoped_array types.
+ template <class C2> bool operator==(scoped_array<C2> const& p2) const;
+ template <class C2> bool operator!=(scoped_array<C2> const& p2) const;
+
+ // Disallow evil constructors
+ scoped_array(const scoped_array&);
+ void operator=(const scoped_array&);
+};
+
+
+///////////////////////////////////
+// Escape methods
+///////////////////////////////////
+
+namespace strings {
+
+// Return a mutable char* pointing to a string's internal buffer,
+// which may not be null-terminated. Writing through this pointer will
+// modify the string.
+//
+// string_as_array(&str)[i] is valid for 0 <= i < str.size() until the
+// next call to a string method that invalidates iterators.
+//
+// As of 2006-04, there is no standard-blessed way of getting a
+// mutable reference to a string's internal buffer. However, issue 530
+// (http://www.open-std.org/JTC1/SC22/WG21/docs/lwg-active.html#530)
+// proposes this as the method. According to Matt Austern, this should
+// already work on all current implementations.
+inline char* string_as_array(string* str) {
+ // DO NOT USE const_cast<char*>(str->data())! See the unittest for why.
+ return str->empty() ? NULL : &*str->begin();
+}
+
+int CalculateBase64EscapedLen(int input_len, bool do_padding) {
+ // these formulae were copied from comments that used to go with the base64
+ // encoding functions
+ int intermediate_result = 8 * input_len + 5;
+ assert(intermediate_result > 0); // make sure we didn't overflow
+ int len = intermediate_result / 6;
+ if (do_padding) len = ((len + 3) / 4) * 4;
+ return len;
+}
+
+// Base64Escape does padding, so this calculation includes padding.
+int CalculateBase64EscapedLen(int input_len) {
+ return CalculateBase64EscapedLen(input_len, true);
+}
+
+// ----------------------------------------------------------------------
+// int Base64Unescape() - base64 decoder
+// int Base64Escape() - base64 encoder
+// int WebSafeBase64Unescape() - Google's variation of base64 decoder
+// int WebSafeBase64Escape() - Google's variation of base64 encoder
+//
+// Check out
+// http://www.cis.ohio-state.edu/htbin/rfc/rfc2045.html for formal
+// description, but what we care about is that...
+// Take the encoded stuff in groups of 4 characters and turn each
+// character into a code 0 to 63 thus:
+// A-Z map to 0 to 25
+// a-z map to 26 to 51
+// 0-9 map to 52 to 61
+// +(- for WebSafe) maps to 62
+// /(_ for WebSafe) maps to 63
+// There will be four numbers, all less than 64 which can be represented
+// by a 6 digit binary number (aaaaaa, bbbbbb, cccccc, dddddd respectively).
+// Arrange the 6 digit binary numbers into three bytes as such:
+// aaaaaabb bbbbcccc ccdddddd
+// Equals signs (one or two) are used at the end of the encoded block to
+// indicate that the text was not an integer multiple of three bytes long.
+// ----------------------------------------------------------------------
+
+int Base64UnescapeInternal(const char *src, int szsrc,
+ char *dest, int szdest,
+ const signed char* unbase64) {
+ static const char kPad64 = '=';
+
+ int decode = 0;
+ int destidx = 0;
+ int state = 0;
+ unsigned int ch = 0;
+ unsigned int temp = 0;
+
+ // The GET_INPUT macro gets the next input character, skipping
+ // over any whitespace, and stopping when we reach the end of the
+ // string or when we read any non-data character. The arguments are
+ // an arbitrary identifier (used as a label for goto) and the number
+ // of data bytes that must remain in the input to avoid aborting the
+ // loop.
+#define GET_INPUT(label, remain) \
+ label: \
+ --szsrc; \
+ ch = *src++; \
+ decode = unbase64[ch]; \
+ if (decode < 0) { \
+ if (ascii_isspace((char)ch) && szsrc >= remain) \
+ goto label; \
+ state = 4 - remain; \
+ break; \
+ }
+
+ // if dest is null, we're just checking to see if it's legal input
+ // rather than producing output. (I suspect this could just be done
+ // with a regexp...). We duplicate the loop so this test can be
+ // outside it instead of in every iteration.
+
+ if (dest) {
+ // This loop consumes 4 input bytes and produces 3 output bytes
+ // per iteration. We can't know at the start that there is enough
+ // data left in the string for a full iteration, so the loop may
+ // break out in the middle; if so 'state' will be set to the
+ // number of input bytes read.
+
+ while (szsrc >= 4) {
+ // We'll start by optimistically assuming that the next four
+ // bytes of the string (src[0..3]) are four good data bytes
+ // (that is, no nulls, whitespace, padding chars, or illegal
+ // chars). We need to test src[0..2] for nulls individually
+ // before constructing temp to preserve the property that we
+ // never read past a null in the string (no matter how long
+ // szsrc claims the string is).
+
+ if (!src[0] || !src[1] || !src[2] ||
+ (temp = ((unbase64[static_cast<int>(src[0])] << 18) |
+ (unbase64[static_cast<int>(src[1])] << 12) |
+ (unbase64[static_cast<int>(src[2])] << 6) |
+ (unbase64[static_cast<int>(src[3])]))) & 0x80000000) {
+ // Iff any of those four characters was bad (null, illegal,
+ // whitespace, padding), then temp's high bit will be set
+ // (because unbase64[] is -1 for all bad characters).
+ //
+ // We'll back up and resort to the slower decoder, which knows
+ // how to handle those cases.
+
+ GET_INPUT(first, 4);
+ temp = decode;
+ GET_INPUT(second, 3);
+ temp = (temp << 6) | decode;
+ GET_INPUT(third, 2);
+ temp = (temp << 6) | decode;
+ GET_INPUT(fourth, 1);
+ temp = (temp << 6) | decode;
+ } else {
+ // We really did have four good data bytes, so advance four
+ // characters in the string.
+
+ szsrc -= 4;
+ src += 4;
+ decode = -1;
+ ch = '\0';
+ }
+
+ // temp has 24 bits of input, so write that out as three bytes.
+
+ if (destidx+3 > szdest) return -1;
+ dest[destidx+2] = (char)temp;
+ temp >>= 8;
+ dest[destidx+1] = (char)temp;
+ temp >>= 8;
+ dest[destidx] = (char)temp;
+ destidx += 3;
+ }
+ } else {
+ while (szsrc >= 4) {
+ if (!src[0] || !src[1] || !src[2] ||
+ (temp = ((unbase64[static_cast<int>(src[0])] << 18) |
+ (unbase64[static_cast<int>(src[1])] << 12) |
+ (unbase64[static_cast<int>(src[2])] << 6) |
+ (unbase64[static_cast<int>(src[3])]))) & 0x80000000) {
+ GET_INPUT(first_no_dest, 4);
+ GET_INPUT(second_no_dest, 3);
+ GET_INPUT(third_no_dest, 2);
+ GET_INPUT(fourth_no_dest, 1);
+ } else {
+ szsrc -= 4;
+ src += 4;
+ decode = -1;
+ ch = '\0';
+ }
+ destidx += 3;
+ }
+ }
+
+#undef GET_INPUT
+
+ // if the loop terminated because we read a bad character, return
+ // now.
+ if (decode < 0 && ch != '\0' && ch != kPad64 && !ascii_isspace((char)ch))
+ return -1;
+
+ if (ch == kPad64) {
+ // if we stopped by hitting an '=', un-read that character -- we'll
+ // look at it again when we count to check for the proper number of
+ // equals signs at the end.
+ ++szsrc;
+ --src;
+ } else {
+ // This loop consumes 1 input byte per iteration. It's used to
+ // clean up the 0-3 input bytes remaining when the first, faster
+ // loop finishes. 'temp' contains the data from 'state' input
+ // characters read by the first loop.
+ while (szsrc > 0) {
+ --szsrc;
+ ch = *src++;
+ decode = unbase64[ch];
+ if (decode < 0) {
+ if (ascii_isspace((char)ch)) {
+ continue;
+ } else if (ch == '\0') {
+ break;
+ } else if (ch == kPad64) {
+ // back up one character; we'll read it again when we check
+ // for the correct number of equals signs at the end.
+ ++szsrc;
+ --src;
+ break;
+ } else {
+ return -1;
+ }
+ }
+
+ // Each input character gives us six bits of output.
+ temp = (temp << 6) | decode;
+ ++state;
+ if (state == 4) {
+ // If we've accumulated 24 bits of output, write that out as
+ // three bytes.
+ if (dest) {
+ if (destidx+3 > szdest) return -1;
+ dest[destidx+2] = (char)temp;
+ temp >>= 8;
+ dest[destidx+1] = (char)temp;
+ temp >>= 8;
+ dest[destidx] = (char)temp;
+ }
+ destidx += 3;
+ state = 0;
+ temp = 0;
+ }
+ }
+ }
+
+ // Process the leftover data contained in 'temp' at the end of the input.
+ int expected_equals = 0;
+ switch (state) {
+ case 0:
+ // Nothing left over; output is a multiple of 3 bytes.
+ break;
+
+ case 1:
+ // Bad input; we have 6 bits left over.
+ return -1;
+
+ case 2:
+ // Produce one more output byte from the 12 input bits we have left.
+ if (dest) {
+ if (destidx+1 > szdest) return -1;
+ temp >>= 4;
+ dest[destidx] = (char)temp;
+ }
+ ++destidx;
+ expected_equals = 2;
+ break;
+
+ case 3:
+ // Produce two more output bytes from the 18 input bits we have left.
+ if (dest) {
+ if (destidx+2 > szdest) return -1;
+ temp >>= 2;
+ dest[destidx+1] = (char)temp;
+ temp >>= 8;
+ dest[destidx] = (char)temp;
+ }
+ destidx += 2;
+ expected_equals = 1;
+ break;
+
+ default:
+ // state should have no other values at this point.
+ fprintf(stdout, "This can't happen; base64 decoder state = %d", state);
+ }
+
+ // The remainder of the string should be all whitespace, mixed with
+ // exactly 0 equals signs, or exactly 'expected_equals' equals
+ // signs. (Always accepting 0 equals signs is a google extension
+ // not covered in the RFC.)
+
+ int equals = 0;
+ while (szsrc > 0 && *src) {
+ if (*src == kPad64)
+ ++equals;
+ else if (!ascii_isspace(*src))
+ return -1;
+ --szsrc;
+ ++src;
+ }
+
+ return (equals == 0 || equals == expected_equals) ? destidx : -1;
+}
+
+int Base64Unescape(const char *src, int szsrc, char *dest, int szdest) {
+ static const signed char UnBase64[] = {
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, 62/*+*/, -1, -1, -1, 63/*/ */,
+ 52/*0*/, 53/*1*/, 54/*2*/, 55/*3*/, 56/*4*/, 57/*5*/, 58/*6*/, 59/*7*/,
+ 60/*8*/, 61/*9*/, -1, -1, -1, -1, -1, -1,
+ -1, 0/*A*/, 1/*B*/, 2/*C*/, 3/*D*/, 4/*E*/, 5/*F*/, 6/*G*/,
+ 7/*H*/, 8/*I*/, 9/*J*/, 10/*K*/, 11/*L*/, 12/*M*/, 13/*N*/, 14/*O*/,
+ 15/*P*/, 16/*Q*/, 17/*R*/, 18/*S*/, 19/*T*/, 20/*U*/, 21/*V*/, 22/*W*/,
+ 23/*X*/, 24/*Y*/, 25/*Z*/, -1, -1, -1, -1, -1,
+ -1, 26/*a*/, 27/*b*/, 28/*c*/, 29/*d*/, 30/*e*/, 31/*f*/, 32/*g*/,
+ 33/*h*/, 34/*i*/, 35/*j*/, 36/*k*/, 37/*l*/, 38/*m*/, 39/*n*/, 40/*o*/,
+ 41/*p*/, 42/*q*/, 43/*r*/, 44/*s*/, 45/*t*/, 46/*u*/, 47/*v*/, 48/*w*/,
+ 49/*x*/, 50/*y*/, 51/*z*/, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1
+ };
+ // The above array was generated by the following code
+ // #include <sys/time.h>
+ // #include <stdlib.h>
+ // #include <string.h>
+ // main()
+ // {
+ // static const char Base64[] =
+ // "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+ // char *pos;
+ // int idx, i, j;
+ // printf(" ");
+ // for (i = 0; i < 255; i += 8) {
+ // for (j = i; j < i + 8; j++) {
+ // pos = strchr(Base64, j);
+ // if ((pos == NULL) || (j == 0))
+ // idx = -1;
+ // else
+ // idx = pos - Base64;
+ // if (idx == -1)
+ // printf(" %2d, ", idx);
+ // else
+ // printf(" %2d/*%c*/,", idx, j);
+ // }
+ // printf("\n ");
+ // }
+ // }
+
+ return Base64UnescapeInternal(src, szsrc, dest, szdest, UnBase64);
+}
+
+bool Base64Unescape(const char *src, int slen, string* dest) {
+ // Determine the size of the output string. Base64 encodes every 3 bytes into
+ // 4 characters. any leftover chars are added directly for good measure.
+ // This is documented in the base64 RFC: http://www.ietf.org/rfc/rfc3548.txt
+ const int dest_len = 3 * (slen / 4) + (slen % 4);
+
+ dest->resize(dest_len);
+
+ // We are getting the destination buffer by getting the beginning of the
+ // string and converting it into a char *.
+ const int len = Base64Unescape(src, slen,
+ string_as_array(dest), dest->size());
+ if (len < 0) {
+ return false;
+ }
+
+ // could be shorter if there was padding
+ assert(len <= dest_len);
+ dest->resize(len);
+
+ return true;
+}
+
+// Base64Escape
+//
+// NOTE: We have to use an unsigned type for src because code built
+// in the the /google tree treats characters as signed unless
+// otherwised specified.
+//
+// TODO(who?): Move this function to use the char* type for "src"
+int Base64EscapeInternal(const unsigned char *src, int szsrc,
+ char *dest, int szdest, const char *base64,
+ bool do_padding) {
+ static const char kPad64 = '=';
+
+ if (szsrc <= 0) return 0;
+
+ char *cur_dest = dest;
+ const unsigned char *cur_src = src;
+
+ // Three bytes of data encodes to four characters of cyphertext.
+ // So we can pump through three-byte chunks atomically.
+ while (szsrc > 2) { /* keep going until we have less than 24 bits */
+ if ((szdest -= 4) < 0) return 0;
+ cur_dest[0] = base64[cur_src[0] >> 2];
+ cur_dest[1] = base64[((cur_src[0] & 0x03) << 4) + (cur_src[1] >> 4)];
+ cur_dest[2] = base64[((cur_src[1] & 0x0f) << 2) + (cur_src[2] >> 6)];
+ cur_dest[3] = base64[cur_src[2] & 0x3f];
+
+ cur_dest += 4;
+ cur_src += 3;
+ szsrc -= 3;
+ }
+
+ /* now deal with the tail (<=2 bytes) */
+ switch (szsrc) {
+ case 0:
+ // Nothing left; nothing more to do.
+ break;
+ case 1:
+ // One byte left: this encodes to two characters, and (optionally)
+ // two pad characters to round out the four-character cypherblock.
+ if ((szdest -= 2) < 0) return 0;
+ cur_dest[0] = base64[cur_src[0] >> 2];
+ cur_dest[1] = base64[(cur_src[0] & 0x03) << 4];
+ cur_dest += 2;
+ if (do_padding) {
+ if ((szdest -= 2) < 0) return 0;
+ cur_dest[0] = kPad64;
+ cur_dest[1] = kPad64;
+ cur_dest += 2;
+ }
+ break;
+ case 2:
+ // Two bytes left: this encodes to three characters, and (optionally)
+ // one pad character to round out the four-character cypherblock.
+ if ((szdest -= 3) < 0) return 0;
+ cur_dest[0] = base64[cur_src[0] >> 2];
+ cur_dest[1] = base64[((cur_src[0] & 0x03) << 4) + (cur_src[1] >> 4)];
+ cur_dest[2] = base64[(cur_src[1] & 0x0f) << 2];
+ cur_dest += 3;
+ if (do_padding) {
+ if ((szdest -= 1) < 0) return 0;
+ cur_dest[0] = kPad64;
+ cur_dest += 1;
+ }
+ break;
+ default:
+ // Should not be reached: blocks of 3 bytes are handled
+ // in the while loop before this switch statement.
+ fprintf(stderr, "Logic problem? szsrc = %d", szsrc);
+ assert(false);
+ break;
+ }
+ return (cur_dest - dest);
+}
+
+static const char kBase64Chars[] =
+"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+static const char kWebSafeBase64Chars[] =
+"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
+
+int Base64Escape(const unsigned char *src, int szsrc, char *dest, int szdest) {
+ return Base64EscapeInternal(src, szsrc, dest, szdest, kBase64Chars, true);
+}
+
+void Base64Escape(const unsigned char *src, int szsrc,
+ string* dest, bool do_padding) {
+ const int max_escaped_size =
+ CalculateBase64EscapedLen(szsrc, do_padding);
+ dest->clear();
+ dest->resize(max_escaped_size + 1, '\0');
+ const int escaped_len = Base64EscapeInternal(src, szsrc,
+ &*dest->begin(), dest->size(),
+ kBase64Chars,
+ do_padding);
+ assert(max_escaped_size <= escaped_len);
+ dest->resize(escaped_len);
+}
+
+void Base64Escape(const string& src, string* dest) {
+ Base64Escape(reinterpret_cast<const unsigned char*>(src.c_str()),
+ src.size(), dest, true);
+}
+
+////////////////////////////////////////////////////
+// WebSafe methods
+////////////////////////////////////////////////////
+
+int WebSafeBase64Unescape(const char *src, int szsrc, char *dest, int szdest) {
+ static const signed char UnBase64[] = {
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, 62/*-*/, -1, -1,
+ 52/*0*/, 53/*1*/, 54/*2*/, 55/*3*/, 56/*4*/, 57/*5*/, 58/*6*/, 59/*7*/,
+ 60/*8*/, 61/*9*/, -1, -1, -1, -1, -1, -1,
+ -1, 0/*A*/, 1/*B*/, 2/*C*/, 3/*D*/, 4/*E*/, 5/*F*/, 6/*G*/,
+ 7/*H*/, 8/*I*/, 9/*J*/, 10/*K*/, 11/*L*/, 12/*M*/, 13/*N*/, 14/*O*/,
+ 15/*P*/, 16/*Q*/, 17/*R*/, 18/*S*/, 19/*T*/, 20/*U*/, 21/*V*/, 22/*W*/,
+ 23/*X*/, 24/*Y*/, 25/*Z*/, -1, -1, -1, -1, 63/*_*/,
+ -1, 26/*a*/, 27/*b*/, 28/*c*/, 29/*d*/, 30/*e*/, 31/*f*/, 32/*g*/,
+ 33/*h*/, 34/*i*/, 35/*j*/, 36/*k*/, 37/*l*/, 38/*m*/, 39/*n*/, 40/*o*/,
+ 41/*p*/, 42/*q*/, 43/*r*/, 44/*s*/, 45/*t*/, 46/*u*/, 47/*v*/, 48/*w*/,
+ 49/*x*/, 50/*y*/, 51/*z*/, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1
+ };
+ // The above array was generated by the following code
+ // #include <sys/time.h>
+ // #include <stdlib.h>
+ // #include <string.h>
+ // main()
+ // {
+ // static const char Base64[] =
+ // "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
+ // char *pos;
+ // int idx, i, j;
+ // printf(" ");
+ // for (i = 0; i < 255; i += 8) {
+ // for (j = i; j < i + 8; j++) {
+ // pos = strchr(Base64, j);
+ // if ((pos == NULL) || (j == 0))
+ // idx = -1;
+ // else
+ // idx = pos - Base64;
+ // if (idx == -1)
+ // printf(" %2d, ", idx);
+ // else
+ // printf(" %2d/*%c*/,", idx, j);
+ // }
+ // printf("\n ");
+ // }
+ // }
+
+ return Base64UnescapeInternal(src, szsrc, dest, szdest, UnBase64);
+}
+
+bool WebSafeBase64Unescape(const char *src, int slen, string* dest) {
+ int dest_len = 3 * (slen / 4) + (slen % 4);
+ dest->clear();
+ dest->resize(dest_len);
+ int len = WebSafeBase64Unescape(src, slen, &*dest->begin(), dest->size());
+ if (len < 0) {
+ dest->clear();
+ return false;
+ }
+ // could be shorter if there was padding
+ assert(len <= dest_len);
+ dest->resize(len);
+ return true;
+}
+
+bool WebSafeBase64Unescape(const string& src, string* dest) {
+ return WebSafeBase64Unescape(src.data(), src.size(), dest);
+}
+
+int WebSafeBase64Escape(const unsigned char *src, int szsrc, char *dest,
+ int szdest, bool do_padding) {
+ return Base64EscapeInternal(src, szsrc, dest, szdest,
+ kWebSafeBase64Chars, do_padding);
+}
+
+void WebSafeBase64Escape(const unsigned char *src, int szsrc,
+ string *dest, bool do_padding) {
+ const int max_escaped_size =
+ CalculateBase64EscapedLen(szsrc, do_padding);
+ dest->clear();
+ dest->resize(max_escaped_size + 1, '\0');
+ const int escaped_len = Base64EscapeInternal(src, szsrc,
+ &*dest->begin(), dest->size(),
+ kWebSafeBase64Chars,
+ do_padding);
+ assert(max_escaped_size <= escaped_len);
+ dest->resize(escaped_len);
+}
+
+void WebSafeBase64EscapeInternal(const string& src,
+ string* dest,
+ bool do_padding) {
+ int encoded_len = CalculateBase64EscapedLen(src.size());
+ scoped_array<char> buf(new char[encoded_len]);
+ int len = WebSafeBase64Escape(reinterpret_cast<const unsigned char*>(src.c_str()),
+ src.size(), buf.get(),
+ encoded_len, do_padding);
+ dest->assign(buf.get(), len);
+}
+
+void WebSafeBase64Escape(const string& src, string* dest) {
+ WebSafeBase64EscapeInternal(src, dest, false);
+}
+
+void WebSafeBase64EscapeWithPadding(const string& src, string* dest) {
+ WebSafeBase64EscapeInternal(src, dest, true);
+}
+
+} // namespace strings
diff --git a/src/tools/windows/converter_exe/escaping.h b/src/tools/windows/converter_exe/escaping.h
index c8aa90b7..bc36bf57 100644
--- a/src/tools/windows/converter_exe/escaping.h
+++ b/src/tools/windows/converter_exe/escaping.h
@@ -1,99 +1,99 @@
-// Copyright 2019 Google Inc. All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-//
-// Base64 escaping methods to encode/decode strings.
-
-#ifndef TOOLS_WINDOWS_CONVERTER_EXE_ESCAPING_H_
-#define TOOLS_WINDOWS_CONVERTER_EXE_ESCAPING_H_
-
-#include <string>
-
-namespace strings {
-
-using std::string;
-
-// ----------------------------------------------------------------------
-// Base64Escape()
-// WebSafeBase64Escape()
-// Encode "src" to "dest" using base64 encoding.
-// src is not null terminated, instead specify len.
-// 'dest' should have at least CalculateBase64EscapedLen() length.
-// RETURNS the length of dest.
-// The WebSafe variation use '-' instead of '+' and '_' instead of '/'
-// so that we can place the out in the URL or cookies without having
-// to escape them. It also has an extra parameter "do_padding",
-// which when set to false will prevent padding with "=".
-// ----------------------------------------------------------------------
-void Base64Escape(const string& src, string* dest);
-int Base64Escape(const unsigned char* src, int slen, char* dest, int szdest);
-// Encode src into dest with padding.
-void Base64Escape(const unsigned char* src, int szsrc,
- string* dest, bool do_padding);
-
-int WebSafeBase64Escape(const unsigned char* src, int slen, char* dest,
- int szdest, bool do_padding);
-// Encode src into dest web-safely without padding.
-void WebSafeBase64Escape(const string& src, string* dest);
-// Encode src into dest web-safely with padding.
-void WebSafeBase64EscapeWithPadding(const string& src, string* dest);
-void WebSafeBase64Escape(const unsigned char* src, int szsrc,
- string* dest, bool do_padding);
-
-// ----------------------------------------------------------------------
-// Base64Unescape()
-// WebSafeBase64Unescape()
-// Copies "src" to "dest", where src is in base64 and is written to its
-// ASCII equivalents. src is not null terminated, instead specify len.
-// I recommend that slen<szdest, but we honor szdest anyway.
-// RETURNS the length of dest, or -1 if src contains invalid chars.
-// The WebSafe variation use '-' instead of '+' and '_' instead of '/'.
-// The variations that store into a string clear the string first, and
-// return false (with dest empty) if src contains invalid chars; for
-// these versions src and dest must be different strings.
-// ----------------------------------------------------------------------
-int Base64Unescape(const char* src, int slen, char* dest, int szdest);
-bool Base64Unescape(const char* src, int slen, string* dest);
-inline bool Base64Unescape(const string& src, string* dest) {
- return Base64Unescape(src.data(), src.size(), dest);
-}
-
-
-int WebSafeBase64Unescape(const char* src, int slen, char* dest, int szdest);
-bool WebSafeBase64Unescape(const char* src, int slen, string* dest);
-bool WebSafeBase64Unescape(const string& src, string* dest);
-
-// Return the length to use for the output buffer given to the base64 escape
-// routines. Make sure to use the same value for do_padding in both.
-// This function may return incorrect results if given input_len values that
-// are extremely high, which should happen rarely.
-int CalculateBase64EscapedLen(int input_len, bool do_padding);
-// Use this version when calling Base64Escape without a do_padding arg.
-int CalculateBase64EscapedLen(int input_len);
-} // namespace strings
-
-#endif // TOOLS_WINDOWS_CONVERTER_EXE_ESCAPING_H_
+// Copyright 2019 Google LLC
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google LLC nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Base64 escaping methods to encode/decode strings.
+
+#ifndef TOOLS_WINDOWS_CONVERTER_EXE_ESCAPING_H_
+#define TOOLS_WINDOWS_CONVERTER_EXE_ESCAPING_H_
+
+#include <string>
+
+namespace strings {
+
+using std::string;
+
+// ----------------------------------------------------------------------
+// Base64Escape()
+// WebSafeBase64Escape()
+// Encode "src" to "dest" using base64 encoding.
+// src is not null terminated, instead specify len.
+// 'dest' should have at least CalculateBase64EscapedLen() length.
+// RETURNS the length of dest.
+// The WebSafe variation use '-' instead of '+' and '_' instead of '/'
+// so that we can place the out in the URL or cookies without having
+// to escape them. It also has an extra parameter "do_padding",
+// which when set to false will prevent padding with "=".
+// ----------------------------------------------------------------------
+void Base64Escape(const string& src, string* dest);
+int Base64Escape(const unsigned char* src, int slen, char* dest, int szdest);
+// Encode src into dest with padding.
+void Base64Escape(const unsigned char* src, int szsrc,
+ string* dest, bool do_padding);
+
+int WebSafeBase64Escape(const unsigned char* src, int slen, char* dest,
+ int szdest, bool do_padding);
+// Encode src into dest web-safely without padding.
+void WebSafeBase64Escape(const string& src, string* dest);
+// Encode src into dest web-safely with padding.
+void WebSafeBase64EscapeWithPadding(const string& src, string* dest);
+void WebSafeBase64Escape(const unsigned char* src, int szsrc,
+ string* dest, bool do_padding);
+
+// ----------------------------------------------------------------------
+// Base64Unescape()
+// WebSafeBase64Unescape()
+// Copies "src" to "dest", where src is in base64 and is written to its
+// ASCII equivalents. src is not null terminated, instead specify len.
+// I recommend that slen<szdest, but we honor szdest anyway.
+// RETURNS the length of dest, or -1 if src contains invalid chars.
+// The WebSafe variation use '-' instead of '+' and '_' instead of '/'.
+// The variations that store into a string clear the string first, and
+// return false (with dest empty) if src contains invalid chars; for
+// these versions src and dest must be different strings.
+// ----------------------------------------------------------------------
+int Base64Unescape(const char* src, int slen, char* dest, int szdest);
+bool Base64Unescape(const char* src, int slen, string* dest);
+inline bool Base64Unescape(const string& src, string* dest) {
+ return Base64Unescape(src.data(), src.size(), dest);
+}
+
+
+int WebSafeBase64Unescape(const char* src, int slen, char* dest, int szdest);
+bool WebSafeBase64Unescape(const char* src, int slen, string* dest);
+bool WebSafeBase64Unescape(const string& src, string* dest);
+
+// Return the length to use for the output buffer given to the base64 escape
+// routines. Make sure to use the same value for do_padding in both.
+// This function may return incorrect results if given input_len values that
+// are extremely high, which should happen rarely.
+int CalculateBase64EscapedLen(int input_len, bool do_padding);
+// Use this version when calling Base64Escape without a do_padding arg.
+int CalculateBase64EscapedLen(int input_len);
+} // namespace strings
+
+#endif // TOOLS_WINDOWS_CONVERTER_EXE_ESCAPING_H_
diff --git a/src/tools/windows/converter_exe/http_client.h b/src/tools/windows/converter_exe/http_client.h
index 3e7aa8a7..38ebf2e4 100644
--- a/src/tools/windows/converter_exe/http_client.h
+++ b/src/tools/windows/converter_exe/http_client.h
@@ -1,96 +1,96 @@
-// Copyright 2019 Google Inc. All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-#ifndef TOOLS_CRASH_CONVERTER_WINDOWS_HTTP_CLIENT_H_
-#define TOOLS_CRASH_CONVERTER_WINDOWS_HTTP_CLIENT_H_
-
-#include <tchar.h>
-#include <windows.h>
-#include <vector>
-
-typedef void* HttpHandle;
-
-namespace crash {
-
-// HttpClient provides an abstract layer for HTTP APIs. The actual
-// implementation can be based on either WinHttp or WinInet.
-class HttpClient {
- public:
- enum AccessType {
- ACCESS_TYPE_PRECONFIG,
- ACCESS_TYPE_DIRECT,
- ACCESS_TYPE_PROXY,
- };
-
- virtual ~HttpClient() {}
-
- virtual bool CrackUrl(const TCHAR* url,
- DWORD flags,
- TCHAR* scheme,
- size_t scheme_buffer_length,
- TCHAR* host,
- size_t host_buffer_length,
- TCHAR* uri,
- size_t uri_buffer_length,
- int* port) const = 0;
- virtual bool Open(const TCHAR* user_agent,
- DWORD access_type,
- const TCHAR* proxy_name,
- const TCHAR* proxy_bypass,
- HttpHandle* session_handle) const = 0;
- virtual bool Connect(HttpHandle session_handle,
- const TCHAR* server,
- int port,
- HttpHandle* connection_handle) const = 0;
- virtual bool OpenRequest(HttpHandle connection_handle,
- const TCHAR* verb,
- const TCHAR* uri,
- const TCHAR* version,
- const TCHAR* referrer,
- bool is_secure,
- HttpHandle* request_handle) const = 0;
- virtual bool SendRequest(HttpHandle request_handle,
- const TCHAR* headers,
- DWORD headers_length) const = 0;
- virtual bool ReceiveResponse(HttpHandle request_handle) const = 0;
- virtual bool GetHttpStatusCode(HttpHandle request_handle,
- int* status_code) const = 0;
- virtual bool GetContentLength(HttpHandle request_handle,
- DWORD* content_length) const = 0;
- virtual bool ReadData(HttpHandle request_handle,
- void* buffer,
- DWORD buffer_length,
- DWORD* bytes_read) const = 0;
- virtual bool Close(HttpHandle handle) const = 0;
-
- static const DWORD kUnknownContentLength = (DWORD)-1;
-};
-
-} // namespace crash
-
-#endif // TOOLS_CRASH_CONVERTER_WINDOWS_HTTP_CLIENT_H_
+// Copyright 2019 Google LLC
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google LLC nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef TOOLS_CRASH_CONVERTER_WINDOWS_HTTP_CLIENT_H_
+#define TOOLS_CRASH_CONVERTER_WINDOWS_HTTP_CLIENT_H_
+
+#include <tchar.h>
+#include <windows.h>
+#include <vector>
+
+typedef void* HttpHandle;
+
+namespace crash {
+
+// HttpClient provides an abstract layer for HTTP APIs. The actual
+// implementation can be based on either WinHttp or WinInet.
+class HttpClient {
+ public:
+ enum AccessType {
+ ACCESS_TYPE_PRECONFIG,
+ ACCESS_TYPE_DIRECT,
+ ACCESS_TYPE_PROXY,
+ };
+
+ virtual ~HttpClient() {}
+
+ virtual bool CrackUrl(const TCHAR* url,
+ DWORD flags,
+ TCHAR* scheme,
+ size_t scheme_buffer_length,
+ TCHAR* host,
+ size_t host_buffer_length,
+ TCHAR* uri,
+ size_t uri_buffer_length,
+ int* port) const = 0;
+ virtual bool Open(const TCHAR* user_agent,
+ DWORD access_type,
+ const TCHAR* proxy_name,
+ const TCHAR* proxy_bypass,
+ HttpHandle* session_handle) const = 0;
+ virtual bool Connect(HttpHandle session_handle,
+ const TCHAR* server,
+ int port,
+ HttpHandle* connection_handle) const = 0;
+ virtual bool OpenRequest(HttpHandle connection_handle,
+ const TCHAR* verb,
+ const TCHAR* uri,
+ const TCHAR* version,
+ const TCHAR* referrer,
+ bool is_secure,
+ HttpHandle* request_handle) const = 0;
+ virtual bool SendRequest(HttpHandle request_handle,
+ const TCHAR* headers,
+ DWORD headers_length) const = 0;
+ virtual bool ReceiveResponse(HttpHandle request_handle) const = 0;
+ virtual bool GetHttpStatusCode(HttpHandle request_handle,
+ int* status_code) const = 0;
+ virtual bool GetContentLength(HttpHandle request_handle,
+ DWORD* content_length) const = 0;
+ virtual bool ReadData(HttpHandle request_handle,
+ void* buffer,
+ DWORD buffer_length,
+ DWORD* bytes_read) const = 0;
+ virtual bool Close(HttpHandle handle) const = 0;
+
+ static const DWORD kUnknownContentLength = (DWORD)-1;
+};
+
+} // namespace crash
+
+#endif // TOOLS_CRASH_CONVERTER_WINDOWS_HTTP_CLIENT_H_
diff --git a/src/tools/windows/converter_exe/http_download.cc b/src/tools/windows/converter_exe/http_download.cc
index 5afc1ccc..75f674e0 100644
--- a/src/tools/windows/converter_exe/http_download.cc
+++ b/src/tools/windows/converter_exe/http_download.cc
@@ -1,326 +1,326 @@
-// Copyright 2019 Google Inc. All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-#include <assert.h>
-#include <stdio.h>
-#include <Windows.h>
-#include <WinInet.h>
-
-#include <vector>
-
-#include "tools/windows/converter_exe/http_download.h"
-#include "tools/windows/converter_exe/winhttp_client.h"
-#include "tools/windows/converter_exe/wininet_client.h"
-
-namespace crash {
-static const std::vector<char>::size_type kVectorChunkSize = 4096; // 4 KB
-
-using std::vector;
-
-// Class that atuo closes the contained HttpHandle when the object
-// goes out of scope.
-class AutoHttpHandle {
- public:
- AutoHttpHandle() : handle_(NULL) {}
- explicit AutoHttpHandle(HttpHandle handle) : handle_(handle) {}
- ~AutoHttpHandle() {
- if (handle_) {
- InternetCloseHandle(handle_);
- }
- }
-
- HttpHandle get() { return handle_; }
- HttpHandle* get_handle_addr () { return &handle_; }
-
- private:
- HttpHandle handle_;
-};
-
-// Template class for auto releasing the contained pointer when
-// the object goes out of scope.
-template<typename T>
-class AutoPtr {
- public:
- explicit AutoPtr(T* ptr) : ptr_(ptr) {}
- ~AutoPtr() {
- if (ptr_) {
- delete ptr_;
- }
- }
-
- T* get() { return ptr_; }
- T* operator -> () { return ptr_; }
-
- private:
- T* ptr_;
-};
-
-// CheckParameters ensures that the parameters in |parameters| are safe for
-// use in an HTTP URL. Returns true if they are, false if unsafe characters
-// are present.
-static bool CheckParameters(const map<wstring, wstring> *parameters) {
- for (map<wstring, wstring>::const_iterator iterator = parameters->begin();
- iterator != parameters->end();
- ++iterator) {
- const wstring &key = iterator->first;
- if (key.empty()) {
- // Disallow empty parameter names.
- return false;
- }
- for (unsigned int i = 0; i < key.size(); ++i) {
- wchar_t c = key[i];
- if (c < 32 || c == '"' || c == '?' || c == '&' || c > 127) {
- return false;
- }
- }
-
- const wstring &value = iterator->second;
- for (unsigned int i = 0; i < value.size(); ++i) {
- wchar_t c = value[i];
- if (c < 32 || c == '"' || c == '?' || c == '&' || c > 127) {
- return false;
- }
- }
- }
-
- return true;
-}
-
-HttpClient* HTTPDownload::CreateHttpClient(const wchar_t* url) {
- const TCHAR* kHttpApiPolicyEnvironmentVariable = TEXT("USE_WINHTTP");
- TCHAR buffer[2] = {0};
- HttpClient* http_client = NULL;
-
- if (::GetEnvironmentVariable(kHttpApiPolicyEnvironmentVariable,
- buffer,
- sizeof(buffer)/sizeof(buffer[0])) > 0) {
- fprintf(stdout,
- "Environment variable [%ws] is set, use WinHttp\n",
- kHttpApiPolicyEnvironmentVariable);
- http_client = CreateWinHttpClient(url);
- if (http_client == NULL) {
- fprintf(stderr, "WinHttpClient not created, Is the protocol HTTPS? "
- "Fall back to WinInet API.\n");
- }
- } else {
- fprintf(stderr,
- "Environment variable [%ws] is NOT set, use WinInet API\n",
- kHttpApiPolicyEnvironmentVariable);
- }
-
- if (http_client == NULL) {
- return CreateWinInetClient(url);
- }
-
- return http_client;
-}
-
-// static
-bool HTTPDownload::Download(const wstring &url,
- const map<wstring, wstring> *parameters,
- string *content, int *status_code) {
- assert(content);
- AutoPtr<HttpClient> http_client(CreateHttpClient(url.c_str()));
-
- if (!http_client.get()) {
- fprintf(stderr, "Failed to create any http client.\n");
- return false;
- }
-
- if (status_code) {
- *status_code = 0;
- }
-
- wchar_t scheme[16] = {0};
- wchar_t host[256] = {0};
- wchar_t path[256] = {0};
- int port = 0;
- if (!http_client->CrackUrl(url.c_str(),
- 0,
- scheme,
- sizeof(scheme)/sizeof(scheme[0]),
- host,
- sizeof(host)/sizeof(host[0]),
- path,
- sizeof(path)/sizeof(path[0]),
- &port)) {
- fprintf(stderr,
- "HTTPDownload::Download: InternetCrackUrl: error %lu for %ws\n",
- GetLastError(), url.c_str());
- return false;
- }
-
- bool secure = false;
- if (_wcsicmp(scheme, L"https") == 0) {
- secure = true;
- } else if (wcscmp(scheme, L"http") != 0) {
- fprintf(stderr,
- "HTTPDownload::Download: scheme must be http or https for %ws\n",
- url.c_str());
- return false;
- }
-
- AutoHttpHandle internet;
- if (!http_client->Open(NULL, // user agent
- HttpClient::ACCESS_TYPE_PRECONFIG,
- NULL, // proxy name
- NULL, // proxy bypass
- internet.get_handle_addr())) {
- fprintf(stderr,
- "HTTPDownload::Download: Open: error %lu for %ws\n",
- GetLastError(), url.c_str());
- return false;
- }
-
- AutoHttpHandle connection;
- if (!http_client->Connect(internet.get(),
- host,
- port,
- connection.get_handle_addr())) {
- fprintf(stderr,
- "HTTPDownload::Download: InternetConnect: error %lu for %ws\n",
- GetLastError(), url.c_str());
- return false;
- }
-
- wstring request_string = path;
- if (parameters) {
- // TODO(mmentovai): escape bad characters in parameters instead of
- // forbidding them.
- if (!CheckParameters(parameters)) {
- fprintf(stderr,
- "HTTPDownload::Download: invalid characters in parameters\n");
- return false;
- }
-
- bool added_parameter = false;
- for (map<wstring, wstring>::const_iterator iterator = parameters->begin();
- iterator != parameters->end();
- ++iterator) {
- request_string.append(added_parameter ? L"&" : L"?");
- request_string.append(iterator->first);
- request_string.append(L"=");
- request_string.append(iterator->second);
- added_parameter = true;
- }
- }
-
- AutoHttpHandle request;
- if (!http_client->OpenRequest(connection.get(),
- L"GET",
- request_string.c_str(),
- NULL, // version
- NULL, // referer
- secure,
- request.get_handle_addr())) {
- fprintf(stderr,
- "HttpClient::OpenRequest: error %lu for %ws, request: %ws\n",
- GetLastError(), url.c_str(), request_string.c_str());
- return false;
- }
-
- if (!http_client->SendRequest(request.get(), NULL, 0)) {
- fprintf(stderr,
- "HttpClient::SendRequest: error %lu for %ws\n",
- GetLastError(), url.c_str());
- return false;
- }
-
- if (!http_client->ReceiveResponse(request.get())) {
- fprintf(stderr,
- "HttpClient::ReceiveResponse: error %lu for %ws\n",
- GetLastError(), url.c_str());
- return false;
- }
-
- int http_status = 0;
- if (!http_client->GetHttpStatusCode(request.get(), &http_status)) {
- fprintf(stderr,
- "HttpClient::GetHttpStatusCode: error %lu for %ws\n",
- GetLastError(), url.c_str());
- return false;
- }
- if (http_status != 200) {
- fprintf(stderr,
- "HTTPDownload::Download: HTTP status code %d for %ws\n",
- http_status, url.c_str());
- return false;
- }
-
- DWORD content_length = 0;
- vector<char>::size_type buffer_size = 0;
- http_client->GetContentLength(request.get(), &content_length);
- if (content_length == HttpClient::kUnknownContentLength) {
- buffer_size = kVectorChunkSize;
- } else {
- buffer_size = content_length;
- }
-
- if (content_length != 0) {
- vector<char> response_buffer = vector<char>(buffer_size+1);
- DWORD size_read;
- DWORD total_read = 0;
- bool read_result;
- do {
- if (content_length == HttpClient::kUnknownContentLength
- && buffer_size == total_read) {
- // The content length wasn't specified in the response header, so we
- // have to keep growing the buffer until we're done reading.
- buffer_size += kVectorChunkSize;
- response_buffer.resize(buffer_size);
- }
- read_result = !!http_client->ReadData(
- request.get(),
- &response_buffer[total_read],
- static_cast<DWORD>(buffer_size) - total_read,
- &size_read);
- total_read += size_read;
- } while (read_result && (size_read != 0));
-
- if (!read_result) {
- fprintf(stderr,
- "HttpClient::ReadData: error %lu for %ws\n",
- GetLastError(),
- url.c_str());
- return false;
- } else if (size_read != 0) {
- fprintf(stderr,
- "HttpClient::ReadData: error %lu/%lu for %ws\n",
- total_read,
- content_length,
- url.c_str());
- return false;
- }
- content->assign(&response_buffer[0], total_read);
- } else {
- content->clear();
- }
- return true;
-}
-
-} // namespace crash
+// Copyright 2019 Google LLC
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google LLC nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <assert.h>
+#include <stdio.h>
+#include <Windows.h>
+#include <WinInet.h>
+
+#include <vector>
+
+#include "tools/windows/converter_exe/http_download.h"
+#include "tools/windows/converter_exe/winhttp_client.h"
+#include "tools/windows/converter_exe/wininet_client.h"
+
+namespace crash {
+static const std::vector<char>::size_type kVectorChunkSize = 4096; // 4 KB
+
+using std::vector;
+
+// Class that atuo closes the contained HttpHandle when the object
+// goes out of scope.
+class AutoHttpHandle {
+ public:
+ AutoHttpHandle() : handle_(NULL) {}
+ explicit AutoHttpHandle(HttpHandle handle) : handle_(handle) {}
+ ~AutoHttpHandle() {
+ if (handle_) {
+ InternetCloseHandle(handle_);
+ }
+ }
+
+ HttpHandle get() { return handle_; }
+ HttpHandle* get_handle_addr () { return &handle_; }
+
+ private:
+ HttpHandle handle_;
+};
+
+// Template class for auto releasing the contained pointer when
+// the object goes out of scope.
+template<typename T>
+class AutoPtr {
+ public:
+ explicit AutoPtr(T* ptr) : ptr_(ptr) {}
+ ~AutoPtr() {
+ if (ptr_) {
+ delete ptr_;
+ }
+ }
+
+ T* get() { return ptr_; }
+ T* operator -> () { return ptr_; }
+
+ private:
+ T* ptr_;
+};
+
+// CheckParameters ensures that the parameters in |parameters| are safe for
+// use in an HTTP URL. Returns true if they are, false if unsafe characters
+// are present.
+static bool CheckParameters(const map<wstring, wstring>* parameters) {
+ for (map<wstring, wstring>::const_iterator iterator = parameters->begin();
+ iterator != parameters->end();
+ ++iterator) {
+ const wstring& key = iterator->first;
+ if (key.empty()) {
+ // Disallow empty parameter names.
+ return false;
+ }
+ for (unsigned int i = 0; i < key.size(); ++i) {
+ wchar_t c = key[i];
+ if (c < 32 || c == '"' || c == '?' || c == '&' || c > 127) {
+ return false;
+ }
+ }
+
+ const wstring& value = iterator->second;
+ for (unsigned int i = 0; i < value.size(); ++i) {
+ wchar_t c = value[i];
+ if (c < 32 || c == '"' || c == '?' || c == '&' || c > 127) {
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+HttpClient* HTTPDownload::CreateHttpClient(const wchar_t* url) {
+ const TCHAR* kHttpApiPolicyEnvironmentVariable = TEXT("USE_WINHTTP");
+ TCHAR buffer[2] = {0};
+ HttpClient* http_client = NULL;
+
+ if (::GetEnvironmentVariable(kHttpApiPolicyEnvironmentVariable,
+ buffer,
+ sizeof(buffer)/sizeof(buffer[0])) > 0) {
+ fprintf(stdout,
+ "Environment variable [%ws] is set, use WinHttp\n",
+ kHttpApiPolicyEnvironmentVariable);
+ http_client = CreateWinHttpClient(url);
+ if (http_client == NULL) {
+ fprintf(stderr, "WinHttpClient not created, Is the protocol HTTPS? "
+ "Fall back to WinInet API.\n");
+ }
+ } else {
+ fprintf(stderr,
+ "Environment variable [%ws] is NOT set, use WinInet API\n",
+ kHttpApiPolicyEnvironmentVariable);
+ }
+
+ if (http_client == NULL) {
+ return CreateWinInetClient(url);
+ }
+
+ return http_client;
+}
+
+// static
+bool HTTPDownload::Download(const wstring& url,
+ const map<wstring, wstring>* parameters,
+ string *content, int *status_code) {
+ assert(content);
+ AutoPtr<HttpClient> http_client(CreateHttpClient(url.c_str()));
+
+ if (!http_client.get()) {
+ fprintf(stderr, "Failed to create any http client.\n");
+ return false;
+ }
+
+ if (status_code) {
+ *status_code = 0;
+ }
+
+ wchar_t scheme[16] = {0};
+ wchar_t host[256] = {0};
+ wchar_t path[256] = {0};
+ int port = 0;
+ if (!http_client->CrackUrl(url.c_str(),
+ 0,
+ scheme,
+ sizeof(scheme)/sizeof(scheme[0]),
+ host,
+ sizeof(host)/sizeof(host[0]),
+ path,
+ sizeof(path)/sizeof(path[0]),
+ &port)) {
+ fprintf(stderr,
+ "HTTPDownload::Download: InternetCrackUrl: error %lu for %ws\n",
+ GetLastError(), url.c_str());
+ return false;
+ }
+
+ bool secure = false;
+ if (_wcsicmp(scheme, L"https") == 0) {
+ secure = true;
+ } else if (wcscmp(scheme, L"http") != 0) {
+ fprintf(stderr,
+ "HTTPDownload::Download: scheme must be http or https for %ws\n",
+ url.c_str());
+ return false;
+ }
+
+ AutoHttpHandle internet;
+ if (!http_client->Open(NULL, // user agent
+ HttpClient::ACCESS_TYPE_PRECONFIG,
+ NULL, // proxy name
+ NULL, // proxy bypass
+ internet.get_handle_addr())) {
+ fprintf(stderr,
+ "HTTPDownload::Download: Open: error %lu for %ws\n",
+ GetLastError(), url.c_str());
+ return false;
+ }
+
+ AutoHttpHandle connection;
+ if (!http_client->Connect(internet.get(),
+ host,
+ port,
+ connection.get_handle_addr())) {
+ fprintf(stderr,
+ "HTTPDownload::Download: InternetConnect: error %lu for %ws\n",
+ GetLastError(), url.c_str());
+ return false;
+ }
+
+ wstring request_string = path;
+ if (parameters) {
+ // TODO(mmentovai): escape bad characters in parameters instead of
+ // forbidding them.
+ if (!CheckParameters(parameters)) {
+ fprintf(stderr,
+ "HTTPDownload::Download: invalid characters in parameters\n");
+ return false;
+ }
+
+ bool added_parameter = false;
+ for (map<wstring, wstring>::const_iterator iterator = parameters->begin();
+ iterator != parameters->end();
+ ++iterator) {
+ request_string.append(added_parameter ? L"&" : L"?");
+ request_string.append(iterator->first);
+ request_string.append(L"=");
+ request_string.append(iterator->second);
+ added_parameter = true;
+ }
+ }
+
+ AutoHttpHandle request;
+ if (!http_client->OpenRequest(connection.get(),
+ L"GET",
+ request_string.c_str(),
+ NULL, // version
+ NULL, // referer
+ secure,
+ request.get_handle_addr())) {
+ fprintf(stderr,
+ "HttpClient::OpenRequest: error %lu for %ws, request: %ws\n",
+ GetLastError(), url.c_str(), request_string.c_str());
+ return false;
+ }
+
+ if (!http_client->SendRequest(request.get(), NULL, 0)) {
+ fprintf(stderr,
+ "HttpClient::SendRequest: error %lu for %ws\n",
+ GetLastError(), url.c_str());
+ return false;
+ }
+
+ if (!http_client->ReceiveResponse(request.get())) {
+ fprintf(stderr,
+ "HttpClient::ReceiveResponse: error %lu for %ws\n",
+ GetLastError(), url.c_str());
+ return false;
+ }
+
+ int http_status = 0;
+ if (!http_client->GetHttpStatusCode(request.get(), &http_status)) {
+ fprintf(stderr,
+ "HttpClient::GetHttpStatusCode: error %lu for %ws\n",
+ GetLastError(), url.c_str());
+ return false;
+ }
+ if (http_status != 200) {
+ fprintf(stderr,
+ "HTTPDownload::Download: HTTP status code %d for %ws\n",
+ http_status, url.c_str());
+ return false;
+ }
+
+ DWORD content_length = 0;
+ vector<char>::size_type buffer_size = 0;
+ http_client->GetContentLength(request.get(), &content_length);
+ if (content_length == HttpClient::kUnknownContentLength) {
+ buffer_size = kVectorChunkSize;
+ } else {
+ buffer_size = content_length;
+ }
+
+ if (content_length != 0) {
+ vector<char> response_buffer = vector<char>(buffer_size+1);
+ DWORD size_read;
+ DWORD total_read = 0;
+ bool read_result;
+ do {
+ if (content_length == HttpClient::kUnknownContentLength
+ && buffer_size == total_read) {
+ // The content length wasn't specified in the response header, so we
+ // have to keep growing the buffer until we're done reading.
+ buffer_size += kVectorChunkSize;
+ response_buffer.resize(buffer_size);
+ }
+ read_result = !!http_client->ReadData(
+ request.get(),
+ &response_buffer[total_read],
+ static_cast<DWORD>(buffer_size) - total_read,
+ &size_read);
+ total_read += size_read;
+ } while (read_result && (size_read != 0));
+
+ if (!read_result) {
+ fprintf(stderr,
+ "HttpClient::ReadData: error %lu for %ws\n",
+ GetLastError(),
+ url.c_str());
+ return false;
+ } else if (size_read != 0) {
+ fprintf(stderr,
+ "HttpClient::ReadData: error %lu/%lu for %ws\n",
+ total_read,
+ content_length,
+ url.c_str());
+ return false;
+ }
+ content->assign(&response_buffer[0], total_read);
+ } else {
+ content->clear();
+ }
+ return true;
+}
+
+} // namespace crash
diff --git a/src/tools/windows/converter_exe/http_download.h b/src/tools/windows/converter_exe/http_download.h
index 2d705d5e..f58a3d0f 100644
--- a/src/tools/windows/converter_exe/http_download.h
+++ b/src/tools/windows/converter_exe/http_download.h
@@ -1,62 +1,62 @@
-// Copyright 2019 Google Inc. All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-#ifndef TOOLS_WINDOWS_CONVERTER_EXE_HTTP_DOWNLOAD_H_
-#define TOOLS_WINDOWS_CONVERTER_EXE_HTTP_DOWNLOAD_H_
-
-#include <map>
-#include <string>
-#include "tools/windows/converter_exe/winhttp_client.h"
-
-namespace crash {
-
-using std::map;
-using std::string;
-using std::wstring;
-
-class HTTPDownload {
- public:
- // Retrieves the resource located at |url|, a http or https URL, via WinInet.
- // The request is fetched with GET request; the optional |parameters| are
- // appended to the URL. Returns true on success, placing the content of the
- // retrieved resource in |content|. Returns false on failure. HTTP status
- // codes other than 200 cause Download to return false. If |status_code| is
- // supplied, it will be set to the value of the HTTP status code, if an HTTP
- // transaction occurs. If Download fails before a transaction can occur,
- // |status_code| will be set to 0. Any failures will result in messages
- // being printed to stderr.
- static bool Download(const wstring &url,
- const map<wstring, wstring> *parameters,
- string *content, int *status_code);
- private:
- static HttpClient* CreateHttpClient(const wchar_t*);
-};
-
-} // namespace crash
-
-#endif // TOOLS_WINDOWS_CONVERTER_EXE_HTTP_DOWNLOAD_H_
+// Copyright 2019 Google LLC
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google LLC nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef TOOLS_WINDOWS_CONVERTER_EXE_HTTP_DOWNLOAD_H_
+#define TOOLS_WINDOWS_CONVERTER_EXE_HTTP_DOWNLOAD_H_
+
+#include <map>
+#include <string>
+#include "tools/windows/converter_exe/winhttp_client.h"
+
+namespace crash {
+
+using std::map;
+using std::string;
+using std::wstring;
+
+class HTTPDownload {
+ public:
+ // Retrieves the resource located at |url|, a http or https URL, via WinInet.
+ // The request is fetched with GET request; the optional |parameters| are
+ // appended to the URL. Returns true on success, placing the content of the
+ // retrieved resource in |content|. Returns false on failure. HTTP status
+ // codes other than 200 cause Download to return false. If |status_code| is
+ // supplied, it will be set to the value of the HTTP status code, if an HTTP
+ // transaction occurs. If Download fails before a transaction can occur,
+ // |status_code| will be set to 0. Any failures will result in messages
+ // being printed to stderr.
+ static bool Download(const wstring& url,
+ const map<wstring, wstring>* parameters,
+ string *content, int *status_code);
+ private:
+ static HttpClient* CreateHttpClient(const wchar_t*);
+};
+
+} // namespace crash
+
+#endif // TOOLS_WINDOWS_CONVERTER_EXE_HTTP_DOWNLOAD_H_
diff --git a/src/tools/windows/converter_exe/tokenizer.cc b/src/tools/windows/converter_exe/tokenizer.cc
index 992694cd..6d627536 100644
--- a/src/tools/windows/converter_exe/tokenizer.cc
+++ b/src/tools/windows/converter_exe/tokenizer.cc
@@ -1,61 +1,61 @@
-// Copyright 2019 Google Inc. All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-#include <assert.h>
-
-#include "tools/windows/converter_exe/tokenizer.h"
-
-namespace crash {
-
-// static
-void Tokenizer::Tokenize(const string &delimiters, const string &input,
- vector<string> *output) {
- assert(output);
- output->clear();
-
- string::size_type position = 0; // Where to begin looking for a delimiter
- string::size_type new_position; // Position of found delimiter
- string token;
-
- while ((new_position = input.find_first_of(delimiters, position)) !=
- string::npos) {
- token = input.substr(position, new_position - position);
- output->push_back(token);
-
- // Next time, begin looking right after this delimiter.
- position = new_position + 1;
- }
-
- // There are no more delimiters in the string. Take everything from the
- // final delimiter up to the end of the string as a token. This may be
- // an empty string.
- token = input.substr(position);
- output->push_back(token);
-}
-
-} // namespace crash
+// Copyright 2019 Google LLC
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google LLC nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <assert.h>
+
+#include "tools/windows/converter_exe/tokenizer.h"
+
+namespace crash {
+
+// static
+void Tokenizer::Tokenize(const string& delimiters, const string& input,
+ vector<string>* output) {
+ assert(output);
+ output->clear();
+
+ string::size_type position = 0; // Where to begin looking for a delimiter
+ string::size_type new_position; // Position of found delimiter
+ string token;
+
+ while ((new_position = input.find_first_of(delimiters, position)) !=
+ string::npos) {
+ token = input.substr(position, new_position - position);
+ output->push_back(token);
+
+ // Next time, begin looking right after this delimiter.
+ position = new_position + 1;
+ }
+
+ // There are no more delimiters in the string. Take everything from the
+ // final delimiter up to the end of the string as a token. This may be
+ // an empty string.
+ token = input.substr(position);
+ output->push_back(token);
+}
+
+} // namespace crash
diff --git a/src/tools/windows/converter_exe/tokenizer.h b/src/tools/windows/converter_exe/tokenizer.h
index f4bbcfd0..d9829f60 100644
--- a/src/tools/windows/converter_exe/tokenizer.h
+++ b/src/tools/windows/converter_exe/tokenizer.h
@@ -1,51 +1,51 @@
-// Copyright 2019 Google Inc. All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-#ifndef TOOLS_WINDOWS_CONVERTER_EXE_TOKENIZER_H_
-#define TOOLS_WINDOWS_CONVERTER_EXE_TOKENIZER_H_
-
-#include <string>
-#include <vector>
-
-namespace crash {
-
-using std::string;
-using std::vector;
-
-class Tokenizer {
- public:
- // Splits |input| into a series of tokens delimited in the input string by
- // any of the characters in |delimiters|. The tokens are passed back in the
- // |output| vector.
- static void Tokenize(const string &delimiters, const string &input,
- vector<string> *output);
-};
-
-} // namespace crash
-
-#endif // TOOLS_WINDOWS_CONVERTER_EXE_TOKENIZER_H_
+// Copyright 2019 Google LLC
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google LLC nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef TOOLS_WINDOWS_CONVERTER_EXE_TOKENIZER_H_
+#define TOOLS_WINDOWS_CONVERTER_EXE_TOKENIZER_H_
+
+#include <string>
+#include <vector>
+
+namespace crash {
+
+using std::string;
+using std::vector;
+
+class Tokenizer {
+ public:
+ // Splits |input| into a series of tokens delimited in the input string by
+ // any of the characters in |delimiters|. The tokens are passed back in the
+ // |output| vector.
+ static void Tokenize(const string& delimiters, const string& input,
+ vector<string>* output);
+};
+
+} // namespace crash
+
+#endif // TOOLS_WINDOWS_CONVERTER_EXE_TOKENIZER_H_
diff --git a/src/tools/windows/converter_exe/winhttp_client.cc b/src/tools/windows/converter_exe/winhttp_client.cc
index 8a8ade3b..f8c1492d 100644
--- a/src/tools/windows/converter_exe/winhttp_client.cc
+++ b/src/tools/windows/converter_exe/winhttp_client.cc
@@ -1,307 +1,307 @@
-// Copyright 2019 Google Inc. All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-#include "tools/windows/converter_exe/winhttp_client.h"
-
-#include <assert.h>
-#include <stdlib.h>
-#include <windows.h>
-#include <winhttp.h>
-#include <vector>
-
-namespace crash {
-
-namespace internal {
-
-// This class implements HttpClient based on WinInet APIs.
-class WinHttpClient : public HttpClient {
- public:
- virtual ~WinHttpClient() {}
- virtual bool CrackUrl(const TCHAR* url,
- DWORD flags,
- TCHAR* scheme,
- size_t scheme_buffer_length,
- TCHAR* host,
- size_t host_buffer_length,
- TCHAR* uri,
- size_t uri_buffer_length,
- int* port) const;
- virtual bool Open(const TCHAR* user_agent,
- DWORD access_type,
- const TCHAR* proxy_name,
- const TCHAR* proxy_bypass,
- HttpHandle* session_handle) const;
- virtual bool Connect(HttpHandle session_handle,
- const TCHAR* server,
- int port,
- HttpHandle* connection_handle) const;
- virtual bool OpenRequest(HttpHandle connection_handle,
- const TCHAR* verb,
- const TCHAR* uri,
- const TCHAR* version,
- const TCHAR* referrer,
- bool is_secure,
- HttpHandle* request_handle) const;
- virtual bool SendRequest(HttpHandle request_handle,
- const TCHAR* headers,
- DWORD headers_length) const;
- virtual bool ReceiveResponse(HttpHandle request_handle) const;
- virtual bool GetHttpStatusCode(HttpHandle request_handle,
- int* status_code) const;
- virtual bool GetContentLength(HttpHandle request_handle,
- DWORD* content_length) const;
- virtual bool ReadData(HttpHandle request_handle,
- void* buffer,
- DWORD buffer_length,
- DWORD* bytes_read) const;
- virtual bool Close(HttpHandle handle) const;
-
- private:
- static DWORD MapAccessType(DWORD access_type);
- static HINTERNET ToHINTERNET(HttpHandle handle);
- static HttpHandle FromHINTERNET(HINTERNET handle);
-};
-
-bool WinHttpClient::CrackUrl(const TCHAR* url,
- DWORD flags,
- TCHAR* scheme,
- size_t scheme_buffer_length,
- TCHAR* host,
- size_t host_buffer_length,
- TCHAR* uri,
- size_t uri_buffer_length,
- int* port) const {
- assert(url);
- assert(scheme);
- assert(host);
- assert(uri);
- assert(port);
-
- URL_COMPONENTS url_comp = {0};
- url_comp.dwStructSize = sizeof(url_comp);
- url_comp.lpszScheme = scheme;
- url_comp.dwSchemeLength = static_cast<DWORD>(scheme_buffer_length);
- url_comp.lpszHostName = host;
- url_comp.dwHostNameLength = static_cast<DWORD>(host_buffer_length);
- url_comp.lpszUrlPath = uri;
- url_comp.dwUrlPathLength = static_cast<DWORD>(uri_buffer_length);
-
- bool result = !!::WinHttpCrackUrl(url, 0, flags, &url_comp);
- if (result) {
- *port = static_cast<int>(url_comp.nPort);
- }
- return result;
-}
-
-bool WinHttpClient::Open(const TCHAR* user_agent,
- DWORD access_type,
- const TCHAR* proxy_name,
- const TCHAR* proxy_bypass,
- HttpHandle* session_handle) const {
- *session_handle = FromHINTERNET(::WinHttpOpen(user_agent,
- MapAccessType(access_type),
- proxy_name,
- proxy_bypass,
- 0));
-
- return !!(*session_handle);
-}
-
-bool WinHttpClient::Connect(HttpHandle session_handle,
- const TCHAR* server,
- int port,
- HttpHandle* connection_handle) const {
- assert(server);
-
- // Uses NULL user name and password to connect.
- *connection_handle = FromHINTERNET(::WinHttpConnect(
- ToHINTERNET(session_handle),
- server,
- static_cast<INTERNET_PORT>(port),
- NULL));
- return !!(*connection_handle);
-}
-
-bool WinHttpClient::OpenRequest(HttpHandle connection_handle,
- const TCHAR* verb,
- const TCHAR* uri,
- const TCHAR* version,
- const TCHAR* referrer,
- bool is_secure,
- HttpHandle* request_handle) const {
- assert(connection_handle);
- assert(verb);
- assert(uri);
- assert(request_handle);
-
- *request_handle = FromHINTERNET(::WinHttpOpenRequest(
- ToHINTERNET(connection_handle),
- verb,
- uri,
- version,
- referrer,
- WINHTTP_DEFAULT_ACCEPT_TYPES,
- is_secure ? WINHTTP_FLAG_SECURE : 0));
- return !!(*request_handle);
-}
-
-bool WinHttpClient::SendRequest(HttpHandle request_handle,
- const TCHAR* headers,
- DWORD headers_length) const {
- assert(request_handle);
-
- return !!::WinHttpSendRequest(ToHINTERNET(request_handle),
- headers,
- headers_length,
- NULL,
- 0,
- WINHTTP_IGNORE_REQUEST_TOTAL_LENGTH,
- NULL);
-}
-
-bool WinHttpClient::ReceiveResponse(HttpHandle request_handle) const {
- assert(request_handle);
-
- return !!::WinHttpReceiveResponse(ToHINTERNET(request_handle), NULL);
-}
-
-bool WinHttpClient::GetHttpStatusCode(HttpHandle request_handle,
- int* status_code) const {
- TCHAR http_status_string[4] = {0};
- DWORD http_status_string_size = sizeof(http_status_string);
- if (!::WinHttpQueryHeaders(ToHINTERNET(request_handle),
- WINHTTP_QUERY_STATUS_CODE,
- WINHTTP_HEADER_NAME_BY_INDEX,
- static_cast<void *>(&http_status_string),
- &http_status_string_size, 0)) {
- return false;
- }
-
- *status_code = static_cast<DWORD>(_tcstol(http_status_string, NULL, 10));
- return true;
-}
-
-bool WinHttpClient::GetContentLength(HttpHandle request_handle,
- DWORD* content_length) const {
- assert(request_handle);
- assert(content_length);
-
- TCHAR content_length_string[11] = {0};
- DWORD content_length_string_size = sizeof(content_length_string);
- if (!::WinHttpQueryHeaders(ToHINTERNET(request_handle),
- WINHTTP_QUERY_CONTENT_LENGTH,
- WINHTTP_HEADER_NAME_BY_INDEX,
- static_cast<void *>(&content_length_string),
- &content_length_string_size, 0)) {
- *content_length = kUnknownContentLength;
- } else {
- *content_length =
- static_cast<DWORD>(wcstol(content_length_string, NULL, 10));
- }
- return true;
-}
-
-bool WinHttpClient::ReadData(HttpHandle request_handle,
- void* buffer,
- DWORD buffer_length,
- DWORD* bytes_read) const {
- assert(request_handle);
- assert(buffer);
- assert(bytes_read);
-
- DWORD bytes_read_local = 0;
- if (!::WinHttpReadData(ToHINTERNET(request_handle),
- buffer,
- buffer_length,
- &bytes_read_local)) {
- return false;
- }
- *bytes_read = bytes_read_local;
- return true;
-}
-
-bool WinHttpClient::Close(HttpHandle handle) const {
- assert(handle);
- return !!::WinHttpCloseHandle(ToHINTERNET(handle));
-}
-
-DWORD WinHttpClient::MapAccessType(DWORD access_type) {
- switch (static_cast<AccessType>(access_type)) {
- case ACCESS_TYPE_PRECONFIG:
- default:
- return WINHTTP_ACCESS_TYPE_DEFAULT_PROXY;
- case ACCESS_TYPE_DIRECT:
- return WINHTTP_ACCESS_TYPE_NO_PROXY;
- case ACCESS_TYPE_PROXY:
- return WINHTTP_ACCESS_TYPE_NAMED_PROXY;
- }
-}
-
-
-HINTERNET WinHttpClient::ToHINTERNET(HttpHandle handle) {
- return static_cast<HINTERNET>(handle);
-}
-
-HttpHandle WinHttpClient::FromHINTERNET(HINTERNET handle) {
- return static_cast<HttpHandle>(handle);
-}
-
-} // namespace internal
-
-HttpClient* CreateWinHttpClient(const TCHAR* url) {
- assert(url);
-
- internal::WinHttpClient winhttp;
- wchar_t scheme[16] = {0};
- wchar_t host[256] = {0};
- wchar_t path[256] = {0};
- int port = 0;
-
- if (!winhttp.CrackUrl(url,
- 0,
- scheme,
- sizeof(scheme)/sizeof(scheme[0]),
- host,
- sizeof(host)/sizeof(host[0]),
- path,
- sizeof(path)/sizeof(path[0]),
- &port)) {
- return NULL;
- }
-
- if (_wcsicmp(scheme, L"https") == 0) {
- // Winhttp under WINE doesn't support wildcard certificates, so avoid
- // to use it if the scheme is https. The caller should fall back to
- // use wininet if NULL is returned.
- return NULL;
- }
-
- return new internal::WinHttpClient();
-}
-
-} // namespace crash
+// Copyright 2019 Google LLC
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google LLC nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "tools/windows/converter_exe/winhttp_client.h"
+
+#include <assert.h>
+#include <stdlib.h>
+#include <windows.h>
+#include <winhttp.h>
+#include <vector>
+
+namespace crash {
+
+namespace internal {
+
+// This class implements HttpClient based on WinInet APIs.
+class WinHttpClient : public HttpClient {
+ public:
+ virtual ~WinHttpClient() {}
+ virtual bool CrackUrl(const TCHAR* url,
+ DWORD flags,
+ TCHAR* scheme,
+ size_t scheme_buffer_length,
+ TCHAR* host,
+ size_t host_buffer_length,
+ TCHAR* uri,
+ size_t uri_buffer_length,
+ int* port) const;
+ virtual bool Open(const TCHAR* user_agent,
+ DWORD access_type,
+ const TCHAR* proxy_name,
+ const TCHAR* proxy_bypass,
+ HttpHandle* session_handle) const;
+ virtual bool Connect(HttpHandle session_handle,
+ const TCHAR* server,
+ int port,
+ HttpHandle* connection_handle) const;
+ virtual bool OpenRequest(HttpHandle connection_handle,
+ const TCHAR* verb,
+ const TCHAR* uri,
+ const TCHAR* version,
+ const TCHAR* referrer,
+ bool is_secure,
+ HttpHandle* request_handle) const;
+ virtual bool SendRequest(HttpHandle request_handle,
+ const TCHAR* headers,
+ DWORD headers_length) const;
+ virtual bool ReceiveResponse(HttpHandle request_handle) const;
+ virtual bool GetHttpStatusCode(HttpHandle request_handle,
+ int* status_code) const;
+ virtual bool GetContentLength(HttpHandle request_handle,
+ DWORD* content_length) const;
+ virtual bool ReadData(HttpHandle request_handle,
+ void* buffer,
+ DWORD buffer_length,
+ DWORD* bytes_read) const;
+ virtual bool Close(HttpHandle handle) const;
+
+ private:
+ static DWORD MapAccessType(DWORD access_type);
+ static HINTERNET ToHINTERNET(HttpHandle handle);
+ static HttpHandle FromHINTERNET(HINTERNET handle);
+};
+
+bool WinHttpClient::CrackUrl(const TCHAR* url,
+ DWORD flags,
+ TCHAR* scheme,
+ size_t scheme_buffer_length,
+ TCHAR* host,
+ size_t host_buffer_length,
+ TCHAR* uri,
+ size_t uri_buffer_length,
+ int* port) const {
+ assert(url);
+ assert(scheme);
+ assert(host);
+ assert(uri);
+ assert(port);
+
+ URL_COMPONENTS url_comp = {0};
+ url_comp.dwStructSize = sizeof(url_comp);
+ url_comp.lpszScheme = scheme;
+ url_comp.dwSchemeLength = static_cast<DWORD>(scheme_buffer_length);
+ url_comp.lpszHostName = host;
+ url_comp.dwHostNameLength = static_cast<DWORD>(host_buffer_length);
+ url_comp.lpszUrlPath = uri;
+ url_comp.dwUrlPathLength = static_cast<DWORD>(uri_buffer_length);
+
+ bool result = !!::WinHttpCrackUrl(url, 0, flags, &url_comp);
+ if (result) {
+ *port = static_cast<int>(url_comp.nPort);
+ }
+ return result;
+}
+
+bool WinHttpClient::Open(const TCHAR* user_agent,
+ DWORD access_type,
+ const TCHAR* proxy_name,
+ const TCHAR* proxy_bypass,
+ HttpHandle* session_handle) const {
+ *session_handle = FromHINTERNET(::WinHttpOpen(user_agent,
+ MapAccessType(access_type),
+ proxy_name,
+ proxy_bypass,
+ 0));
+
+ return !!(*session_handle);
+}
+
+bool WinHttpClient::Connect(HttpHandle session_handle,
+ const TCHAR* server,
+ int port,
+ HttpHandle* connection_handle) const {
+ assert(server);
+
+ // Uses NULL user name and password to connect.
+ *connection_handle = FromHINTERNET(::WinHttpConnect(
+ ToHINTERNET(session_handle),
+ server,
+ static_cast<INTERNET_PORT>(port),
+ NULL));
+ return !!(*connection_handle);
+}
+
+bool WinHttpClient::OpenRequest(HttpHandle connection_handle,
+ const TCHAR* verb,
+ const TCHAR* uri,
+ const TCHAR* version,
+ const TCHAR* referrer,
+ bool is_secure,
+ HttpHandle* request_handle) const {
+ assert(connection_handle);
+ assert(verb);
+ assert(uri);
+ assert(request_handle);
+
+ *request_handle = FromHINTERNET(::WinHttpOpenRequest(
+ ToHINTERNET(connection_handle),
+ verb,
+ uri,
+ version,
+ referrer,
+ WINHTTP_DEFAULT_ACCEPT_TYPES,
+ is_secure ? WINHTTP_FLAG_SECURE : 0));
+ return !!(*request_handle);
+}
+
+bool WinHttpClient::SendRequest(HttpHandle request_handle,
+ const TCHAR* headers,
+ DWORD headers_length) const {
+ assert(request_handle);
+
+ return !!::WinHttpSendRequest(ToHINTERNET(request_handle),
+ headers,
+ headers_length,
+ NULL,
+ 0,
+ WINHTTP_IGNORE_REQUEST_TOTAL_LENGTH,
+ NULL);
+}
+
+bool WinHttpClient::ReceiveResponse(HttpHandle request_handle) const {
+ assert(request_handle);
+
+ return !!::WinHttpReceiveResponse(ToHINTERNET(request_handle), NULL);
+}
+
+bool WinHttpClient::GetHttpStatusCode(HttpHandle request_handle,
+ int* status_code) const {
+ TCHAR http_status_string[4] = {0};
+ DWORD http_status_string_size = sizeof(http_status_string);
+ if (!::WinHttpQueryHeaders(ToHINTERNET(request_handle),
+ WINHTTP_QUERY_STATUS_CODE,
+ WINHTTP_HEADER_NAME_BY_INDEX,
+ static_cast<void*>(&http_status_string),
+ &http_status_string_size, 0)) {
+ return false;
+ }
+
+ *status_code = static_cast<DWORD>(_tcstol(http_status_string, NULL, 10));
+ return true;
+}
+
+bool WinHttpClient::GetContentLength(HttpHandle request_handle,
+ DWORD* content_length) const {
+ assert(request_handle);
+ assert(content_length);
+
+ TCHAR content_length_string[11] = {0};
+ DWORD content_length_string_size = sizeof(content_length_string);
+ if (!::WinHttpQueryHeaders(ToHINTERNET(request_handle),
+ WINHTTP_QUERY_CONTENT_LENGTH,
+ WINHTTP_HEADER_NAME_BY_INDEX,
+ static_cast<void*>(&content_length_string),
+ &content_length_string_size, 0)) {
+ *content_length = kUnknownContentLength;
+ } else {
+ *content_length =
+ static_cast<DWORD>(wcstol(content_length_string, NULL, 10));
+ }
+ return true;
+}
+
+bool WinHttpClient::ReadData(HttpHandle request_handle,
+ void* buffer,
+ DWORD buffer_length,
+ DWORD* bytes_read) const {
+ assert(request_handle);
+ assert(buffer);
+ assert(bytes_read);
+
+ DWORD bytes_read_local = 0;
+ if (!::WinHttpReadData(ToHINTERNET(request_handle),
+ buffer,
+ buffer_length,
+ &bytes_read_local)) {
+ return false;
+ }
+ *bytes_read = bytes_read_local;
+ return true;
+}
+
+bool WinHttpClient::Close(HttpHandle handle) const {
+ assert(handle);
+ return !!::WinHttpCloseHandle(ToHINTERNET(handle));
+}
+
+DWORD WinHttpClient::MapAccessType(DWORD access_type) {
+ switch (static_cast<AccessType>(access_type)) {
+ case ACCESS_TYPE_PRECONFIG:
+ default:
+ return WINHTTP_ACCESS_TYPE_DEFAULT_PROXY;
+ case ACCESS_TYPE_DIRECT:
+ return WINHTTP_ACCESS_TYPE_NO_PROXY;
+ case ACCESS_TYPE_PROXY:
+ return WINHTTP_ACCESS_TYPE_NAMED_PROXY;
+ }
+}
+
+
+HINTERNET WinHttpClient::ToHINTERNET(HttpHandle handle) {
+ return static_cast<HINTERNET>(handle);
+}
+
+HttpHandle WinHttpClient::FromHINTERNET(HINTERNET handle) {
+ return static_cast<HttpHandle>(handle);
+}
+
+} // namespace internal
+
+HttpClient* CreateWinHttpClient(const TCHAR* url) {
+ assert(url);
+
+ internal::WinHttpClient winhttp;
+ wchar_t scheme[16] = {0};
+ wchar_t host[256] = {0};
+ wchar_t path[256] = {0};
+ int port = 0;
+
+ if (!winhttp.CrackUrl(url,
+ 0,
+ scheme,
+ sizeof(scheme)/sizeof(scheme[0]),
+ host,
+ sizeof(host)/sizeof(host[0]),
+ path,
+ sizeof(path)/sizeof(path[0]),
+ &port)) {
+ return NULL;
+ }
+
+ if (_wcsicmp(scheme, L"https") == 0) {
+ // Winhttp under WINE doesn't support wildcard certificates, so avoid
+ // to use it if the scheme is https. The caller should fall back to
+ // use wininet if NULL is returned.
+ return NULL;
+ }
+
+ return new internal::WinHttpClient();
+}
+
+} // namespace crash
diff --git a/src/tools/windows/converter_exe/winhttp_client.h b/src/tools/windows/converter_exe/winhttp_client.h
index 819d610f..4ccac7e0 100644
--- a/src/tools/windows/converter_exe/winhttp_client.h
+++ b/src/tools/windows/converter_exe/winhttp_client.h
@@ -1,40 +1,40 @@
-// Copyright 2019 Google Inc. All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-#ifndef TOOLS_WINDOWS_CONVERTER_EXE_WINHTTP_CLIENT_H_
-#define TOOLS_WINDOWS_CONVERTER_EXE_WINHTTP_CLIENT_H_
-
-#include "tools/windows/converter_exe/http_client.h"
-
-namespace crash {
-
-HttpClient* CreateWinHttpClient(const TCHAR* url);
-
-} // namespace crash
-
-#endif // TOOLS_WINDOWS_CONVERTER_EXE_WINHTTP_CLIENT_H_
+// Copyright 2019 Google LLC
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google LLC nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef TOOLS_WINDOWS_CONVERTER_EXE_WINHTTP_CLIENT_H_
+#define TOOLS_WINDOWS_CONVERTER_EXE_WINHTTP_CLIENT_H_
+
+#include "tools/windows/converter_exe/http_client.h"
+
+namespace crash {
+
+HttpClient* CreateWinHttpClient(const TCHAR* url);
+
+} // namespace crash
+
+#endif // TOOLS_WINDOWS_CONVERTER_EXE_WINHTTP_CLIENT_H_
diff --git a/src/tools/windows/converter_exe/wininet_client.cc b/src/tools/windows/converter_exe/wininet_client.cc
index 3e542db2..90cf114c 100644
--- a/src/tools/windows/converter_exe/wininet_client.cc
+++ b/src/tools/windows/converter_exe/wininet_client.cc
@@ -1,278 +1,278 @@
-// Copyright 2019 Google Inc. All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-#include "tools/windows/converter_exe/wininet_client.h"
-
-#include <assert.h>
-#include <stdlib.h>
-#include <windows.h>
-#include <wininet.h>
-
-namespace crash {
-
-namespace internal {
-
-// This class implements HttpClient based on WinInet APIs.
-class WinInetClient : public HttpClient {
- public:
- virtual ~WinInetClient() {}
- virtual bool CrackUrl(const TCHAR* url,
- DWORD flags,
- TCHAR* scheme,
- size_t scheme_buffer_length,
- TCHAR* host,
- size_t host_buffer_length,
- TCHAR* uri,
- size_t uri_buffer_length,
- int* port) const;
- virtual bool Open(const TCHAR* user_agent,
- DWORD access_type,
- const TCHAR* proxy_name,
- const TCHAR* proxy_bypass,
- HttpHandle* session_handle) const;
- virtual bool Connect(HttpHandle session_handle,
- const TCHAR* server,
- int port,
- HttpHandle* connection_handle) const;
- virtual bool OpenRequest(HttpHandle connection_handle,
- const TCHAR* verb,
- const TCHAR* uri,
- const TCHAR* version,
- const TCHAR* referrer,
- bool is_secure,
- HttpHandle* request_handle) const;
- virtual bool SendRequest(HttpHandle request_handle,
- const TCHAR* headers,
- DWORD headers_length) const;
- virtual bool ReceiveResponse(HttpHandle request_handle) const;
- virtual bool GetHttpStatusCode(HttpHandle request_handle,
- int* status_code) const;
- virtual bool GetContentLength(HttpHandle request_handle,
- DWORD* content_length) const;
- virtual bool ReadData(HttpHandle request_handle,
- void* buffer,
- DWORD buffer_length,
- DWORD* bytes_read) const;
- virtual bool Close(HttpHandle handle) const;
-
- private:
- static DWORD MapAccessType(DWORD access_type);
- static HINTERNET ToHINTERNET(HttpHandle handle);
- static HttpHandle FromHINTERNET(HINTERNET handle);
-};
-
-bool WinInetClient::CrackUrl(const TCHAR* url,
- DWORD flags,
- TCHAR* scheme,
- size_t scheme_buffer_length,
- TCHAR* host,
- size_t host_buffer_length,
- TCHAR* uri,
- size_t uri_buffer_length,
- int* port) const {
- assert(url);
- assert(scheme);
- assert(host);
- assert(uri);
- assert(port);
-
- URL_COMPONENTS url_comp = {0};
- url_comp.dwStructSize = sizeof(url_comp);
- url_comp.lpszScheme = scheme;
- url_comp.dwSchemeLength = static_cast<DWORD>(scheme_buffer_length);
- url_comp.lpszHostName = host;
- url_comp.dwHostNameLength = static_cast<DWORD>(host_buffer_length);
- url_comp.lpszUrlPath = uri;
- url_comp.dwUrlPathLength = static_cast<DWORD>(uri_buffer_length);
-
- bool result = !!::InternetCrackUrl(url, 0, flags, &url_comp);
- if (result) {
- *port = static_cast<int>(url_comp.nPort);
- }
- return result;
-}
-
-bool WinInetClient::Open(const TCHAR* user_agent,
- DWORD access_type,
- const TCHAR* proxy_name,
- const TCHAR* proxy_bypass,
- HttpHandle* session_handle) const {
- *session_handle = FromHINTERNET(::InternetOpen(user_agent,
- MapAccessType(access_type),
- proxy_name,
- proxy_bypass,
- 0));
- return !!(*session_handle);
-}
-
-bool WinInetClient::Connect(HttpHandle session_handle,
- const TCHAR* server,
- int port,
- HttpHandle* connection_handle) const {
- assert(server);
-
- // Uses NULL user name and password to connect. Always uses http service.
- *connection_handle = FromHINTERNET(::InternetConnect(
- ToHINTERNET(session_handle),
- server,
- static_cast<INTERNET_PORT>(port),
- NULL,
- NULL,
- INTERNET_SERVICE_HTTP,
- 0,
- 0));
- return !!(*connection_handle);
-}
-
-bool WinInetClient::OpenRequest(HttpHandle connection_handle,
- const TCHAR* verb,
- const TCHAR* uri,
- const TCHAR* version,
- const TCHAR* referrer,
- bool is_secure,
- HttpHandle* request_handle) const {
- assert(connection_handle);
- assert(verb);
- assert(uri);
-
- *request_handle = FromHINTERNET(::HttpOpenRequest(
- ToHINTERNET(connection_handle),
- verb,
- uri,
- version,
- referrer,
- NULL,
- is_secure ? INTERNET_FLAG_SECURE : 0,
- NULL));
- return !!(*request_handle);
-}
-
-bool WinInetClient::SendRequest(HttpHandle request_handle,
- const TCHAR* headers,
- DWORD headers_length) const {
- assert(request_handle);
-
- return !!::HttpSendRequest(ToHINTERNET(request_handle),
- headers,
- headers_length,
- NULL,
- 0);
-}
-
-bool WinInetClient::ReceiveResponse(HttpHandle) const {
- return true;
-}
-
-bool WinInetClient::GetHttpStatusCode(HttpHandle request_handle,
- int* status_code) const {
- assert(request_handle);
-
- TCHAR http_status_string[4] = {0};
- DWORD http_status_string_size = sizeof(http_status_string);
- if (!::HttpQueryInfo(ToHINTERNET(request_handle),
- HTTP_QUERY_STATUS_CODE,
- static_cast<void *>(&http_status_string),
- &http_status_string_size,
- 0)) {
- return false;
- }
-
- *status_code = _tcstol(http_status_string, NULL, 10);
- return true;
-}
-
-bool WinInetClient::GetContentLength(HttpHandle request_handle,
- DWORD* content_length) const {
- assert(request_handle);
- assert(content_length);
-
- TCHAR content_length_string[11];
- DWORD content_length_string_size = sizeof(content_length_string);
- if (!::HttpQueryInfo(ToHINTERNET(request_handle),
- HTTP_QUERY_CONTENT_LENGTH,
- static_cast<void *>(&content_length_string),
- &content_length_string_size,
- 0)) {
- *content_length = kUnknownContentLength;
- } else {
- *content_length = wcstol(content_length_string, NULL, 10);
- }
- return true;
-}
-
-bool WinInetClient::ReadData(HttpHandle request_handle,
- void* buffer,
- DWORD buffer_length,
- DWORD* bytes_read) const {
- assert(request_handle);
- assert(buffer);
- assert(bytes_read);
-
- DWORD bytes_read_local = 0;
- if (!::InternetReadFile(ToHINTERNET(request_handle),
- buffer,
- buffer_length,
- &bytes_read_local)) {
- return false;
- }
- *bytes_read = bytes_read_local;
- return true;
-}
-
-bool WinInetClient::Close(HttpHandle handle) const {
- assert(handle);
- return !!::InternetCloseHandle(ToHINTERNET(handle));
-}
-
-DWORD WinInetClient::MapAccessType(DWORD access_type) {
- switch (static_cast<AccessType>(access_type)) {
- case ACCESS_TYPE_PRECONFIG:
- default:
- return INTERNET_OPEN_TYPE_PRECONFIG;
- case ACCESS_TYPE_DIRECT:
- return INTERNET_OPEN_TYPE_DIRECT;
- case ACCESS_TYPE_PROXY:
- return INTERNET_OPEN_TYPE_PROXY;
- }
-}
-
-HINTERNET WinInetClient::ToHINTERNET(HttpHandle handle) {
- return static_cast<HINTERNET>(handle);
-}
-
-HttpHandle WinInetClient::FromHINTERNET(HINTERNET handle) {
- return static_cast<HttpHandle>(handle);
-}
-
-} // namespace internal
-
-HttpClient* CreateWinInetClient(const TCHAR*) {
- return new internal::WinInetClient();
-}
-
-} // namespace crash
+// Copyright 2019 Google LLC
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google LLC nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "tools/windows/converter_exe/wininet_client.h"
+
+#include <assert.h>
+#include <stdlib.h>
+#include <windows.h>
+#include <wininet.h>
+
+namespace crash {
+
+namespace internal {
+
+// This class implements HttpClient based on WinInet APIs.
+class WinInetClient : public HttpClient {
+ public:
+ virtual ~WinInetClient() {}
+ virtual bool CrackUrl(const TCHAR* url,
+ DWORD flags,
+ TCHAR* scheme,
+ size_t scheme_buffer_length,
+ TCHAR* host,
+ size_t host_buffer_length,
+ TCHAR* uri,
+ size_t uri_buffer_length,
+ int* port) const;
+ virtual bool Open(const TCHAR* user_agent,
+ DWORD access_type,
+ const TCHAR* proxy_name,
+ const TCHAR* proxy_bypass,
+ HttpHandle* session_handle) const;
+ virtual bool Connect(HttpHandle session_handle,
+ const TCHAR* server,
+ int port,
+ HttpHandle* connection_handle) const;
+ virtual bool OpenRequest(HttpHandle connection_handle,
+ const TCHAR* verb,
+ const TCHAR* uri,
+ const TCHAR* version,
+ const TCHAR* referrer,
+ bool is_secure,
+ HttpHandle* request_handle) const;
+ virtual bool SendRequest(HttpHandle request_handle,
+ const TCHAR* headers,
+ DWORD headers_length) const;
+ virtual bool ReceiveResponse(HttpHandle request_handle) const;
+ virtual bool GetHttpStatusCode(HttpHandle request_handle,
+ int* status_code) const;
+ virtual bool GetContentLength(HttpHandle request_handle,
+ DWORD* content_length) const;
+ virtual bool ReadData(HttpHandle request_handle,
+ void* buffer,
+ DWORD buffer_length,
+ DWORD* bytes_read) const;
+ virtual bool Close(HttpHandle handle) const;
+
+ private:
+ static DWORD MapAccessType(DWORD access_type);
+ static HINTERNET ToHINTERNET(HttpHandle handle);
+ static HttpHandle FromHINTERNET(HINTERNET handle);
+};
+
+bool WinInetClient::CrackUrl(const TCHAR* url,
+ DWORD flags,
+ TCHAR* scheme,
+ size_t scheme_buffer_length,
+ TCHAR* host,
+ size_t host_buffer_length,
+ TCHAR* uri,
+ size_t uri_buffer_length,
+ int* port) const {
+ assert(url);
+ assert(scheme);
+ assert(host);
+ assert(uri);
+ assert(port);
+
+ URL_COMPONENTS url_comp = {0};
+ url_comp.dwStructSize = sizeof(url_comp);
+ url_comp.lpszScheme = scheme;
+ url_comp.dwSchemeLength = static_cast<DWORD>(scheme_buffer_length);
+ url_comp.lpszHostName = host;
+ url_comp.dwHostNameLength = static_cast<DWORD>(host_buffer_length);
+ url_comp.lpszUrlPath = uri;
+ url_comp.dwUrlPathLength = static_cast<DWORD>(uri_buffer_length);
+
+ bool result = !!::InternetCrackUrl(url, 0, flags, &url_comp);
+ if (result) {
+ *port = static_cast<int>(url_comp.nPort);
+ }
+ return result;
+}
+
+bool WinInetClient::Open(const TCHAR* user_agent,
+ DWORD access_type,
+ const TCHAR* proxy_name,
+ const TCHAR* proxy_bypass,
+ HttpHandle* session_handle) const {
+ *session_handle = FromHINTERNET(::InternetOpen(user_agent,
+ MapAccessType(access_type),
+ proxy_name,
+ proxy_bypass,
+ 0));
+ return !!(*session_handle);
+}
+
+bool WinInetClient::Connect(HttpHandle session_handle,
+ const TCHAR* server,
+ int port,
+ HttpHandle* connection_handle) const {
+ assert(server);
+
+ // Uses NULL user name and password to connect. Always uses http service.
+ *connection_handle = FromHINTERNET(::InternetConnect(
+ ToHINTERNET(session_handle),
+ server,
+ static_cast<INTERNET_PORT>(port),
+ NULL,
+ NULL,
+ INTERNET_SERVICE_HTTP,
+ 0,
+ 0));
+ return !!(*connection_handle);
+}
+
+bool WinInetClient::OpenRequest(HttpHandle connection_handle,
+ const TCHAR* verb,
+ const TCHAR* uri,
+ const TCHAR* version,
+ const TCHAR* referrer,
+ bool is_secure,
+ HttpHandle* request_handle) const {
+ assert(connection_handle);
+ assert(verb);
+ assert(uri);
+
+ *request_handle = FromHINTERNET(::HttpOpenRequest(
+ ToHINTERNET(connection_handle),
+ verb,
+ uri,
+ version,
+ referrer,
+ NULL,
+ is_secure ? INTERNET_FLAG_SECURE : 0,
+ NULL));
+ return !!(*request_handle);
+}
+
+bool WinInetClient::SendRequest(HttpHandle request_handle,
+ const TCHAR* headers,
+ DWORD headers_length) const {
+ assert(request_handle);
+
+ return !!::HttpSendRequest(ToHINTERNET(request_handle),
+ headers,
+ headers_length,
+ NULL,
+ 0);
+}
+
+bool WinInetClient::ReceiveResponse(HttpHandle) const {
+ return true;
+}
+
+bool WinInetClient::GetHttpStatusCode(HttpHandle request_handle,
+ int* status_code) const {
+ assert(request_handle);
+
+ TCHAR http_status_string[4] = {0};
+ DWORD http_status_string_size = sizeof(http_status_string);
+ if (!::HttpQueryInfo(ToHINTERNET(request_handle),
+ HTTP_QUERY_STATUS_CODE,
+ static_cast<void*>(&http_status_string),
+ &http_status_string_size,
+ 0)) {
+ return false;
+ }
+
+ *status_code = _tcstol(http_status_string, NULL, 10);
+ return true;
+}
+
+bool WinInetClient::GetContentLength(HttpHandle request_handle,
+ DWORD* content_length) const {
+ assert(request_handle);
+ assert(content_length);
+
+ TCHAR content_length_string[11];
+ DWORD content_length_string_size = sizeof(content_length_string);
+ if (!::HttpQueryInfo(ToHINTERNET(request_handle),
+ HTTP_QUERY_CONTENT_LENGTH,
+ static_cast<void*>(&content_length_string),
+ &content_length_string_size,
+ 0)) {
+ *content_length = kUnknownContentLength;
+ } else {
+ *content_length = wcstol(content_length_string, NULL, 10);
+ }
+ return true;
+}
+
+bool WinInetClient::ReadData(HttpHandle request_handle,
+ void* buffer,
+ DWORD buffer_length,
+ DWORD* bytes_read) const {
+ assert(request_handle);
+ assert(buffer);
+ assert(bytes_read);
+
+ DWORD bytes_read_local = 0;
+ if (!::InternetReadFile(ToHINTERNET(request_handle),
+ buffer,
+ buffer_length,
+ &bytes_read_local)) {
+ return false;
+ }
+ *bytes_read = bytes_read_local;
+ return true;
+}
+
+bool WinInetClient::Close(HttpHandle handle) const {
+ assert(handle);
+ return !!::InternetCloseHandle(ToHINTERNET(handle));
+}
+
+DWORD WinInetClient::MapAccessType(DWORD access_type) {
+ switch (static_cast<AccessType>(access_type)) {
+ case ACCESS_TYPE_PRECONFIG:
+ default:
+ return INTERNET_OPEN_TYPE_PRECONFIG;
+ case ACCESS_TYPE_DIRECT:
+ return INTERNET_OPEN_TYPE_DIRECT;
+ case ACCESS_TYPE_PROXY:
+ return INTERNET_OPEN_TYPE_PROXY;
+ }
+}
+
+HINTERNET WinInetClient::ToHINTERNET(HttpHandle handle) {
+ return static_cast<HINTERNET>(handle);
+}
+
+HttpHandle WinInetClient::FromHINTERNET(HINTERNET handle) {
+ return static_cast<HttpHandle>(handle);
+}
+
+} // namespace internal
+
+HttpClient* CreateWinInetClient(const TCHAR*) {
+ return new internal::WinInetClient();
+}
+
+} // namespace crash
diff --git a/src/tools/windows/converter_exe/wininet_client.h b/src/tools/windows/converter_exe/wininet_client.h
index bd04b605..8b4c61b5 100644
--- a/src/tools/windows/converter_exe/wininet_client.h
+++ b/src/tools/windows/converter_exe/wininet_client.h
@@ -1,40 +1,40 @@
-// Copyright 2019 Google Inc. All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-#ifndef TOOLS_WINDOWS_CONVERTER_EXE_WININET_CLIENT_H_
-#define TOOLS_WINDOWS_CONVERTER_EXE_WININET_CLIENT_H_
-
-#include "tools/windows/converter_exe/http_client.h"
-
-namespace crash {
-
-HttpClient* CreateWinInetClient(const TCHAR* url);
-
-} // namespace crash
-
-#endif // TOOLS_WINDOWS_CONVERTER_EXE_WININET_CLIENT_H_
+// Copyright 2019 Google LLC
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google LLC nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef TOOLS_WINDOWS_CONVERTER_EXE_WININET_CLIENT_H_
+#define TOOLS_WINDOWS_CONVERTER_EXE_WININET_CLIENT_H_
+
+#include "tools/windows/converter_exe/http_client.h"
+
+namespace crash {
+
+HttpClient* CreateWinInetClient(const TCHAR* url);
+
+} // namespace crash
+
+#endif // TOOLS_WINDOWS_CONVERTER_EXE_WININET_CLIENT_H_
diff --git a/src/tools/windows/dump_syms/dump_syms.cc b/src/tools/windows/dump_syms/dump_syms.cc
index 5b7d1777..26c226a2 100644
--- a/src/tools/windows/dump_syms/dump_syms.cc
+++ b/src/tools/windows/dump_syms/dump_syms.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2006, Google Inc.
-// All rights reserved.
+// Copyright 2006 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -33,35 +32,61 @@
#include <stdio.h>
#include <wchar.h>
+#include <memory>
#include <string>
#include "common/windows/pdb_source_line_writer.h"
#include "common/windows/pe_source_line_writer.h"
-using std::wstring;
using google_breakpad::PDBSourceLineWriter;
using google_breakpad::PESourceLineWriter;
using std::unique_ptr;
+using std::wstring;
+
+int usage(const wchar_t* self) {
+ fprintf(stderr, "Usage: %ws [--pe] [--i] <file.[pdb|exe|dll]>\n", self);
+ fprintf(stderr, "Options:\n");
+ fprintf(stderr,
+ "--pe:\tRead debugging information from PE file and do "
+ "not attempt to locate matching PDB file.\n"
+ "\tThis is only supported for PE32+ (64 bit) PE files.\n");
+ fprintf(stderr,
+ "--i:\tOutput INLINE/INLINE_ORIGIN record\n"
+ "\tThis cannot be used with [--pe].\n");
+ return 1;
+}
-int wmain(int argc, wchar_t **argv) {
- bool success;
- if (argc == 2) {
- PDBSourceLineWriter pdb_writer;
- if (!pdb_writer.Open(wstring(argv[1]), PDBSourceLineWriter::ANY_FILE)) {
+int wmain(int argc, wchar_t** argv) {
+ bool success = false;
+ bool pe = false;
+ bool handle_inline = false;
+ int arg_index = 1;
+ while (arg_index < argc && wcslen(argv[arg_index]) > 0 &&
+ wcsncmp(L"--", argv[arg_index], 2) == 0) {
+ if (wcscmp(L"--pe", argv[arg_index]) == 0) {
+ pe = true;
+ } else if (wcscmp(L"--i", argv[arg_index]) == 0) {
+ handle_inline = true;
+ }
+ ++arg_index;
+ }
+
+ if ((pe && handle_inline) || arg_index == argc) {
+ usage(argv[0]);
+ return 1;
+ }
+
+ wchar_t* file_path = argv[arg_index];
+ if (pe) {
+ PESourceLineWriter pe_writer(file_path);
+ success = pe_writer.WriteSymbols(stdout);
+ } else {
+ PDBSourceLineWriter pdb_writer(handle_inline);
+ if (!pdb_writer.Open(wstring(file_path), PDBSourceLineWriter::ANY_FILE)) {
fprintf(stderr, "Open failed.\n");
return 1;
}
success = pdb_writer.WriteSymbols(stdout);
- } else if (argc == 3 && wcscmp(argv[1], L"--pe") == 0) {
- PESourceLineWriter pe_writer(argv[2]);
- success = pe_writer.WriteSymbols(stdout);
- } else {
- fprintf(stderr, "Usage: %ws [--pe] <file.[pdb|exe|dll]>\n", argv[0]);
- fprintf(stderr, "Options:\n");
- fprintf(stderr, "--pe:\tRead debugging information from PE file and do "
- "not attempt to locate matching PDB file.\n"
- "\tThis is only supported for PE32+ (64 bit) PE files.\n");
- return 1;
}
if (!success) {
diff --git a/src/tools/windows/dump_syms/dump_syms.gyp b/src/tools/windows/dump_syms/dump_syms.gyp
deleted file mode 100644
index b815574b..00000000
--- a/src/tools/windows/dump_syms/dump_syms.gyp
+++ /dev/null
@@ -1,64 +0,0 @@
-# Copyright 2013 Google Inc. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-# * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-# * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-{
- 'includes': [
- '../../../build/common.gypi',
- ],
- 'targets': [
- {
- 'target_name': 'dump_syms',
- 'type': 'executable',
- 'sources': [
- 'dump_syms.cc',
- ],
- 'dependencies': [
- '../../../common/windows/common_windows.gyp:common_windows_lib',
- ],
- },
- {
- 'target_name': 'dump_syms_unittest',
- 'type': 'executable',
- 'sources': [
- 'dump_syms_unittest.cc',
- ],
- 'dependencies': [
- '<(DEPTH)/client/windows/unittests/testing.gyp:gmock',
- '<(DEPTH)/client/windows/unittests/testing.gyp:gtest',
- 'dump_syms',
- ],
- 'msvs_settings': {
- 'VCLinkerTool': {
- 'AdditionalDependencies': [
- 'shell32.lib',
- ],
- },
- },
- },
- ],
-}
diff --git a/src/tools/windows/dump_syms/dump_syms_unittest.cc b/src/tools/windows/dump_syms/dump_syms_unittest.cc
index 766e5c09..97dc5c9b 100644
--- a/src/tools/windows/dump_syms/dump_syms_unittest.cc
+++ b/src/tools/windows/dump_syms/dump_syms_unittest.cc
@@ -1,244 +1,244 @@
-// Copyright 2003 Google Inc. All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-#include <Windows.h>
-#include <shellapi.h>
-
-#include <string>
-#include <utility>
-
-#include "breakpad_googletest_includes.h"
-
-namespace tools {
-namespace windows {
-namespace dump_syms {
-
-namespace {
-
-// Root names of PDB and dumped symbol files to be regression tested. These are
-// specified in complexity of the resulting dumped symbol files.
-const wchar_t* kRootNames[] = {
- // A PDB file with no OMAP data.
- L"dump_syms_regtest",
- // A PDB file with OMAP data for an image that has been function-level
- // reordered.
- L"omap_reorder_funcs",
- // A PDB file with OMAP data for an image that had new content injected, all
- // of it with source data.
- L"omap_stretched_filled",
- // A PDB file with OMAP data for an image that had new content injected, but
- // without source data.
- L"omap_stretched",
- // A PDB file with OMAP data for an image that has been basic block reordered.
- L"omap_reorder_bbs",
- // A 64bit PDB file with no OMAP data.
- L"dump_syms_regtest64",
-};
-
-const wchar_t* kPEOnlyRootNames[] = {
- L"pe_only_symbol_test",
-};
-
-void TrimLastComponent(const std::wstring& path,
- std::wstring* trimmed,
- std::wstring* component) {
- size_t len = path.size();
- while (len > 0 && path[len - 1] != '\\')
- --len;
-
- if (component != NULL)
- component->assign(path.c_str() + len, path.c_str() + path.size());
-
- while (len > 0 && path[len - 1] == '\\')
- --len;
-
- if (trimmed != NULL)
- trimmed->assign(path.c_str(), len);
-}
-
-// Get the directory of the current executable.
-bool GetSelfDirectory(std::wstring* self_dir) {
- std::wstring command_line = GetCommandLineW();
-
- int num_args = 0;
- wchar_t** args = NULL;
- args = ::CommandLineToArgvW(command_line.c_str(), &num_args);
- if (args == NULL)
- return false;
-
- *self_dir = args[0];
- TrimLastComponent(*self_dir, self_dir, NULL);
-
- return true;
-}
-
-void RunCommand(const std::wstring& command_line,
- std::string* stdout_string) {
- // Create a PIPE for the child process stdout.
- HANDLE child_stdout_read = 0;
- HANDLE child_stdout_write = 0;
- SECURITY_ATTRIBUTES sec_attr_stdout = {};
- sec_attr_stdout.nLength = sizeof(sec_attr_stdout);
- sec_attr_stdout.bInheritHandle = TRUE;
- ASSERT_TRUE(::CreatePipe(&child_stdout_read, &child_stdout_write,
- &sec_attr_stdout, 0));
- ASSERT_TRUE(::SetHandleInformation(child_stdout_read, HANDLE_FLAG_INHERIT,
- 0));
-
- // Create a PIPE for the child process stdin.
- HANDLE child_stdin_read = 0;
- HANDLE child_stdin_write = 0;
- SECURITY_ATTRIBUTES sec_attr_stdin = {};
- sec_attr_stdin.nLength = sizeof(sec_attr_stdin);
- sec_attr_stdin.bInheritHandle = TRUE;
- ASSERT_TRUE(::CreatePipe(&child_stdin_read, &child_stdin_write,
- &sec_attr_stdin, 0));
- ASSERT_TRUE(::SetHandleInformation(child_stdin_write, HANDLE_FLAG_INHERIT,
- 0));
-
- // Startup the child.
- STARTUPINFO startup_info = {};
- PROCESS_INFORMATION process_info = {};
- startup_info.cb = sizeof(STARTUPINFO);
- startup_info.hStdError = NULL;
- startup_info.hStdInput = child_stdin_read;
- startup_info.hStdOutput = child_stdout_write;
- startup_info.dwFlags = STARTF_USESTDHANDLES;
- ASSERT_TRUE(::CreateProcessW(NULL, (LPWSTR)command_line.c_str(), NULL, NULL,
- TRUE, 0, NULL, NULL,
- &startup_info, &process_info));
-
- // Collect the output.
- ASSERT_TRUE(::CloseHandle(child_stdout_write));
- char buffer[4096] = {};
- DWORD bytes_read = 0;
- while (::ReadFile(child_stdout_read, buffer, sizeof(buffer), &bytes_read,
- NULL) && bytes_read > 0) {
- stdout_string->append(buffer, bytes_read);
- }
-
- // Wait for the process to finish.
- ::WaitForSingleObject(process_info.hProcess, INFINITE);
-
- // Shut down all of our handles.
- ASSERT_TRUE(::CloseHandle(process_info.hThread));
- ASSERT_TRUE(::CloseHandle(process_info.hProcess));
- ASSERT_TRUE(::CloseHandle(child_stdin_write));
- ASSERT_TRUE(::CloseHandle(child_stdin_read));
- ASSERT_TRUE(::CloseHandle(child_stdout_read));
-}
-
-void GetFileContents(const std::wstring& path, std::string* content) {
- FILE* f = ::_wfopen(path.c_str(), L"rb");
- ASSERT_TRUE(f != NULL);
-
- char buffer[4096] = {};
- while (true) {
- size_t bytes_read = ::fread(buffer, 1, sizeof(buffer), f);
- if (bytes_read == 0)
- break;
- content->append(buffer, bytes_read);
- }
-}
-
-class DumpSymsRegressionTest : public testing::TestWithParam<const wchar_t *> {
- public:
- virtual void SetUp() {
- std::wstring self_dir;
- ASSERT_TRUE(GetSelfDirectory(&self_dir));
- dump_syms_exe = self_dir + L"\\dump_syms.exe";
-
- TrimLastComponent(self_dir, &testdata_dir, NULL);
- testdata_dir += L"\\testdata";
- }
-
- std::wstring dump_syms_exe;
- std::wstring testdata_dir;
-};
-
-class DumpSymsPEOnlyRegressionTest : public testing::TestWithParam<const wchar_t *> {
-public:
- virtual void SetUp() {
- std::wstring self_dir;
- ASSERT_TRUE(GetSelfDirectory(&self_dir));
- dump_syms_exe = self_dir + L"\\dump_syms.exe";
-
- TrimLastComponent(self_dir, &testdata_dir, NULL);
- testdata_dir += L"\\testdata";
- }
-
- std::wstring dump_syms_exe;
- std::wstring testdata_dir;
-};
-
-} //namespace
-
-TEST_P(DumpSymsRegressionTest, EnsureDumpedSymbolsMatch) {
- const wchar_t* root_name = GetParam();
- std::wstring root_path = testdata_dir + L"\\" + root_name;
-
- std::wstring sym_path = root_path + L".sym";
- std::string expected_symbols;
- ASSERT_NO_FATAL_FAILURE(GetFileContents(sym_path, &expected_symbols));
-
- std::wstring pdb_path = root_path + L".pdb";
- std::wstring command_line = L"\"" + dump_syms_exe + L"\" \"" +
- pdb_path + L"\"";
- std::string symbols;
- ASSERT_NO_FATAL_FAILURE(RunCommand(command_line, &symbols));
-
- EXPECT_EQ(expected_symbols, symbols);
-}
-
-INSTANTIATE_TEST_CASE_P(DumpSyms, DumpSymsRegressionTest,
- testing::ValuesIn(kRootNames));
-
-TEST_P(DumpSymsPEOnlyRegressionTest, EnsurePEOnlyDumpedSymbolsMatch) {
- const wchar_t* root_name = GetParam();
- std::wstring root_path = testdata_dir + L"\\" + root_name;
-
- std::wstring sym_path = root_path + L".sym";
- std::string expected_symbols;
- ASSERT_NO_FATAL_FAILURE(GetFileContents(sym_path, &expected_symbols));
-
- std::wstring dll_path = root_path + L".dll";
- std::wstring command_line = L"\"" + dump_syms_exe + L"\" --pe \"" +
- dll_path + L"\"";
- std::string symbols;
- ASSERT_NO_FATAL_FAILURE(RunCommand(command_line, &symbols));
-
- EXPECT_EQ(expected_symbols, symbols);
-}
-
-INSTANTIATE_TEST_CASE_P(PEOnlyDumpSyms, DumpSymsPEOnlyRegressionTest,
- testing::ValuesIn(kPEOnlyRootNames));
-
-
-} // namespace dump_syms
-} // namespace windows
-} // namespace tools
+// Copyright 2003 Google LLC
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google LLC nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <Windows.h>
+#include <shellapi.h>
+
+#include <string>
+#include <utility>
+
+#include "breakpad_googletest_includes.h"
+
+namespace tools {
+namespace windows {
+namespace dump_syms {
+
+namespace {
+
+// Root names of PDB and dumped symbol files to be regression tested. These are
+// specified in complexity of the resulting dumped symbol files.
+const wchar_t* kRootNames[] = {
+ // A PDB file with no OMAP data.
+ L"dump_syms_regtest",
+ // A PDB file with OMAP data for an image that has been function-level
+ // reordered.
+ L"omap_reorder_funcs",
+ // A PDB file with OMAP data for an image that had new content injected, all
+ // of it with source data.
+ L"omap_stretched_filled",
+ // A PDB file with OMAP data for an image that had new content injected, but
+ // without source data.
+ L"omap_stretched",
+ // A PDB file with OMAP data for an image that has been basic block reordered.
+ L"omap_reorder_bbs",
+ // A 64bit PDB file with no OMAP data.
+ L"dump_syms_regtest64",
+};
+
+const wchar_t* kPEOnlyRootNames[] = {
+ L"pe_only_symbol_test",
+};
+
+void TrimLastComponent(const std::wstring& path,
+ std::wstring* trimmed,
+ std::wstring* component) {
+ size_t len = path.size();
+ while (len > 0 && path[len - 1] != '\\')
+ --len;
+
+ if (component != NULL)
+ component->assign(path.c_str() + len, path.c_str() + path.size());
+
+ while (len > 0 && path[len - 1] == '\\')
+ --len;
+
+ if (trimmed != NULL)
+ trimmed->assign(path.c_str(), len);
+}
+
+// Get the directory of the current executable.
+bool GetSelfDirectory(std::wstring* self_dir) {
+ std::wstring command_line = GetCommandLineW();
+
+ int num_args = 0;
+ wchar_t** args = NULL;
+ args = ::CommandLineToArgvW(command_line.c_str(), &num_args);
+ if (args == NULL)
+ return false;
+
+ *self_dir = args[0];
+ TrimLastComponent(*self_dir, self_dir, NULL);
+
+ return true;
+}
+
+void RunCommand(const std::wstring& command_line,
+ std::string* stdout_string) {
+ // Create a PIPE for the child process stdout.
+ HANDLE child_stdout_read = 0;
+ HANDLE child_stdout_write = 0;
+ SECURITY_ATTRIBUTES sec_attr_stdout = {};
+ sec_attr_stdout.nLength = sizeof(sec_attr_stdout);
+ sec_attr_stdout.bInheritHandle = TRUE;
+ ASSERT_TRUE(::CreatePipe(&child_stdout_read, &child_stdout_write,
+ &sec_attr_stdout, 0));
+ ASSERT_TRUE(::SetHandleInformation(child_stdout_read, HANDLE_FLAG_INHERIT,
+ 0));
+
+ // Create a PIPE for the child process stdin.
+ HANDLE child_stdin_read = 0;
+ HANDLE child_stdin_write = 0;
+ SECURITY_ATTRIBUTES sec_attr_stdin = {};
+ sec_attr_stdin.nLength = sizeof(sec_attr_stdin);
+ sec_attr_stdin.bInheritHandle = TRUE;
+ ASSERT_TRUE(::CreatePipe(&child_stdin_read, &child_stdin_write,
+ &sec_attr_stdin, 0));
+ ASSERT_TRUE(::SetHandleInformation(child_stdin_write, HANDLE_FLAG_INHERIT,
+ 0));
+
+ // Startup the child.
+ STARTUPINFO startup_info = {};
+ PROCESS_INFORMATION process_info = {};
+ startup_info.cb = sizeof(STARTUPINFO);
+ startup_info.hStdError = NULL;
+ startup_info.hStdInput = child_stdin_read;
+ startup_info.hStdOutput = child_stdout_write;
+ startup_info.dwFlags = STARTF_USESTDHANDLES;
+ ASSERT_TRUE(::CreateProcessW(NULL, (LPWSTR)command_line.c_str(), NULL, NULL,
+ TRUE, 0, NULL, NULL,
+ &startup_info, &process_info));
+
+ // Collect the output.
+ ASSERT_TRUE(::CloseHandle(child_stdout_write));
+ char buffer[4096] = {};
+ DWORD bytes_read = 0;
+ while (::ReadFile(child_stdout_read, buffer, sizeof(buffer), &bytes_read,
+ NULL) && bytes_read > 0) {
+ stdout_string->append(buffer, bytes_read);
+ }
+
+ // Wait for the process to finish.
+ ::WaitForSingleObject(process_info.hProcess, INFINITE);
+
+ // Shut down all of our handles.
+ ASSERT_TRUE(::CloseHandle(process_info.hThread));
+ ASSERT_TRUE(::CloseHandle(process_info.hProcess));
+ ASSERT_TRUE(::CloseHandle(child_stdin_write));
+ ASSERT_TRUE(::CloseHandle(child_stdin_read));
+ ASSERT_TRUE(::CloseHandle(child_stdout_read));
+}
+
+void GetFileContents(const std::wstring& path, std::string* content) {
+ FILE* f = ::_wfopen(path.c_str(), L"rb");
+ ASSERT_TRUE(f != NULL);
+
+ char buffer[4096] = {};
+ while (true) {
+ size_t bytes_read = ::fread(buffer, 1, sizeof(buffer), f);
+ if (bytes_read == 0)
+ break;
+ content->append(buffer, bytes_read);
+ }
+}
+
+class DumpSymsRegressionTest : public testing::TestWithParam<const wchar_t*> {
+ public:
+ virtual void SetUp() {
+ std::wstring self_dir;
+ ASSERT_TRUE(GetSelfDirectory(&self_dir));
+ dump_syms_exe = self_dir + L"\\dump_syms.exe";
+
+ TrimLastComponent(self_dir, &testdata_dir, NULL);
+ testdata_dir += L"\\testdata";
+ }
+
+ std::wstring dump_syms_exe;
+ std::wstring testdata_dir;
+};
+
+class DumpSymsPEOnlyRegressionTest : public testing::TestWithParam<const wchar_t*> {
+public:
+ virtual void SetUp() {
+ std::wstring self_dir;
+ ASSERT_TRUE(GetSelfDirectory(&self_dir));
+ dump_syms_exe = self_dir + L"\\dump_syms.exe";
+
+ TrimLastComponent(self_dir, &testdata_dir, NULL);
+ testdata_dir += L"\\testdata";
+ }
+
+ std::wstring dump_syms_exe;
+ std::wstring testdata_dir;
+};
+
+} //namespace
+
+TEST_P(DumpSymsRegressionTest, EnsureDumpedSymbolsMatch) {
+ const wchar_t* root_name = GetParam();
+ std::wstring root_path = testdata_dir + L"\\" + root_name;
+
+ std::wstring sym_path = root_path + L".sym";
+ std::string expected_symbols;
+ ASSERT_NO_FATAL_FAILURE(GetFileContents(sym_path, &expected_symbols));
+
+ std::wstring pdb_path = root_path + L".pdb";
+ std::wstring command_line = L"\"" + dump_syms_exe + L"\" \"" +
+ pdb_path + L"\"";
+ std::string symbols;
+ ASSERT_NO_FATAL_FAILURE(RunCommand(command_line, &symbols));
+
+ EXPECT_EQ(expected_symbols, symbols);
+}
+
+INSTANTIATE_TEST_SUITE_P(DumpSyms, DumpSymsRegressionTest,
+ testing::ValuesIn(kRootNames));
+
+TEST_P(DumpSymsPEOnlyRegressionTest, EnsurePEOnlyDumpedSymbolsMatch) {
+ const wchar_t* root_name = GetParam();
+ std::wstring root_path = testdata_dir + L"\\" + root_name;
+
+ std::wstring sym_path = root_path + L".sym";
+ std::string expected_symbols;
+ ASSERT_NO_FATAL_FAILURE(GetFileContents(sym_path, &expected_symbols));
+
+ std::wstring dll_path = root_path + L".dll";
+ std::wstring command_line = L"\"" + dump_syms_exe + L"\" --pe \"" +
+ dll_path + L"\"";
+ std::string symbols;
+ ASSERT_NO_FATAL_FAILURE(RunCommand(command_line, &symbols));
+
+ EXPECT_EQ(expected_symbols, symbols);
+}
+
+INSTANTIATE_TEST_SUITE_P(PEOnlyDumpSyms, DumpSymsPEOnlyRegressionTest,
+ testing::ValuesIn(kPEOnlyRootNames));
+
+
+} // namespace dump_syms
+} // namespace windows
+} // namespace tools
diff --git a/src/tools/windows/dump_syms/run_regtest.sh b/src/tools/windows/dump_syms/run_regtest.sh
index 1f20f64f..2401edd1 100755
--- a/src/tools/windows/dump_syms/run_regtest.sh
+++ b/src/tools/windows/dump_syms/run_regtest.sh
@@ -1,7 +1,6 @@
#!/bin/sh
-# Copyright (c) 2006, Google Inc.
-# All rights reserved.
+# Copyright 2006 Google LLC
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
@@ -13,7 +12,7 @@
# copyright notice, this list of conditions and the following disclaimer
# in the documentation and/or other materials provided with the
# distribution.
-# * Neither the name of Google Inc. nor the names of its
+# * Neither the name of Google LLC nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
diff --git a/src/tools/windows/dump_syms/testdata/dump_syms_regtest.cc b/src/tools/windows/dump_syms/testdata/dump_syms_regtest.cc
index e8efbeb8..442676ba 100644
--- a/src/tools/windows/dump_syms/testdata/dump_syms_regtest.cc
+++ b/src/tools/windows/dump_syms/testdata/dump_syms_regtest.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2007, Google Inc.
-// All rights reserved.
+// Copyright 2007 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -48,7 +47,7 @@ class C {
void f() { member_ = g(); }
virtual int g() { return 2; }
- static char* h(const C &that) { return 0; }
+ static char* h(const C& that) { return 0; }
private:
int member_;
@@ -60,12 +59,12 @@ static int i() {
} // namespace google_breakpad
-int main(int argc, char **argv) {
+int main(int argc, char** argv) {
google_breakpad::C object;
object.set_member(google_breakpad::i());
object.f();
int value = object.g();
- char *nothing = object.h(object);
+ char* nothing = object.h(object);
return 0;
}
diff --git a/src/tools/windows/symupload/symupload.cc b/src/tools/windows/symupload/symupload.cc
index 7e302932..65123a28 100644
--- a/src/tools/windows/symupload/symupload.cc
+++ b/src/tools/windows/symupload/symupload.cc
@@ -1,5 +1,4 @@
-// Copyright (c) 2006, Google Inc.
-// All rights reserved.
+// Copyright 2006 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -11,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
@@ -56,24 +55,23 @@
#include "common/windows/http_upload.h"
#include "common/windows/pdb_source_line_writer.h"
+#include "common/windows/sym_upload_v2_protocol.h"
#include "common/windows/symbol_collector_client.h"
-using std::string;
-using std::wstring;
-using std::vector;
-using std::map;
using google_breakpad::HTTPUpload;
-using google_breakpad::SymbolCollectorClient;
-using google_breakpad::SymbolStatus;
-using google_breakpad::UploadUrlResponse;
-using google_breakpad::CompleteUploadResult;
using google_breakpad::PDBModuleInfo;
using google_breakpad::PDBSourceLineWriter;
using google_breakpad::WindowsStringUtils;
+using std::map;
+using std::string;
+using std::vector;
+using std::wstring;
+
+const wchar_t* kSymbolUploadTypeBreakpad = L"BREAKPAD";
// Extracts the file version information for the given filename,
// as a string, for example, "1.2.3.4". Returns true on success.
-static bool GetFileVersionString(const wchar_t *filename, wstring *version) {
+static bool GetFileVersionString(const wchar_t* filename, wstring* version) {
DWORD handle;
DWORD version_size = GetFileVersionInfoSize(filename, &handle);
if (version_size < sizeof(VS_FIXEDFILEINFO)) {
@@ -85,7 +83,7 @@ static bool GetFileVersionString(const wchar_t *filename, wstring *version) {
return false;
}
- void *file_info_buffer = NULL;
+ void* file_info_buffer = NULL;
unsigned int file_info_length;
if (!VerQueryValue(&version_info[0], L"\\",
&file_info_buffer, &file_info_length)) {
@@ -95,7 +93,7 @@ static bool GetFileVersionString(const wchar_t *filename, wstring *version) {
// The maximum value of each version component is 65535 (0xffff),
// so the max length is 24, including the terminating null.
wchar_t ver_string[24];
- VS_FIXEDFILEINFO *file_info =
+ VS_FIXEDFILEINFO* file_info =
reinterpret_cast<VS_FIXEDFILEINFO*>(file_info_buffer);
swprintf(ver_string, sizeof(ver_string) / sizeof(ver_string[0]),
L"%d.%d.%d.%d",
@@ -114,10 +112,11 @@ static bool GetFileVersionString(const wchar_t *filename, wstring *version) {
// Creates a new temporary file and writes the symbol data from the given
// exe/dll file to it. Returns the path to the temp file in temp_file_path
// and information about the pdb in pdb_info.
-static bool DumpSymbolsToTempFile(const wchar_t *file,
- wstring *temp_file_path,
- PDBModuleInfo *pdb_info) {
- google_breakpad::PDBSourceLineWriter writer;
+static bool DumpSymbolsToTempFile(const wchar_t* file,
+ wstring* temp_file_path,
+ PDBModuleInfo* pdb_info,
+ bool handle_inline) {
+ google_breakpad::PDBSourceLineWriter writer(handle_inline);
// Use EXE_FILE to get information out of the exe/dll in addition to the
// pdb. The name and version number of the exe/dll are of value, and
// there's no way to locate an exe/dll given a pdb.
@@ -135,7 +134,7 @@ static bool DumpSymbolsToTempFile(const wchar_t *file,
return false;
}
- FILE *temp_file = NULL;
+ FILE* temp_file = NULL;
#if _MSC_VER >= 1400 // MSVC 2005/8
if (_wfopen_s(&temp_file, temp_filename, L"w") != 0)
#else // _MSC_VER >= 1400
@@ -159,97 +158,12 @@ static bool DumpSymbolsToTempFile(const wchar_t *file,
return writer.GetModuleInfo(pdb_info);
}
-static bool DoSymUploadV2(
- const wchar_t* api_url,
- const wchar_t* api_key,
- const wstring& debug_file,
- const wstring& debug_id,
- const wstring& symbol_file,
- bool force) {
- wstring url(api_url);
- wstring key(api_key);
-
- if (!force) {
- SymbolStatus symbolStatus = SymbolCollectorClient::CheckSymbolStatus(
- url,
- key,
- debug_file,
- debug_id);
- if (symbolStatus == SymbolStatus::Found) {
- wprintf(L"Symbol file already exists, upload aborted."
- L" Use \"-f\" to overwrite.\n");
- return true;
- }
- else if (symbolStatus == SymbolStatus::Unknown) {
- wprintf(L"Failed to get check for existing symbol.\n");
- return false;
- }
- }
-
- UploadUrlResponse uploadUrlResponse;
- if (!SymbolCollectorClient::CreateUploadUrl(
- url,
- key,
- &uploadUrlResponse)) {
- wprintf(L"Failed to create upload URL.\n");
- return false;
- }
-
- wstring signed_url = uploadUrlResponse.upload_url;
- wstring upload_key = uploadUrlResponse.upload_key;
- wstring response;
- int response_code;
- bool success = HTTPUpload::SendPutRequest(
- signed_url,
- symbol_file,
- /* timeout = */ NULL,
- &response,
- &response_code);
- if (!success) {
- wprintf(L"Failed to send symbol file.\n");
- wprintf(L"Response code: %ld\n", response_code);
- wprintf(L"Response:\n");
- wprintf(L"%s\n", response.c_str());
- return false;
- }
- else if (response_code == 0) {
- wprintf(L"Failed to send symbol file: No response code\n");
- return false;
- }
- else if (response_code != 200) {
- wprintf(L"Failed to send symbol file: Response code %ld\n", response_code);
- wprintf(L"Response:\n");
- wprintf(L"%s\n", response.c_str());
- return false;
- }
-
- CompleteUploadResult completeUploadResult =
- SymbolCollectorClient::CompleteUpload(
- url,
- key,
- upload_key,
- debug_file,
- debug_id);
- if (completeUploadResult == CompleteUploadResult::Error) {
- wprintf(L"Failed to complete upload.\n");
- return false;
- }
- else if (completeUploadResult == CompleteUploadResult::DuplicateData) {
- wprintf(L"Uploaded file checksum matched existing file checksum,"
- L" no change necessary.\n");
- }
- else {
- wprintf(L"Successfully sent the symbol file.\n");
- }
-
- return true;
-}
-
__declspec(noreturn) void printUsageAndExit() {
wprintf(L"Usage:\n\n"
- L" symupload [--timeout NN] [--product product_name] ^\n"
+ L" symupload [--i] [--timeout NN] [--product product_name] ^\n"
L" <file.exe|file.dll> <symbol upload URL> ^\n"
L" [...<symbol upload URLs>]\n\n");
+ wprintf(L" - i: Extract inline information from pdb.\n");
wprintf(L" - Timeout is in milliseconds, or can be 0 to be unlimited.\n");
wprintf(L" - product_name is an HTTP-friendly product name. It must only\n"
L" contain an ascii subset: alphanumeric and punctuation.\n"
@@ -270,9 +184,10 @@ __declspec(noreturn) void printUsageAndExit() {
exit(0);
}
-int wmain(int argc, wchar_t *argv[]) {
- const wchar_t *module;
- const wchar_t *product = nullptr;
+int wmain(int argc, wchar_t* argv[]) {
+ const wchar_t* module;
+ const wchar_t* product = nullptr;
+ bool handle_inline = false;
int timeout = -1;
int currentarg = 1;
bool use_sym_upload_v2 = false;
@@ -280,6 +195,11 @@ int wmain(int argc, wchar_t *argv[]) {
const wchar_t* api_url = nullptr;
const wchar_t* api_key = nullptr;
while (argc > currentarg + 1) {
+ if (!wcscmp(L"--i", argv[currentarg])) {
+ handle_inline = true;
+ ++currentarg;
+ continue;
+ }
if (!wcscmp(L"--timeout", argv[currentarg])) {
timeout = _wtoi(argv[currentarg + 1]);
currentarg += 2;
@@ -310,7 +230,7 @@ int wmain(int argc, wchar_t *argv[]) {
wstring symbol_file;
PDBModuleInfo pdb_info;
- if (!DumpSymbolsToTempFile(module, &symbol_file, &pdb_info)) {
+ if (!DumpSymbolsToTempFile(module, &symbol_file, &pdb_info, handle_inline)) {
fwprintf(stderr, L"Could not get symbol data from %s\n", module);
return 1;
}
@@ -329,14 +249,12 @@ int wmain(int argc, wchar_t *argv[]) {
if (argc >= currentarg + 2) {
api_url = argv[currentarg++];
api_key = argv[currentarg++];
+ wstring product_name = product ? wstring(product) : L"";
- success = DoSymUploadV2(
- api_url,
- api_key,
- pdb_info.debug_file,
- pdb_info.debug_identifier,
- symbol_file,
- force);
+ success = google_breakpad::SymUploadV2ProtocolSend(
+ api_url, api_key, timeout == -1 ? nullptr : &timeout,
+ pdb_info.debug_file, pdb_info.debug_identifier, symbol_file,
+ kSymbolUploadTypeBreakpad, product_name, force);
} else {
printUsageAndExit();
}
diff --git a/src/tools/windows/symupload/symupload.gyp b/src/tools/windows/symupload/symupload.gyp
deleted file mode 100644
index 4567a4bd..00000000
--- a/src/tools/windows/symupload/symupload.gyp
+++ /dev/null
@@ -1,50 +0,0 @@
-# Copyright 2013 Google Inc. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-# * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-# * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-{
- 'includes': [
- '../../../build/common.gypi',
- ],
- 'targets': [
- {
- 'target_name': 'symupload',
- 'type': 'executable',
- 'sources': [
- 'symupload.cc',
- ],
- 'dependencies': [
- '../../../common/windows/common_windows.gyp:common_windows_lib',
- ],
- 'msvs_settings': {
- 'VCLinkerTool': {
- 'LargeAddressAware': '2',
- },
- },
- },
- ],
-}
diff --git a/src/tools/windows/tools_windows.gyp b/src/tools/windows/tools_windows.gyp
deleted file mode 100644
index 17b88b4a..00000000
--- a/src/tools/windows/tools_windows.gyp
+++ /dev/null
@@ -1,46 +0,0 @@
-# Copyright 2017 Google Inc. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-# * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-# * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-
-{
- 'includes': [
- '../../build/common.gypi',
- ],
- 'targets': [
- {
- 'target_name': 'build_all',
- 'type': 'none',
- 'dependencies': [
- './converter/ms_symbol_server_converter.gyp:*',
- './converter_exe/converter.gyp:*',
- './dump_syms/dump_syms.gyp:*',
- './symupload/symupload.gyp:*',
- ],
- },
- ],
-}