# HG changeset patch # User Ted Mielczarek # Date 1360255134 18000 # Node ID d7bfb673574a3afe8b4f76f42fb52e2545770dad # Parent d23a69a6c34a1f1c21e241f37b388c8689f2386b Rework PostfixEvaluator to use a UniqueString type Patch by Julian Seward , R=ted diff --git a/Makefile.am b/Makefile.am --- a/Makefile.am +++ b/Makefile.am @@ -134,16 +134,17 @@ src/google_breakpad/processor/source_line_resolver_interface.h \ src/google_breakpad/processor/stack_frame.h \ src/google_breakpad/processor/stack_frame_cpu.h \ src/google_breakpad/processor/stack_frame_symbolizer.h \ src/google_breakpad/processor/stackwalker.h \ src/google_breakpad/processor/symbol_supplier.h \ src/google_breakpad/processor/system_info.h \ src/common/module.cc \ + src/common/unique_string.cc \ src/processor/address_map-inl.h \ src/processor/address_map.h \ src/processor/basic_code_module.h \ src/processor/basic_code_modules.cc \ src/processor/basic_code_modules.h \ src/processor/basic_source_line_resolver_types.h \ src/processor/basic_source_line_resolver.cc \ src/processor/binarystream.h \ @@ -426,16 +427,17 @@ src_tools_linux_dump_syms_dump_syms_SOURCES = \ src/common/dwarf_cfi_to_module.cc \ src/common/dwarf_cu_to_module.cc \ src/common/dwarf_line_to_module.cc \ src/common/language.cc \ src/common/module.cc \ src/common/stabs_reader.cc \ src/common/stabs_to_module.cc \ + src/common/unique_string.cc \ src/common/dwarf/bytereader.cc \ src/common/dwarf/dwarf2diehandler.cc \ src/common/dwarf/dwarf2reader.cc \ src/common/linux/dump_symbols.cc \ src/common/linux/elf_symbols_to_module.cc \ src/common/linux/elfutils.cc \ src/common/linux/file_id.cc \ src/common/linux/linux_libc_support.cc \ @@ -469,16 +471,17 @@ src/common/memory_range_unittest.cc \ src/common/module.cc \ src/common/module_unittest.cc \ src/common/stabs_reader.cc \ src/common/stabs_reader_unittest.cc \ src/common/stabs_to_module.cc \ src/common/stabs_to_module_unittest.cc \ src/common/test_assembler.cc \ + src/common/unique_string.cc \ src/common/dwarf/bytereader.cc \ src/common/dwarf/bytereader_unittest.cc \ src/common/dwarf/cfi_assembler.cc \ src/common/dwarf/dwarf2diehandler.cc \ src/common/dwarf/dwarf2diehandler_unittest.cc \ src/common/dwarf/dwarf2reader.cc \ src/common/dwarf/dwarf2reader_cfi_unittest.cc \ src/common/dwarf/dwarf2reader_die_unittest.cc \ @@ -557,31 +560,33 @@ src_processor_basic_source_line_resolver_unittest_CPPFLAGS = \ -I$(top_srcdir)/src \ -I$(top_srcdir)/src/testing/include \ -I$(top_srcdir)/src/testing/gtest/include \ -I$(top_srcdir)/src/testing/gtest \ -I$(top_srcdir)/src/testing src_processor_basic_source_line_resolver_unittest_LDADD = \ src/common/module.o \ + src/common/unique_string.o \ src/processor/basic_source_line_resolver.o \ src/processor/cfi_frame_info.o \ src/processor/pathname_stripper.o \ src/processor/logging.o \ src/processor/source_line_resolver_base.o \ src/processor/tokenize.o \ $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) src_processor_cfi_frame_info_unittest_SOURCES = \ src/processor/cfi_frame_info_unittest.cc \ src/testing/gtest/src/gtest-all.cc \ src/testing/gtest/src/gtest_main.cc \ src/testing/src/gmock-all.cc src_processor_cfi_frame_info_unittest_LDADD = \ src/common/module.o \ + src/common/unique_string.o \ src/processor/cfi_frame_info.o \ src/processor/logging.o \ src/processor/pathname_stripper.o \ $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) src_processor_cfi_frame_info_unittest_CPPFLAGS = \ -I$(top_srcdir)/src \ -I$(top_srcdir)/src/testing/include \ -I$(top_srcdir)/src/testing/gtest/include \ @@ -602,16 +607,17 @@ src_processor_exploitability_unittest_CPPFLAGS = \ -I$(top_srcdir)/src \ -I$(top_srcdir)/src/testing/include \ -I$(top_srcdir)/src/testing/gtest/include \ -I$(top_srcdir)/src/testing/gtest \ -I$(top_srcdir)/src/testing src_processor_exploitability_unittest_LDADD = \ src/common/module.o \ + src/common/unique_string.o \ src/processor/minidump_processor.o \ src/processor/process_state.o \ src/processor/disassembler_x86.o \ src/processor/exploitability.o \ src/processor/exploitability_win.o \ src/processor/basic_code_modules.o \ src/processor/basic_source_line_resolver.o \ src/processor/call_stack.o \ @@ -654,16 +660,17 @@ src_processor_fast_source_line_resolver_unittest_CPPFLAGS = \ -I$(top_srcdir)/src \ -I$(top_srcdir)/src/testing/include \ -I$(top_srcdir)/src/testing/gtest/include \ -I$(top_srcdir)/src/testing/gtest \ -I$(top_srcdir)/src/testing src_processor_fast_source_line_resolver_unittest_LDADD = \ src/common/module.o \ + src/common/unique_string.o \ src/processor/fast_source_line_resolver.o \ src/processor/basic_source_line_resolver.o \ src/processor/cfi_frame_info.o \ src/processor/module_comparer.o \ src/processor/module_serializer.o \ src/processor/pathname_stripper.o \ src/processor/logging.o \ src/processor/source_line_resolver_base.o \ @@ -692,16 +699,17 @@ src_processor_minidump_processor_unittest_CPPFLAGS = \ -I$(top_srcdir)/src \ -I$(top_srcdir)/src/testing/include \ -I$(top_srcdir)/src/testing/gtest/include \ -I$(top_srcdir)/src/testing/gtest \ -I$(top_srcdir)/src/testing src_processor_minidump_processor_unittest_LDADD = \ src/common/module.o \ + src/common/unique_string.o \ src/processor/basic_code_modules.o \ src/processor/basic_source_line_resolver.o \ src/processor/call_stack.o \ src/processor/cfi_frame_info.o \ src/processor/disassembler_x86.o \ src/processor/exploitability.o \ src/processor/exploitability_win.o \ src/processor/logging.o \ @@ -806,16 +814,17 @@ src_processor_pathname_stripper_unittest_LDADD = \ src/processor/pathname_stripper.o \ $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) src_processor_postfix_evaluator_unittest_SOURCES = \ src/processor/postfix_evaluator_unittest.cc src_processor_postfix_evaluator_unittest_LDADD = \ src/common/module.o \ + src/common/unique_string.o \ src/processor/logging.o \ src/processor/pathname_stripper.o \ $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) src_processor_range_map_unittest_SOURCES = \ src/processor/range_map_unittest.cc src_processor_range_map_unittest_LDADD = \ src/processor/logging.o \ @@ -936,16 +945,17 @@ src/processor/logging.o \ src/processor/minidump.o \ src/processor/pathname_stripper.o src_processor_minidump_stackwalk_SOURCES = \ src/processor/minidump_stackwalk.cc src_processor_minidump_stackwalk_LDADD = \ src/common/module.o \ + src/common/unique_string.o \ src/processor/basic_code_modules.o \ src/processor/basic_source_line_resolver.o \ src/processor/binarystream.o \ src/processor/call_stack.o \ src/processor/cfi_frame_info.o \ src/processor/disassembler_x86.o \ src/processor/exploitability.o \ src/processor/exploitability_win.o \ diff --git a/Makefile.in b/Makefile.in --- a/Makefile.in +++ b/Makefile.in @@ -267,18 +267,19 @@ src/google_breakpad/processor/source_line_resolver_base.h \ src/google_breakpad/processor/source_line_resolver_interface.h \ src/google_breakpad/processor/stack_frame.h \ src/google_breakpad/processor/stack_frame_cpu.h \ src/google_breakpad/processor/stack_frame_symbolizer.h \ src/google_breakpad/processor/stackwalker.h \ src/google_breakpad/processor/symbol_supplier.h \ src/google_breakpad/processor/system_info.h \ - src/common/module.cc src/processor/address_map-inl.h \ - src/processor/address_map.h src/processor/basic_code_module.h \ + src/common/module.cc src/common/unique_string.cc \ + src/processor/address_map-inl.h src/processor/address_map.h \ + src/processor/basic_code_module.h \ src/processor/basic_code_modules.cc \ src/processor/basic_code_modules.h \ src/processor/basic_source_line_resolver_types.h \ src/processor/basic_source_line_resolver.cc \ src/processor/binarystream.h src/processor/binarystream.cc \ src/processor/call_stack.cc src/processor/cfi_frame_info.cc \ src/processor/cfi_frame_info.h \ src/processor/contained_range_map-inl.h \ @@ -330,16 +331,17 @@ src/processor/static_map_iterator-inl.h \ src/processor/static_map_iterator.h \ src/processor/static_map-inl.h src/processor/static_map.h \ src/processor/static_range_map-inl.h \ src/processor/static_range_map.h src/processor/tokenize.cc \ src/processor/tokenize.h @DISABLE_PROCESSOR_FALSE@am_src_libbreakpad_a_OBJECTS = \ @DISABLE_PROCESSOR_FALSE@ src/common/module.$(OBJEXT) \ +@DISABLE_PROCESSOR_FALSE@ src/common/unique_string.$(OBJEXT) \ @DISABLE_PROCESSOR_FALSE@ src/processor/basic_code_modules.$(OBJEXT) \ @DISABLE_PROCESSOR_FALSE@ src/processor/basic_source_line_resolver.$(OBJEXT) \ @DISABLE_PROCESSOR_FALSE@ src/processor/binarystream.$(OBJEXT) \ @DISABLE_PROCESSOR_FALSE@ src/processor/call_stack.$(OBJEXT) \ @DISABLE_PROCESSOR_FALSE@ src/processor/cfi_frame_info.$(OBJEXT) \ @DISABLE_PROCESSOR_FALSE@ src/processor/disassembler_x86.$(OBJEXT) \ @DISABLE_PROCESSOR_FALSE@ src/processor/exploitability.$(OBJEXT) \ @DISABLE_PROCESSOR_FALSE@ src/processor/exploitability_win.$(OBJEXT) \ @@ -518,17 +520,18 @@ src/common/dwarf_cu_to_module_unittest.cc \ src/common/dwarf_line_to_module.cc \ src/common/dwarf_line_to_module_unittest.cc \ src/common/language.cc src/common/memory_range_unittest.cc \ src/common/module.cc src/common/module_unittest.cc \ src/common/stabs_reader.cc src/common/stabs_reader_unittest.cc \ src/common/stabs_to_module.cc \ src/common/stabs_to_module_unittest.cc \ - src/common/test_assembler.cc src/common/dwarf/bytereader.cc \ + src/common/test_assembler.cc src/common/unique_string.cc \ + src/common/dwarf/bytereader.cc \ src/common/dwarf/bytereader_unittest.cc \ src/common/dwarf/cfi_assembler.cc \ src/common/dwarf/dwarf2diehandler.cc \ src/common/dwarf/dwarf2diehandler_unittest.cc \ src/common/dwarf/dwarf2reader.cc \ src/common/dwarf/dwarf2reader_cfi_unittest.cc \ src/common/dwarf/dwarf2reader_die_unittest.cc \ src/common/linux/dump_symbols.cc \ @@ -562,16 +565,17 @@ @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/src_common_dumper_unittest-memory_range_unittest.$(OBJEXT) \ @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/src_common_dumper_unittest-module.$(OBJEXT) \ @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/src_common_dumper_unittest-module_unittest.$(OBJEXT) \ @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/src_common_dumper_unittest-stabs_reader.$(OBJEXT) \ @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/src_common_dumper_unittest-stabs_reader_unittest.$(OBJEXT) \ @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/src_common_dumper_unittest-stabs_to_module.$(OBJEXT) \ @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/src_common_dumper_unittest-stabs_to_module_unittest.$(OBJEXT) \ @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/src_common_dumper_unittest-test_assembler.$(OBJEXT) \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/src_common_dumper_unittest-unique_string.$(OBJEXT) \ @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/src_common_dumper_unittest-bytereader.$(OBJEXT) \ @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/src_common_dumper_unittest-bytereader_unittest.$(OBJEXT) \ @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/src_common_dumper_unittest-cfi_assembler.$(OBJEXT) \ @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/src_common_dumper_unittest-dwarf2diehandler.$(OBJEXT) \ @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/src_common_dumper_unittest-dwarf2diehandler_unittest.$(OBJEXT) \ @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/src_common_dumper_unittest-dwarf2reader.$(OBJEXT) \ @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/src_common_dumper_unittest-dwarf2reader_cfi_unittest.$(OBJEXT) \ @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/src_common_dumper_unittest-dwarf2reader_die_unittest.$(OBJEXT) \ @@ -630,16 +634,17 @@ src/testing/gtest/src/gtest-all.cc \ src/testing/src/gmock-all.cc @DISABLE_PROCESSOR_FALSE@am_src_processor_basic_source_line_resolver_unittest_OBJECTS = src/processor/src_processor_basic_source_line_resolver_unittest-basic_source_line_resolver_unittest.$(OBJEXT) \ @DISABLE_PROCESSOR_FALSE@ src/testing/gtest/src/src_processor_basic_source_line_resolver_unittest-gtest-all.$(OBJEXT) \ @DISABLE_PROCESSOR_FALSE@ src/testing/src/src_processor_basic_source_line_resolver_unittest-gmock-all.$(OBJEXT) src_processor_basic_source_line_resolver_unittest_OBJECTS = $(am_src_processor_basic_source_line_resolver_unittest_OBJECTS) @DISABLE_PROCESSOR_FALSE@src_processor_basic_source_line_resolver_unittest_DEPENDENCIES = \ @DISABLE_PROCESSOR_FALSE@ src/common/module.o \ +@DISABLE_PROCESSOR_FALSE@ src/common/unique_string.o \ @DISABLE_PROCESSOR_FALSE@ src/processor/basic_source_line_resolver.o \ @DISABLE_PROCESSOR_FALSE@ src/processor/cfi_frame_info.o \ @DISABLE_PROCESSOR_FALSE@ src/processor/pathname_stripper.o \ @DISABLE_PROCESSOR_FALSE@ src/processor/logging.o \ @DISABLE_PROCESSOR_FALSE@ src/processor/source_line_resolver_base.o \ @DISABLE_PROCESSOR_FALSE@ src/processor/tokenize.o \ @DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_1) \ @DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_1) @@ -664,16 +669,17 @@ @DISABLE_PROCESSOR_FALSE@am_src_processor_cfi_frame_info_unittest_OBJECTS = src/processor/src_processor_cfi_frame_info_unittest-cfi_frame_info_unittest.$(OBJEXT) \ @DISABLE_PROCESSOR_FALSE@ src/testing/gtest/src/src_processor_cfi_frame_info_unittest-gtest-all.$(OBJEXT) \ @DISABLE_PROCESSOR_FALSE@ src/testing/gtest/src/src_processor_cfi_frame_info_unittest-gtest_main.$(OBJEXT) \ @DISABLE_PROCESSOR_FALSE@ src/testing/src/src_processor_cfi_frame_info_unittest-gmock-all.$(OBJEXT) src_processor_cfi_frame_info_unittest_OBJECTS = \ $(am_src_processor_cfi_frame_info_unittest_OBJECTS) @DISABLE_PROCESSOR_FALSE@src_processor_cfi_frame_info_unittest_DEPENDENCIES = \ @DISABLE_PROCESSOR_FALSE@ src/common/module.o \ +@DISABLE_PROCESSOR_FALSE@ src/common/unique_string.o \ @DISABLE_PROCESSOR_FALSE@ src/processor/cfi_frame_info.o \ @DISABLE_PROCESSOR_FALSE@ src/processor/logging.o \ @DISABLE_PROCESSOR_FALSE@ src/processor/pathname_stripper.o \ @DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_1) \ @DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_1) am__src_processor_contained_range_map_unittest_SOURCES_DIST = \ src/processor/contained_range_map_unittest.cc @DISABLE_PROCESSOR_FALSE@am_src_processor_contained_range_map_unittest_OBJECTS = src/processor/contained_range_map_unittest.$(OBJEXT) @@ -706,16 +712,17 @@ @DISABLE_PROCESSOR_FALSE@am_src_processor_exploitability_unittest_OBJECTS = src/processor/src_processor_exploitability_unittest-exploitability_unittest.$(OBJEXT) \ @DISABLE_PROCESSOR_FALSE@ src/testing/gtest/src/src_processor_exploitability_unittest-gtest-all.$(OBJEXT) \ @DISABLE_PROCESSOR_FALSE@ src/testing/gtest/src/src_processor_exploitability_unittest-gtest_main.$(OBJEXT) \ @DISABLE_PROCESSOR_FALSE@ src/testing/src/src_processor_exploitability_unittest-gmock-all.$(OBJEXT) src_processor_exploitability_unittest_OBJECTS = \ $(am_src_processor_exploitability_unittest_OBJECTS) @DISABLE_PROCESSOR_FALSE@src_processor_exploitability_unittest_DEPENDENCIES = \ @DISABLE_PROCESSOR_FALSE@ src/common/module.o \ +@DISABLE_PROCESSOR_FALSE@ src/common/unique_string.o \ @DISABLE_PROCESSOR_FALSE@ src/processor/minidump_processor.o \ @DISABLE_PROCESSOR_FALSE@ src/processor/process_state.o \ @DISABLE_PROCESSOR_FALSE@ src/processor/disassembler_x86.o \ @DISABLE_PROCESSOR_FALSE@ src/processor/exploitability.o \ @DISABLE_PROCESSOR_FALSE@ src/processor/exploitability_win.o \ @DISABLE_PROCESSOR_FALSE@ src/processor/basic_code_modules.o \ @DISABLE_PROCESSOR_FALSE@ src/processor/basic_source_line_resolver.o \ @DISABLE_PROCESSOR_FALSE@ src/processor/call_stack.o \ @@ -740,16 +747,17 @@ src/testing/gtest/src/gtest-all.cc \ src/testing/src/gmock-all.cc @DISABLE_PROCESSOR_FALSE@am_src_processor_fast_source_line_resolver_unittest_OBJECTS = src/processor/src_processor_fast_source_line_resolver_unittest-fast_source_line_resolver_unittest.$(OBJEXT) \ @DISABLE_PROCESSOR_FALSE@ src/testing/gtest/src/src_processor_fast_source_line_resolver_unittest-gtest-all.$(OBJEXT) \ @DISABLE_PROCESSOR_FALSE@ src/testing/src/src_processor_fast_source_line_resolver_unittest-gmock-all.$(OBJEXT) src_processor_fast_source_line_resolver_unittest_OBJECTS = $(am_src_processor_fast_source_line_resolver_unittest_OBJECTS) @DISABLE_PROCESSOR_FALSE@src_processor_fast_source_line_resolver_unittest_DEPENDENCIES = \ @DISABLE_PROCESSOR_FALSE@ src/common/module.o \ +@DISABLE_PROCESSOR_FALSE@ src/common/unique_string.o \ @DISABLE_PROCESSOR_FALSE@ src/processor/fast_source_line_resolver.o \ @DISABLE_PROCESSOR_FALSE@ src/processor/basic_source_line_resolver.o \ @DISABLE_PROCESSOR_FALSE@ src/processor/cfi_frame_info.o \ @DISABLE_PROCESSOR_FALSE@ src/processor/module_comparer.o \ @DISABLE_PROCESSOR_FALSE@ src/processor/module_serializer.o \ @DISABLE_PROCESSOR_FALSE@ src/processor/pathname_stripper.o \ @DISABLE_PROCESSOR_FALSE@ src/processor/logging.o \ @DISABLE_PROCESSOR_FALSE@ src/processor/source_line_resolver_base.o \ @@ -786,16 +794,17 @@ src/testing/src/gmock-all.cc @DISABLE_PROCESSOR_FALSE@am_src_processor_minidump_processor_unittest_OBJECTS = src/processor/src_processor_minidump_processor_unittest-minidump_processor_unittest.$(OBJEXT) \ @DISABLE_PROCESSOR_FALSE@ src/testing/gtest/src/src_processor_minidump_processor_unittest-gtest-all.$(OBJEXT) \ @DISABLE_PROCESSOR_FALSE@ src/testing/src/src_processor_minidump_processor_unittest-gmock-all.$(OBJEXT) src_processor_minidump_processor_unittest_OBJECTS = \ $(am_src_processor_minidump_processor_unittest_OBJECTS) @DISABLE_PROCESSOR_FALSE@src_processor_minidump_processor_unittest_DEPENDENCIES = \ @DISABLE_PROCESSOR_FALSE@ src/common/module.o \ +@DISABLE_PROCESSOR_FALSE@ src/common/unique_string.o \ @DISABLE_PROCESSOR_FALSE@ src/processor/basic_code_modules.o \ @DISABLE_PROCESSOR_FALSE@ src/processor/basic_source_line_resolver.o \ @DISABLE_PROCESSOR_FALSE@ src/processor/call_stack.o \ @DISABLE_PROCESSOR_FALSE@ src/processor/cfi_frame_info.o \ @DISABLE_PROCESSOR_FALSE@ src/processor/disassembler_x86.o \ @DISABLE_PROCESSOR_FALSE@ src/processor/exploitability.o \ @DISABLE_PROCESSOR_FALSE@ src/processor/exploitability_win.o \ @DISABLE_PROCESSOR_FALSE@ src/processor/logging.o \ @@ -817,16 +826,17 @@ @DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_1) am__src_processor_minidump_stackwalk_SOURCES_DIST = \ src/processor/minidump_stackwalk.cc @DISABLE_PROCESSOR_FALSE@am_src_processor_minidump_stackwalk_OBJECTS = src/processor/minidump_stackwalk.$(OBJEXT) src_processor_minidump_stackwalk_OBJECTS = \ $(am_src_processor_minidump_stackwalk_OBJECTS) @DISABLE_PROCESSOR_FALSE@src_processor_minidump_stackwalk_DEPENDENCIES = \ @DISABLE_PROCESSOR_FALSE@ src/common/module.o \ +@DISABLE_PROCESSOR_FALSE@ src/common/unique_string.o \ @DISABLE_PROCESSOR_FALSE@ src/processor/basic_code_modules.o \ @DISABLE_PROCESSOR_FALSE@ src/processor/basic_source_line_resolver.o \ @DISABLE_PROCESSOR_FALSE@ src/processor/binarystream.o \ @DISABLE_PROCESSOR_FALSE@ src/processor/call_stack.o \ @DISABLE_PROCESSOR_FALSE@ src/processor/cfi_frame_info.o \ @DISABLE_PROCESSOR_FALSE@ src/processor/disassembler_x86.o \ @DISABLE_PROCESSOR_FALSE@ src/processor/exploitability.o \ @DISABLE_PROCESSOR_FALSE@ src/processor/exploitability_win.o \ @@ -879,16 +889,17 @@ @DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_1) am__src_processor_postfix_evaluator_unittest_SOURCES_DIST = \ src/processor/postfix_evaluator_unittest.cc @DISABLE_PROCESSOR_FALSE@am_src_processor_postfix_evaluator_unittest_OBJECTS = src/processor/postfix_evaluator_unittest.$(OBJEXT) src_processor_postfix_evaluator_unittest_OBJECTS = \ $(am_src_processor_postfix_evaluator_unittest_OBJECTS) @DISABLE_PROCESSOR_FALSE@src_processor_postfix_evaluator_unittest_DEPENDENCIES = \ @DISABLE_PROCESSOR_FALSE@ src/common/module.o \ +@DISABLE_PROCESSOR_FALSE@ src/common/unique_string.o \ @DISABLE_PROCESSOR_FALSE@ src/processor/logging.o \ @DISABLE_PROCESSOR_FALSE@ src/processor/pathname_stripper.o \ @DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_1) \ @DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_1) am__src_processor_range_map_unittest_SOURCES_DIST = \ src/processor/range_map_unittest.cc @DISABLE_PROCESSOR_FALSE@am_src_processor_range_map_unittest_OBJECTS = src/processor/range_map_unittest.$(OBJEXT) src_processor_range_map_unittest_OBJECTS = \ @@ -1058,33 +1069,35 @@ src_tools_linux_core2md_core2md_OBJECTS = \ $(am_src_tools_linux_core2md_core2md_OBJECTS) @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@src_tools_linux_core2md_core2md_DEPENDENCIES = src/client/linux/libbreakpad_client.a am__src_tools_linux_dump_syms_dump_syms_SOURCES_DIST = \ src/common/dwarf_cfi_to_module.cc \ src/common/dwarf_cu_to_module.cc \ src/common/dwarf_line_to_module.cc src/common/language.cc \ src/common/module.cc src/common/stabs_reader.cc \ - src/common/stabs_to_module.cc src/common/dwarf/bytereader.cc \ + src/common/stabs_to_module.cc src/common/unique_string.cc \ + src/common/dwarf/bytereader.cc \ src/common/dwarf/dwarf2diehandler.cc \ src/common/dwarf/dwarf2reader.cc \ src/common/linux/dump_symbols.cc \ src/common/linux/elf_symbols_to_module.cc \ src/common/linux/elfutils.cc src/common/linux/file_id.cc \ src/common/linux/linux_libc_support.cc \ src/common/linux/memory_mapped_file.cc \ src/common/linux/safe_readlink.cc \ src/tools/linux/dump_syms/dump_syms.cc @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@am_src_tools_linux_dump_syms_dump_syms_OBJECTS = src/common/dwarf_cfi_to_module.$(OBJEXT) \ @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf_cu_to_module.$(OBJEXT) \ @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf_line_to_module.$(OBJEXT) \ @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/language.$(OBJEXT) \ @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/module.$(OBJEXT) \ @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/stabs_reader.$(OBJEXT) \ @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/stabs_to_module.$(OBJEXT) \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/unique_string.$(OBJEXT) \ @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/bytereader.$(OBJEXT) \ @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/dwarf2diehandler.$(OBJEXT) \ @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/dwarf2reader.$(OBJEXT) \ @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/dump_symbols.$(OBJEXT) \ @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/elf_symbols_to_module.$(OBJEXT) \ @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/elfutils.$(OBJEXT) \ @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/file_id.$(OBJEXT) \ @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/linux_libc_support.$(OBJEXT) \ @@ -1405,16 +1418,17 @@ @DISABLE_PROCESSOR_FALSE@ src/google_breakpad/processor/source_line_resolver_interface.h \ @DISABLE_PROCESSOR_FALSE@ src/google_breakpad/processor/stack_frame.h \ @DISABLE_PROCESSOR_FALSE@ src/google_breakpad/processor/stack_frame_cpu.h \ @DISABLE_PROCESSOR_FALSE@ src/google_breakpad/processor/stack_frame_symbolizer.h \ @DISABLE_PROCESSOR_FALSE@ src/google_breakpad/processor/stackwalker.h \ @DISABLE_PROCESSOR_FALSE@ src/google_breakpad/processor/symbol_supplier.h \ @DISABLE_PROCESSOR_FALSE@ src/google_breakpad/processor/system_info.h \ @DISABLE_PROCESSOR_FALSE@ src/common/module.cc \ +@DISABLE_PROCESSOR_FALSE@ src/common/unique_string.cc \ @DISABLE_PROCESSOR_FALSE@ src/processor/address_map-inl.h \ @DISABLE_PROCESSOR_FALSE@ src/processor/address_map.h \ @DISABLE_PROCESSOR_FALSE@ src/processor/basic_code_module.h \ @DISABLE_PROCESSOR_FALSE@ src/processor/basic_code_modules.cc \ @DISABLE_PROCESSOR_FALSE@ src/processor/basic_code_modules.h \ @DISABLE_PROCESSOR_FALSE@ src/processor/basic_source_line_resolver_types.h \ @DISABLE_PROCESSOR_FALSE@ src/processor/basic_source_line_resolver.cc \ @DISABLE_PROCESSOR_FALSE@ src/processor/binarystream.h \ @@ -1603,16 +1617,17 @@ @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@src_tools_linux_dump_syms_dump_syms_SOURCES = \ @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf_cfi_to_module.cc \ @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf_cu_to_module.cc \ @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf_line_to_module.cc \ @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/language.cc \ @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/module.cc \ @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/stabs_reader.cc \ @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/stabs_to_module.cc \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/unique_string.cc \ @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/bytereader.cc \ @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/dwarf2diehandler.cc \ @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/dwarf2reader.cc \ @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/dump_symbols.cc \ @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/elf_symbols_to_module.cc \ @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/elfutils.cc \ @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/file_id.cc \ @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/linux_libc_support.cc \ @@ -1646,16 +1661,17 @@ @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/memory_range_unittest.cc \ @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/module.cc \ @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/module_unittest.cc \ @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/stabs_reader.cc \ @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/stabs_reader_unittest.cc \ @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/stabs_to_module.cc \ @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/stabs_to_module_unittest.cc \ @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/test_assembler.cc \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/unique_string.cc \ @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/bytereader.cc \ @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/bytereader_unittest.cc \ @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/cfi_assembler.cc \ @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/dwarf2diehandler.cc \ @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/dwarf2diehandler_unittest.cc \ @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/dwarf2reader.cc \ @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/dwarf2reader_cfi_unittest.cc \ @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/dwarf2reader_die_unittest.cc \ @@ -1738,32 +1754,34 @@ @DISABLE_PROCESSOR_FALSE@ -I$(top_srcdir)/src \ @DISABLE_PROCESSOR_FALSE@ -I$(top_srcdir)/src/testing/include \ @DISABLE_PROCESSOR_FALSE@ -I$(top_srcdir)/src/testing/gtest/include \ @DISABLE_PROCESSOR_FALSE@ -I$(top_srcdir)/src/testing/gtest \ @DISABLE_PROCESSOR_FALSE@ -I$(top_srcdir)/src/testing @DISABLE_PROCESSOR_FALSE@src_processor_basic_source_line_resolver_unittest_LDADD = \ @DISABLE_PROCESSOR_FALSE@ src/common/module.o \ +@DISABLE_PROCESSOR_FALSE@ src/common/unique_string.o \ @DISABLE_PROCESSOR_FALSE@ src/processor/basic_source_line_resolver.o \ @DISABLE_PROCESSOR_FALSE@ src/processor/cfi_frame_info.o \ @DISABLE_PROCESSOR_FALSE@ src/processor/pathname_stripper.o \ @DISABLE_PROCESSOR_FALSE@ src/processor/logging.o \ @DISABLE_PROCESSOR_FALSE@ src/processor/source_line_resolver_base.o \ @DISABLE_PROCESSOR_FALSE@ src/processor/tokenize.o \ @DISABLE_PROCESSOR_FALSE@ $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) @DISABLE_PROCESSOR_FALSE@src_processor_cfi_frame_info_unittest_SOURCES = \ @DISABLE_PROCESSOR_FALSE@ src/processor/cfi_frame_info_unittest.cc \ @DISABLE_PROCESSOR_FALSE@ src/testing/gtest/src/gtest-all.cc \ @DISABLE_PROCESSOR_FALSE@ src/testing/gtest/src/gtest_main.cc \ @DISABLE_PROCESSOR_FALSE@ src/testing/src/gmock-all.cc @DISABLE_PROCESSOR_FALSE@src_processor_cfi_frame_info_unittest_LDADD = \ @DISABLE_PROCESSOR_FALSE@ src/common/module.o \ +@DISABLE_PROCESSOR_FALSE@ src/common/unique_string.o \ @DISABLE_PROCESSOR_FALSE@ src/processor/cfi_frame_info.o \ @DISABLE_PROCESSOR_FALSE@ src/processor/logging.o \ @DISABLE_PROCESSOR_FALSE@ src/processor/pathname_stripper.o \ @DISABLE_PROCESSOR_FALSE@ $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) @DISABLE_PROCESSOR_FALSE@src_processor_cfi_frame_info_unittest_CPPFLAGS = \ @DISABLE_PROCESSOR_FALSE@ -I$(top_srcdir)/src \ @DISABLE_PROCESSOR_FALSE@ -I$(top_srcdir)/src/testing/include \ @@ -1788,16 +1806,17 @@ @DISABLE_PROCESSOR_FALSE@ -I$(top_srcdir)/src \ @DISABLE_PROCESSOR_FALSE@ -I$(top_srcdir)/src/testing/include \ @DISABLE_PROCESSOR_FALSE@ -I$(top_srcdir)/src/testing/gtest/include \ @DISABLE_PROCESSOR_FALSE@ -I$(top_srcdir)/src/testing/gtest \ @DISABLE_PROCESSOR_FALSE@ -I$(top_srcdir)/src/testing @DISABLE_PROCESSOR_FALSE@src_processor_exploitability_unittest_LDADD = \ @DISABLE_PROCESSOR_FALSE@ src/common/module.o \ +@DISABLE_PROCESSOR_FALSE@ src/common/unique_string.o \ @DISABLE_PROCESSOR_FALSE@ src/processor/minidump_processor.o \ @DISABLE_PROCESSOR_FALSE@ src/processor/process_state.o \ @DISABLE_PROCESSOR_FALSE@ src/processor/disassembler_x86.o \ @DISABLE_PROCESSOR_FALSE@ src/processor/exploitability.o \ @DISABLE_PROCESSOR_FALSE@ src/processor/exploitability_win.o \ @DISABLE_PROCESSOR_FALSE@ src/processor/basic_code_modules.o \ @DISABLE_PROCESSOR_FALSE@ src/processor/basic_source_line_resolver.o \ @DISABLE_PROCESSOR_FALSE@ src/processor/call_stack.o \ @@ -1844,16 +1863,17 @@ @DISABLE_PROCESSOR_FALSE@ -I$(top_srcdir)/src \ @DISABLE_PROCESSOR_FALSE@ -I$(top_srcdir)/src/testing/include \ @DISABLE_PROCESSOR_FALSE@ -I$(top_srcdir)/src/testing/gtest/include \ @DISABLE_PROCESSOR_FALSE@ -I$(top_srcdir)/src/testing/gtest \ @DISABLE_PROCESSOR_FALSE@ -I$(top_srcdir)/src/testing @DISABLE_PROCESSOR_FALSE@src_processor_fast_source_line_resolver_unittest_LDADD = \ @DISABLE_PROCESSOR_FALSE@ src/common/module.o \ +@DISABLE_PROCESSOR_FALSE@ src/common/unique_string.o \ @DISABLE_PROCESSOR_FALSE@ src/processor/fast_source_line_resolver.o \ @DISABLE_PROCESSOR_FALSE@ src/processor/basic_source_line_resolver.o \ @DISABLE_PROCESSOR_FALSE@ src/processor/cfi_frame_info.o \ @DISABLE_PROCESSOR_FALSE@ src/processor/module_comparer.o \ @DISABLE_PROCESSOR_FALSE@ src/processor/module_serializer.o \ @DISABLE_PROCESSOR_FALSE@ src/processor/pathname_stripper.o \ @DISABLE_PROCESSOR_FALSE@ src/processor/logging.o \ @DISABLE_PROCESSOR_FALSE@ src/processor/source_line_resolver_base.o \ @@ -1886,16 +1906,17 @@ @DISABLE_PROCESSOR_FALSE@ -I$(top_srcdir)/src \ @DISABLE_PROCESSOR_FALSE@ -I$(top_srcdir)/src/testing/include \ @DISABLE_PROCESSOR_FALSE@ -I$(top_srcdir)/src/testing/gtest/include \ @DISABLE_PROCESSOR_FALSE@ -I$(top_srcdir)/src/testing/gtest \ @DISABLE_PROCESSOR_FALSE@ -I$(top_srcdir)/src/testing @DISABLE_PROCESSOR_FALSE@src_processor_minidump_processor_unittest_LDADD = \ @DISABLE_PROCESSOR_FALSE@ src/common/module.o \ +@DISABLE_PROCESSOR_FALSE@ src/common/unique_string.o \ @DISABLE_PROCESSOR_FALSE@ src/processor/basic_code_modules.o \ @DISABLE_PROCESSOR_FALSE@ src/processor/basic_source_line_resolver.o \ @DISABLE_PROCESSOR_FALSE@ src/processor/call_stack.o \ @DISABLE_PROCESSOR_FALSE@ src/processor/cfi_frame_info.o \ @DISABLE_PROCESSOR_FALSE@ src/processor/disassembler_x86.o \ @DISABLE_PROCESSOR_FALSE@ src/processor/exploitability.o \ @DISABLE_PROCESSOR_FALSE@ src/processor/exploitability_win.o \ @DISABLE_PROCESSOR_FALSE@ src/processor/logging.o \ @@ -2012,16 +2033,17 @@ @DISABLE_PROCESSOR_FALSE@ src/processor/pathname_stripper.o \ @DISABLE_PROCESSOR_FALSE@ $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) @DISABLE_PROCESSOR_FALSE@src_processor_postfix_evaluator_unittest_SOURCES = \ @DISABLE_PROCESSOR_FALSE@ src/processor/postfix_evaluator_unittest.cc @DISABLE_PROCESSOR_FALSE@src_processor_postfix_evaluator_unittest_LDADD = \ @DISABLE_PROCESSOR_FALSE@ src/common/module.o \ +@DISABLE_PROCESSOR_FALSE@ src/common/unique_string.o \ @DISABLE_PROCESSOR_FALSE@ src/processor/logging.o \ @DISABLE_PROCESSOR_FALSE@ src/processor/pathname_stripper.o \ @DISABLE_PROCESSOR_FALSE@ $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) @DISABLE_PROCESSOR_FALSE@src_processor_range_map_unittest_SOURCES = \ @DISABLE_PROCESSOR_FALSE@ src/processor/range_map_unittest.cc @DISABLE_PROCESSOR_FALSE@src_processor_range_map_unittest_LDADD = \ @@ -2151,16 +2173,17 @@ @DISABLE_PROCESSOR_FALSE@ src/processor/minidump.o \ @DISABLE_PROCESSOR_FALSE@ src/processor/pathname_stripper.o @DISABLE_PROCESSOR_FALSE@src_processor_minidump_stackwalk_SOURCES = \ @DISABLE_PROCESSOR_FALSE@ src/processor/minidump_stackwalk.cc @DISABLE_PROCESSOR_FALSE@src_processor_minidump_stackwalk_LDADD = \ @DISABLE_PROCESSOR_FALSE@ src/common/module.o \ +@DISABLE_PROCESSOR_FALSE@ src/common/unique_string.o \ @DISABLE_PROCESSOR_FALSE@ src/processor/basic_code_modules.o \ @DISABLE_PROCESSOR_FALSE@ src/processor/basic_source_line_resolver.o \ @DISABLE_PROCESSOR_FALSE@ src/processor/binarystream.o \ @DISABLE_PROCESSOR_FALSE@ src/processor/call_stack.o \ @DISABLE_PROCESSOR_FALSE@ src/processor/cfi_frame_info.o \ @DISABLE_PROCESSOR_FALSE@ src/processor/disassembler_x86.o \ @DISABLE_PROCESSOR_FALSE@ src/processor/exploitability.o \ @DISABLE_PROCESSOR_FALSE@ src/processor/exploitability_win.o \ @@ -2508,16 +2531,18 @@ @$(MKDIR_P) src/client/linux @: > src/client/linux/$(am__dirstamp) src/client/linux/libbreakpad_client.a: $(src_client_linux_libbreakpad_client_a_OBJECTS) $(src_client_linux_libbreakpad_client_a_DEPENDENCIES) $(EXTRA_src_client_linux_libbreakpad_client_a_DEPENDENCIES) src/client/linux/$(am__dirstamp) -rm -f src/client/linux/libbreakpad_client.a $(src_client_linux_libbreakpad_client_a_AR) src/client/linux/libbreakpad_client.a $(src_client_linux_libbreakpad_client_a_OBJECTS) $(src_client_linux_libbreakpad_client_a_LIBADD) $(RANLIB) src/client/linux/libbreakpad_client.a src/common/module.$(OBJEXT): src/common/$(am__dirstamp) \ src/common/$(DEPDIR)/$(am__dirstamp) +src/common/unique_string.$(OBJEXT): src/common/$(am__dirstamp) \ + src/common/$(DEPDIR)/$(am__dirstamp) src/processor/$(am__dirstamp): @$(MKDIR_P) src/processor @: > src/processor/$(am__dirstamp) src/processor/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) src/processor/$(DEPDIR) @: > src/processor/$(DEPDIR)/$(am__dirstamp) src/processor/basic_code_modules.$(OBJEXT): \ src/processor/$(am__dirstamp) \ @@ -2835,16 +2860,19 @@ src/common/$(am__dirstamp) \ src/common/$(DEPDIR)/$(am__dirstamp) src/common/src_common_dumper_unittest-stabs_to_module_unittest.$(OBJEXT): \ src/common/$(am__dirstamp) \ src/common/$(DEPDIR)/$(am__dirstamp) src/common/src_common_dumper_unittest-test_assembler.$(OBJEXT): \ src/common/$(am__dirstamp) \ src/common/$(DEPDIR)/$(am__dirstamp) +src/common/src_common_dumper_unittest-unique_string.$(OBJEXT): \ + src/common/$(am__dirstamp) \ + src/common/$(DEPDIR)/$(am__dirstamp) src/common/dwarf/$(am__dirstamp): @$(MKDIR_P) src/common/dwarf @: > src/common/dwarf/$(am__dirstamp) src/common/dwarf/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) src/common/dwarf/$(DEPDIR) @: > src/common/dwarf/$(DEPDIR)/$(am__dirstamp) src/common/dwarf/src_common_dumper_unittest-bytereader.$(OBJEXT): \ src/common/dwarf/$(am__dirstamp) \ @@ -3440,28 +3468,30 @@ -rm -f src/common/src_common_dumper_unittest-memory_range_unittest.$(OBJEXT) -rm -f src/common/src_common_dumper_unittest-module.$(OBJEXT) -rm -f src/common/src_common_dumper_unittest-module_unittest.$(OBJEXT) -rm -f src/common/src_common_dumper_unittest-stabs_reader.$(OBJEXT) -rm -f src/common/src_common_dumper_unittest-stabs_reader_unittest.$(OBJEXT) -rm -f src/common/src_common_dumper_unittest-stabs_to_module.$(OBJEXT) -rm -f src/common/src_common_dumper_unittest-stabs_to_module_unittest.$(OBJEXT) -rm -f src/common/src_common_dumper_unittest-test_assembler.$(OBJEXT) + -rm -f src/common/src_common_dumper_unittest-unique_string.$(OBJEXT) -rm -f src/common/src_common_test_assembler_unittest-test_assembler.$(OBJEXT) -rm -f src/common/src_common_test_assembler_unittest-test_assembler_unittest.$(OBJEXT) -rm -f src/common/src_processor_minidump_unittest-test_assembler.$(OBJEXT) -rm -f src/common/src_processor_stackwalker_amd64_unittest-test_assembler.$(OBJEXT) -rm -f src/common/src_processor_stackwalker_arm_unittest-test_assembler.$(OBJEXT) -rm -f src/common/src_processor_stackwalker_x86_unittest-test_assembler.$(OBJEXT) -rm -f src/common/src_processor_synth_minidump_unittest-test_assembler.$(OBJEXT) -rm -f src/common/stabs_reader.$(OBJEXT) -rm -f src/common/stabs_to_module.$(OBJEXT) -rm -f src/common/string_conversion.$(OBJEXT) -rm -f src/common/tests/src_client_linux_linux_client_unittest_shlib-file_utils.$(OBJEXT) -rm -f src/common/tests/src_common_dumper_unittest-file_utils.$(OBJEXT) + -rm -f src/common/unique_string.$(OBJEXT) -rm -f src/processor/address_map_unittest.$(OBJEXT) -rm -f src/processor/basic_code_modules.$(OBJEXT) -rm -f src/processor/basic_source_line_resolver.$(OBJEXT) -rm -f src/processor/binarystream.$(OBJEXT) -rm -f src/processor/call_stack.$(OBJEXT) -rm -f src/processor/cfi_frame_info.$(OBJEXT) -rm -f src/processor/contained_range_map_unittest.$(OBJEXT) -rm -f src/processor/disassembler_x86.$(OBJEXT) @@ -3630,26 +3660,28 @@ @AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/src_common_dumper_unittest-memory_range_unittest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/src_common_dumper_unittest-module.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/src_common_dumper_unittest-module_unittest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/src_common_dumper_unittest-stabs_reader.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/src_common_dumper_unittest-stabs_reader_unittest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/src_common_dumper_unittest-stabs_to_module.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/src_common_dumper_unittest-stabs_to_module_unittest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/src_common_dumper_unittest-test_assembler.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/src_common_dumper_unittest-unique_string.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/src_common_test_assembler_unittest-test_assembler.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/src_common_test_assembler_unittest-test_assembler_unittest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/src_processor_minidump_unittest-test_assembler.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/src_processor_stackwalker_amd64_unittest-test_assembler.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/src_processor_stackwalker_arm_unittest-test_assembler.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/src_processor_stackwalker_x86_unittest-test_assembler.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/src_processor_synth_minidump_unittest-test_assembler.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/stabs_reader.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/stabs_to_module.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/string_conversion.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/unique_string.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/common/android/$(DEPDIR)/breakpad_getcontext.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/common/android/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-breakpad_getcontext.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/common/android/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-breakpad_getcontext_unittest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/common/dwarf/$(DEPDIR)/bytereader.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/common/dwarf/$(DEPDIR)/dwarf2diehandler.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/common/dwarf/$(DEPDIR)/dwarf2reader.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/common/dwarf/$(DEPDIR)/src_common_dumper_unittest-bytereader.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/common/dwarf/$(DEPDIR)/src_common_dumper_unittest-bytereader_unittest.Po@am__quote@ @@ -4412,16 +4444,30 @@ src/common/src_common_dumper_unittest-test_assembler.obj: src/common/test_assembler.cc @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/src_common_dumper_unittest-test_assembler.obj -MD -MP -MF src/common/$(DEPDIR)/src_common_dumper_unittest-test_assembler.Tpo -c -o src/common/src_common_dumper_unittest-test_assembler.obj `if test -f 'src/common/test_assembler.cc'; then $(CYGPATH_W) 'src/common/test_assembler.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/test_assembler.cc'; fi` @am__fastdepCXX_TRUE@ $(am__mv) src/common/$(DEPDIR)/src_common_dumper_unittest-test_assembler.Tpo src/common/$(DEPDIR)/src_common_dumper_unittest-test_assembler.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/common/test_assembler.cc' object='src/common/src_common_dumper_unittest-test_assembler.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/src_common_dumper_unittest-test_assembler.obj `if test -f 'src/common/test_assembler.cc'; then $(CYGPATH_W) 'src/common/test_assembler.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/test_assembler.cc'; fi` +src/common/src_common_dumper_unittest-unique_string.o: src/common/unique_string.cc +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/src_common_dumper_unittest-unique_string.o -MD -MP -MF src/common/$(DEPDIR)/src_common_dumper_unittest-unique_string.Tpo -c -o src/common/src_common_dumper_unittest-unique_string.o `test -f 'src/common/unique_string.cc' || echo '$(srcdir)/'`src/common/unique_string.cc +@am__fastdepCXX_TRUE@ $(am__mv) src/common/$(DEPDIR)/src_common_dumper_unittest-unique_string.Tpo src/common/$(DEPDIR)/src_common_dumper_unittest-unique_string.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/common/unique_string.cc' object='src/common/src_common_dumper_unittest-unique_string.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/src_common_dumper_unittest-unique_string.o `test -f 'src/common/unique_string.cc' || echo '$(srcdir)/'`src/common/unique_string.cc + +src/common/src_common_dumper_unittest-unique_string.obj: src/common/unique_string.cc +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/src_common_dumper_unittest-unique_string.obj -MD -MP -MF src/common/$(DEPDIR)/src_common_dumper_unittest-unique_string.Tpo -c -o src/common/src_common_dumper_unittest-unique_string.obj `if test -f 'src/common/unique_string.cc'; then $(CYGPATH_W) 'src/common/unique_string.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/unique_string.cc'; fi` +@am__fastdepCXX_TRUE@ $(am__mv) src/common/$(DEPDIR)/src_common_dumper_unittest-unique_string.Tpo src/common/$(DEPDIR)/src_common_dumper_unittest-unique_string.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/common/unique_string.cc' object='src/common/src_common_dumper_unittest-unique_string.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/src_common_dumper_unittest-unique_string.obj `if test -f 'src/common/unique_string.cc'; then $(CYGPATH_W) 'src/common/unique_string.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/unique_string.cc'; fi` + src/common/dwarf/src_common_dumper_unittest-bytereader.o: src/common/dwarf/bytereader.cc @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/dwarf/src_common_dumper_unittest-bytereader.o -MD -MP -MF src/common/dwarf/$(DEPDIR)/src_common_dumper_unittest-bytereader.Tpo -c -o src/common/dwarf/src_common_dumper_unittest-bytereader.o `test -f 'src/common/dwarf/bytereader.cc' || echo '$(srcdir)/'`src/common/dwarf/bytereader.cc @am__fastdepCXX_TRUE@ $(am__mv) src/common/dwarf/$(DEPDIR)/src_common_dumper_unittest-bytereader.Tpo src/common/dwarf/$(DEPDIR)/src_common_dumper_unittest-bytereader.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/common/dwarf/bytereader.cc' object='src/common/dwarf/src_common_dumper_unittest-bytereader.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/dwarf/src_common_dumper_unittest-bytereader.o `test -f 'src/common/dwarf/bytereader.cc' || echo '$(srcdir)/'`src/common/dwarf/bytereader.cc src/common/dwarf/src_common_dumper_unittest-bytereader.obj: src/common/dwarf/bytereader.cc diff --git a/src/common/dwarf_cfi_to_module.cc b/src/common/dwarf_cfi_to_module.cc --- a/src/common/dwarf_cfi_to_module.cc +++ b/src/common/dwarf_cfi_to_module.cc @@ -37,40 +37,44 @@ #include #include "common/dwarf_cfi_to_module.h" namespace google_breakpad { using std::ostringstream; -vector DwarfCFIToModule::RegisterNames::MakeVector( - const char * const *strings, +vector DwarfCFIToModule::RegisterNames::MakeVector( + const char* const* strings, size_t size) { - vector names(strings, strings + size); + vector names(size, NULL); + for (size_t i = 0; i < size; ++i) { + names[i] = ToUniqueString(strings[i]); + } + return names; } -vector DwarfCFIToModule::RegisterNames::I386() { +vector DwarfCFIToModule::RegisterNames::I386() { static const char *const names[] = { "$eax", "$ecx", "$edx", "$ebx", "$esp", "$ebp", "$esi", "$edi", "$eip", "$eflags", "$unused1", "$st0", "$st1", "$st2", "$st3", "$st4", "$st5", "$st6", "$st7", "$unused2", "$unused3", "$xmm0", "$xmm1", "$xmm2", "$xmm3", "$xmm4", "$xmm5", "$xmm6", "$xmm7", "$mm0", "$mm1", "$mm2", "$mm3", "$mm4", "$mm5", "$mm6", "$mm7", "$fcw", "$fsw", "$mxcsr", "$es", "$cs", "$ss", "$ds", "$fs", "$gs", "$unused4", "$unused5", "$tr", "$ldtr" }; return MakeVector(names, sizeof(names) / sizeof(names[0])); } -vector DwarfCFIToModule::RegisterNames::X86_64() { +vector DwarfCFIToModule::RegisterNames::X86_64() { static const char *const names[] = { "$rax", "$rdx", "$rcx", "$rbx", "$rsi", "$rdi", "$rbp", "$rsp", "$r8", "$r9", "$r10", "$r11", "$r12", "$r13", "$r14", "$r15", "$rip", "$xmm0","$xmm1","$xmm2", "$xmm3", "$xmm4", "$xmm5", "$xmm6", "$xmm7", "$xmm8","$xmm9","$xmm10","$xmm11","$xmm12","$xmm13","$xmm14","$xmm15", "$st0", "$st1", "$st2", "$st3", "$st4", "$st5", "$st6", "$st7", "$mm0", "$mm1", "$mm2", "$mm3", "$mm4", "$mm5", "$mm6", "$mm7", @@ -80,17 +84,17 @@ "$tr", "$ldtr", "$mxcsr", "$fcw", "$fsw" }; return MakeVector(names, sizeof(names) / sizeof(names[0])); } // Per ARM IHI 0040A, section 3.1 -vector DwarfCFIToModule::RegisterNames::ARM() { +vector DwarfCFIToModule::RegisterNames::ARM() { static const char *const names[] = { "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "sp", "lr", "pc", "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", "fps", "cpsr", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", @@ -122,40 +126,40 @@ return_address_ = return_address; // Breakpad STACK CFI records must provide a .ra rule, but DWARF CFI // may not establish any rule for .ra if the return address column // is an ordinary register, and that register holds the return // address on entry to the function. So establish an initial .ra // rule citing the return address register. if (return_address_ < register_names_.size()) - entry_->initial_rules[ra_name_] + entry_->initial_rules[ustr__ZDra()] = Module::Expr(register_names_[return_address_], 0, false); return true; } -string DwarfCFIToModule::RegisterName(int i) { +const UniqueString* DwarfCFIToModule::RegisterName(int i) { assert(entry_); if (i < 0) { assert(i == kCFARegister); - return cfa_name_; + return ustr__ZDcfa(); } unsigned reg = i; if (reg == return_address_) - return ra_name_; + return ustr__ZDra(); // Ensure that a non-empty name exists for this register value. - if (reg < register_names_.size() && !register_names_[reg].empty()) + if (reg < register_names_.size() && register_names_[reg] != ustr__empty()) return register_names_[reg]; reporter_->UnnamedRegister(entry_offset_, reg); char buf[30]; sprintf(buf, "unnamed_register%u", reg); - return buf; + return ToUniqueString(buf); } void DwarfCFIToModule::Record(Module::Address address, int reg, const Module::Expr &rule) { assert(entry_); // Is this one of this entry's initial rules? if (address == entry_->address) @@ -228,28 +232,30 @@ void DwarfCFIToModule::Reporter::UnnamedRegister(size_t offset, int reg) { fprintf(stderr, "%s, section '%s': " "the call frame entry at offset 0x%zx refers to register %d," " whose name we don't know\n", file_.c_str(), section_.c_str(), offset, reg); } -void DwarfCFIToModule::Reporter::UndefinedNotSupported(size_t offset, - const string ®) { +void DwarfCFIToModule::Reporter::UndefinedNotSupported( + size_t offset, + const UniqueString* 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" " cannot express this\n", - file_.c_str(), section_.c_str(), offset, reg.c_str()); + file_.c_str(), section_.c_str(), offset, FromUniqueString(reg)); } -void DwarfCFIToModule::Reporter::ExpressionsNotSupported(size_t offset, - const string ®) { +void DwarfCFIToModule::Reporter::ExpressionsNotSupported( + size_t offset, + const UniqueString* 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', " " but this translator cannot yet translate DWARF expressions to" " Breakpad postfix expressions\n", - file_.c_str(), section_.c_str(), offset, reg.c_str()); + file_.c_str(), section_.c_str(), offset, FromUniqueString(reg)); } } // namespace google_breakpad diff --git a/src/common/dwarf_cfi_to_module.h b/src/common/dwarf_cfi_to_module.h --- a/src/common/dwarf_cfi_to_module.h +++ b/src/common/dwarf_cfi_to_module.h @@ -44,16 +44,17 @@ #include #include #include #include "common/module.h" #include "common/dwarf/dwarf2reader.h" #include "common/using_std_string.h" +#include "common/unique_string.h" namespace google_breakpad { using dwarf2reader::CallFrameInfo; using google_breakpad::Module; using std::set; using std::vector; @@ -78,61 +79,65 @@ // The DWARF CFI entry at OFFSET cites register REG, but REG is not // covered by the vector of register names passed to the // DwarfCFIToModule constructor, nor does it match the return // address column number for this entry. virtual void UnnamedRegister(size_t offset, int reg); // The DWARF CFI entry at OFFSET says that REG is undefined, but the // Breakpad symbol file format cannot express this. - virtual void UndefinedNotSupported(size_t offset, const string ®); + virtual void UndefinedNotSupported(size_t offset, + const UniqueString* 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 ®); + virtual void ExpressionsNotSupported(size_t offset, + const UniqueString* reg); protected: string file_, section_; }; // Register name tables. If TABLE is a vector returned by one of these // functions, then TABLE[R] is the name of the register numbered R in // DWARF call frame information. class RegisterNames { public: // Intel's "x86" or IA-32. - static vector I386(); + static vector I386(); // AMD x86_64, AMD64, Intel EM64T, or Intel 64 - static vector X86_64(); + static vector X86_64(); // ARM. - static vector ARM(); + static vector ARM(); private: // Given STRINGS, an array of C strings with SIZE elements, return an // equivalent vector. - static vector MakeVector(const char * const *strings, size_t size); + static vector MakeVector(const char * const *strings, + size_t size); }; // Create a handler for the dwarf2reader::CallFrameInfo parser that // records the stack unwinding information it receives in MODULE. // // Use REGISTER_NAMES[I] as the name of register number I; *this // keeps a reference to the vector, so the vector should remain // alive for as long as the DwarfCFIToModule does. // // Use REPORTER for reporting problems encountered in the conversion // process. - DwarfCFIToModule(Module *module, const vector ®ister_names, + DwarfCFIToModule(Module *module, + const vector ®ister_names, Reporter *reporter) : module_(module), register_names_(register_names), reporter_(reporter), - entry_(NULL), return_address_(-1), cfa_name_(".cfa"), ra_name_(".ra") { + entry_(NULL), return_address_(-1) { } virtual ~DwarfCFIToModule() { delete entry_; } virtual bool Entry(size_t offset, uint64 address, uint64 length, uint8 version, const string &augmentation, unsigned return_address); virtual bool UndefinedRule(uint64 address, int reg); virtual bool SameValueRule(uint64 address, int reg); @@ -144,53 +149,36 @@ virtual bool ExpressionRule(uint64 address, int reg, const string &expression); virtual bool ValExpressionRule(uint64 address, int reg, const string &expression); virtual bool End(); private: // Return the name to use for register REG. - string RegisterName(int i); + const UniqueString* RegisterName(int i); // Record RULE for register REG at ADDRESS. void Record(Module::Address address, int reg, const Module::Expr &rule); // The module to which we should add entries. Module *module_; // Map from register numbers to register names. - const vector ®ister_names_; + const vector ®ister_names_; // The reporter to use to report problems. Reporter *reporter_; // The current entry we're constructing. Module::StackFrameEntry *entry_; // The section offset of the current frame description entry, for // use in error messages. size_t entry_offset_; // The return address column for that entry. unsigned return_address_; - - // The names of the return address and canonical frame address. Putting - // these here instead of using string literals allows us to share their - // texts in reference-counted std::string implementations (all the - // popular ones). Many, many rules cite these strings. - string cfa_name_, ra_name_; - - // A set of strings used by this CFI. Before storing a string in one of - // our data structures, insert it into this set, and then use the string - // from the set. - // - // Because std::string uses reference counting internally, simply using - // strings from this set, even if passed by value, assigned, or held - // directly in structures and containers (map, for example), - // causes those strings to share a single instance of each distinct piece - // of text. - set common_strings_; }; } // namespace google_breakpad #endif // COMMON_LINUX_DWARF_CFI_TO_MODULE_H diff --git a/src/common/dwarf_cfi_to_module_unittest.cc b/src/common/dwarf_cfi_to_module_unittest.cc --- a/src/common/dwarf_cfi_to_module_unittest.cc +++ b/src/common/dwarf_cfi_to_module_unittest.cc @@ -37,52 +37,59 @@ #include "breakpad_googletest_includes.h" #include "common/dwarf_cfi_to_module.h" #include "common/using_std_string.h" using std::vector; using google_breakpad::Module; using google_breakpad::DwarfCFIToModule; +using google_breakpad::ToUniqueString; +using google_breakpad::UniqueString; +using google_breakpad::ustr__ZDcfa; +using google_breakpad::ustr__ZDra; +using google_breakpad::ustr__empty; using testing::ContainerEq; using testing::Test; using testing::_; struct MockCFIReporter: public DwarfCFIToModule::Reporter { MockCFIReporter(const string &file, const string §ion) : Reporter(file, section) { } MOCK_METHOD2(UnnamedRegister, void(size_t offset, int reg)); - MOCK_METHOD2(UndefinedNotSupported, void(size_t offset, const string ®)); - MOCK_METHOD2(ExpressionsNotSupported, void(size_t offset, const string ®)); + MOCK_METHOD2(UndefinedNotSupported, void(size_t offset, + const UniqueString* reg)); + MOCK_METHOD2(ExpressionsNotSupported, void(size_t offset, + const UniqueString* reg)); }; struct DwarfCFIToModuleFixture { DwarfCFIToModuleFixture() : module("module name", "module os", "module arch", "module id"), reporter("reporter file", "reporter section"), handler(&module, register_names, &reporter) { - register_names.push_back("reg0"); - register_names.push_back("reg1"); - register_names.push_back("reg2"); - register_names.push_back("reg3"); - register_names.push_back("reg4"); - register_names.push_back("reg5"); - register_names.push_back("reg6"); - register_names.push_back("reg7"); - register_names.push_back("sp"); - register_names.push_back("pc"); - register_names.push_back(""); + register_names.push_back(ToUniqueString("reg0")); + register_names.push_back(ToUniqueString("reg1")); + register_names.push_back(ToUniqueString("reg2")); + register_names.push_back(ToUniqueString("reg3")); + register_names.push_back(ToUniqueString("reg4")); + register_names.push_back(ToUniqueString("reg5")); + register_names.push_back(ToUniqueString("reg6")); + register_names.push_back(ToUniqueString("reg7")); + register_names.push_back(ToUniqueString("sp")); + register_names.push_back(ToUniqueString("pc")); + register_names.push_back(ustr__empty()); EXPECT_CALL(reporter, UnnamedRegister(_, _)).Times(0); EXPECT_CALL(reporter, UndefinedNotSupported(_, _)).Times(0); EXPECT_CALL(reporter, ExpressionsNotSupported(_, _)).Times(0); } Module module; - vector register_names; + vector register_names; MockCFIReporter reporter; DwarfCFIToModule handler; vector entries; }; class Entry: public DwarfCFIToModuleFixture, public Test { }; TEST_F(Entry, Accept) { @@ -127,183 +134,190 @@ } uint64 entry_address, entry_size; unsigned return_reg; }; class Rule: public RuleFixture, public Test { }; TEST_F(Rule, UndefinedRule) { - EXPECT_CALL(reporter, UndefinedNotSupported(_, "reg7")); + EXPECT_CALL(reporter, UndefinedNotSupported(_, ToUniqueString("reg7"))); StartEntry(); ASSERT_TRUE(handler.UndefinedRule(entry_address, 7)); ASSERT_TRUE(handler.End()); CheckEntry(); EXPECT_EQ(0U, entries[0]->initial_rules.size()); EXPECT_EQ(0U, entries[0]->rule_changes.size()); } TEST_F(Rule, RegisterWithEmptyName) { EXPECT_CALL(reporter, UnnamedRegister(_, 10)); - EXPECT_CALL(reporter, UndefinedNotSupported(_, "unnamed_register10")); + EXPECT_CALL(reporter, + UndefinedNotSupported(_, ToUniqueString("unnamed_register10"))); StartEntry(); ASSERT_TRUE(handler.UndefinedRule(entry_address, 10)); ASSERT_TRUE(handler.End()); CheckEntry(); EXPECT_EQ(0U, entries[0]->initial_rules.size()); EXPECT_EQ(0U, entries[0]->rule_changes.size()); } TEST_F(Rule, SameValueRule) { StartEntry(); ASSERT_TRUE(handler.SameValueRule(entry_address, 6)); ASSERT_TRUE(handler.End()); CheckEntry(); Module::RuleMap expected_initial; - expected_initial["reg6"] = Module::Expr("reg6", 0, false); + const UniqueString* reg6 = ToUniqueString("reg6"); + expected_initial[reg6] = Module::Expr(reg6, 0, false); EXPECT_THAT(entries[0]->initial_rules, ContainerEq(expected_initial)); EXPECT_EQ(0U, entries[0]->rule_changes.size()); } TEST_F(Rule, OffsetRule) { StartEntry(); ASSERT_TRUE(handler.OffsetRule(entry_address + 1, return_reg, DwarfCFIToModule::kCFARegister, 16927065)); ASSERT_TRUE(handler.End()); CheckEntry(); EXPECT_EQ(0U, entries[0]->initial_rules.size()); Module::RuleChangeMap expected_changes; - expected_changes[entry_address + 1][".ra"] = - Module::Expr(".cfa", 16927065, true); + expected_changes[entry_address + 1][ustr__ZDra()] = + Module::Expr(ustr__ZDcfa(), 16927065, true); EXPECT_THAT(entries[0]->rule_changes, ContainerEq(expected_changes)); } TEST_F(Rule, OffsetRuleNegative) { StartEntry(); ASSERT_TRUE(handler.OffsetRule(entry_address + 1, DwarfCFIToModule::kCFARegister, 4, -34530721)); ASSERT_TRUE(handler.End()); CheckEntry(); EXPECT_EQ(0U, entries[0]->initial_rules.size()); Module::RuleChangeMap expected_changes; - expected_changes[entry_address + 1][".cfa"] = - Module::Expr("reg4", -34530721, true); + expected_changes[entry_address + 1][ustr__ZDcfa()] = + Module::Expr(ToUniqueString("reg4"), -34530721, true); EXPECT_THAT(entries[0]->rule_changes, ContainerEq(expected_changes)); } TEST_F(Rule, ValOffsetRule) { // Use an unnamed register number, to exercise that branch of RegisterName. EXPECT_CALL(reporter, UnnamedRegister(_, 11)); StartEntry(); ASSERT_TRUE(handler.ValOffsetRule(entry_address + 0x5ab7, DwarfCFIToModule::kCFARegister, 11, 61812979)); ASSERT_TRUE(handler.End()); CheckEntry(); EXPECT_EQ(0U, entries[0]->initial_rules.size()); Module::RuleChangeMap expected_changes; - expected_changes[entry_address + 0x5ab7][".cfa"] = - Module::Expr("unnamed_register11", 61812979, false); + expected_changes[entry_address + 0x5ab7][ustr__ZDcfa()] = + Module::Expr(ToUniqueString("unnamed_register11"), 61812979, false); EXPECT_THAT(entries[0]->rule_changes, ContainerEq(expected_changes)); } TEST_F(Rule, RegisterRule) { StartEntry(); ASSERT_TRUE(handler.RegisterRule(entry_address, return_reg, 3)); ASSERT_TRUE(handler.End()); CheckEntry(); Module::RuleMap expected_initial; - expected_initial[".ra"] = Module::Expr("reg3", 0, false); + expected_initial[ustr__ZDra()] = + Module::Expr(ToUniqueString("reg3"), 0, false); EXPECT_THAT(entries[0]->initial_rules, ContainerEq(expected_initial)); EXPECT_EQ(0U, entries[0]->rule_changes.size()); } TEST_F(Rule, ExpressionRule) { - EXPECT_CALL(reporter, ExpressionsNotSupported(_, "reg2")); + EXPECT_CALL(reporter, ExpressionsNotSupported(_, ToUniqueString("reg2"))); StartEntry(); ASSERT_TRUE(handler.ExpressionRule(entry_address + 0xf326, 2, "it takes two to tango")); ASSERT_TRUE(handler.End()); CheckEntry(); EXPECT_EQ(0U, entries[0]->initial_rules.size()); EXPECT_EQ(0U, entries[0]->rule_changes.size()); } TEST_F(Rule, ValExpressionRule) { - EXPECT_CALL(reporter, ExpressionsNotSupported(_, "reg0")); + EXPECT_CALL(reporter, ExpressionsNotSupported(_, ToUniqueString("reg0"))); StartEntry(); ASSERT_TRUE(handler.ValExpressionRule(entry_address + 0x6367, 0, "bit off more than he could chew")); ASSERT_TRUE(handler.End()); CheckEntry(); EXPECT_EQ(0U, entries[0]->initial_rules.size()); EXPECT_EQ(0U, entries[0]->rule_changes.size()); } TEST_F(Rule, DefaultReturnAddressRule) { return_reg = 2; StartEntry(); ASSERT_TRUE(handler.RegisterRule(entry_address, 0, 1)); ASSERT_TRUE(handler.End()); CheckEntry(); Module::RuleMap expected_initial; - expected_initial[".ra"] = Module::Expr("reg2", 0, false); - expected_initial["reg0"] = Module::Expr("reg1", 0, false); + expected_initial[ustr__ZDra()] = + Module::Expr(ToUniqueString("reg2"), 0, false); + expected_initial[ToUniqueString("reg0")] = + Module::Expr(ToUniqueString("reg1"), 0, false); EXPECT_THAT(entries[0]->initial_rules, ContainerEq(expected_initial)); EXPECT_EQ(0U, entries[0]->rule_changes.size()); } TEST_F(Rule, DefaultReturnAddressRuleOverride) { return_reg = 2; StartEntry(); ASSERT_TRUE(handler.RegisterRule(entry_address, return_reg, 1)); ASSERT_TRUE(handler.End()); CheckEntry(); Module::RuleMap expected_initial; - expected_initial[".ra"] = Module::Expr("reg1", 0, false); + expected_initial[ustr__ZDra()] = + Module::Expr(ToUniqueString("reg1"), 0, false); EXPECT_THAT(entries[0]->initial_rules, ContainerEq(expected_initial)); EXPECT_EQ(0U, entries[0]->rule_changes.size()); } TEST_F(Rule, DefaultReturnAddressRuleLater) { return_reg = 2; StartEntry(); ASSERT_TRUE(handler.RegisterRule(entry_address + 1, return_reg, 1)); ASSERT_TRUE(handler.End()); CheckEntry(); Module::RuleMap expected_initial; - expected_initial[".ra"] = Module::Expr("reg2", 0, false); + expected_initial[ustr__ZDra()] = + Module::Expr(ToUniqueString("reg2"), 0, false); EXPECT_THAT(entries[0]->initial_rules, ContainerEq(expected_initial)); Module::RuleChangeMap expected_changes; - expected_changes[entry_address + 1][".ra"] = - Module::Expr("reg1", 0, false); + expected_changes[entry_address + 1][ustr__ZDra()] = + Module::Expr(ToUniqueString("reg1"), 0, false); EXPECT_THAT(entries[0]->rule_changes, ContainerEq(expected_changes)); } TEST(RegisterNames, I386) { - vector names = DwarfCFIToModule::RegisterNames::I386(); + vector names = DwarfCFIToModule::RegisterNames::I386(); - EXPECT_EQ("$eax", names[0]); - EXPECT_EQ("$ecx", names[1]); - EXPECT_EQ("$esp", names[4]); - EXPECT_EQ("$eip", names[8]); + EXPECT_EQ(ToUniqueString("$eax"), names[0]); + EXPECT_EQ(ToUniqueString("$ecx"), names[1]); + EXPECT_EQ(ToUniqueString("$esp"), names[4]); + EXPECT_EQ(ToUniqueString("$eip"), names[8]); } TEST(RegisterNames, ARM) { - vector names = DwarfCFIToModule::RegisterNames::ARM(); + vector names = DwarfCFIToModule::RegisterNames::ARM(); - EXPECT_EQ("r0", names[0]); - EXPECT_EQ("r10", names[10]); - EXPECT_EQ("sp", names[13]); - EXPECT_EQ("lr", names[14]); - EXPECT_EQ("pc", names[15]); + EXPECT_EQ(ToUniqueString("r0"), names[0]); + EXPECT_EQ(ToUniqueString("r10"), names[10]); + EXPECT_EQ(ToUniqueString("sp"), names[13]); + EXPECT_EQ(ToUniqueString("lr"), names[14]); + EXPECT_EQ(ToUniqueString("pc"), names[15]); } TEST(RegisterNames, X86_64) { - vector names = DwarfCFIToModule::RegisterNames::X86_64(); + vector names = DwarfCFIToModule::RegisterNames::X86_64(); - EXPECT_EQ("$rax", names[0]); - EXPECT_EQ("$rdx", names[1]); - EXPECT_EQ("$rbp", names[6]); - EXPECT_EQ("$rsp", names[7]); - EXPECT_EQ("$rip", names[16]); + EXPECT_EQ(ToUniqueString("$rax"), names[0]); + EXPECT_EQ(ToUniqueString("$rdx"), names[1]); + EXPECT_EQ(ToUniqueString("$rbp"), names[6]); + EXPECT_EQ(ToUniqueString("$rsp"), names[7]); + EXPECT_EQ(ToUniqueString("$rip"), names[16]); } diff --git a/src/common/linux/dump_symbols.cc b/src/common/linux/dump_symbols.cc --- a/src/common/linux/dump_symbols.cc +++ b/src/common/linux/dump_symbols.cc @@ -80,16 +80,17 @@ using google_breakpad::ElfClass64; using google_breakpad::FindElfSectionByName; using google_breakpad::GetOffset; using google_breakpad::IsValidElf; using google_breakpad::Module; #ifndef NO_STABS_SUPPORT using google_breakpad::StabsToModule; #endif +using google_breakpad::UniqueString; using google_breakpad::scoped_ptr; // // FDWrapper // // Wrapper class to make sure opened file is closed. // class FDWrapper { @@ -270,17 +271,17 @@ // Fill REGISTER_NAMES with the register names appropriate to the // machine architecture given in HEADER, indexed by the register // numbers used in DWARF call frame information. Return true on // success, or false if HEADER's machine architecture is not // supported. template bool DwarfCFIRegisterNames(const typename ElfClass::Ehdr* elf_header, - std::vector* register_names) { + std::vector* register_names) { switch (elf_header->e_machine) { case EM_386: *register_names = DwarfCFIToModule::RegisterNames::I386(); return true; case EM_ARM: *register_names = DwarfCFIToModule::RegisterNames::ARM(); return true; case EM_X86_64: @@ -298,17 +299,17 @@ const typename ElfClass::Shdr* section, const bool eh_frame, const typename ElfClass::Shdr* got_section, const typename ElfClass::Shdr* text_section, const bool big_endian, Module* module) { // Find the appropriate set of register names for this file's // architecture. - std::vector register_names; + std::vector register_names; if (!DwarfCFIRegisterNames(elf_header, ®ister_names)) { fprintf(stderr, "%s: unrecognized ELF machine architecture '%d';" " cannot convert DWARF call frame information\n", dwarf_filename.c_str(), elf_header->e_machine); return false; } const dwarf2reader::Endianness endianness = big_endian ? diff --git a/src/common/mac/dump_syms.mm b/src/common/mac/dump_syms.mm --- a/src/common/mac/dump_syms.mm +++ b/src/common/mac/dump_syms.mm @@ -305,17 +305,17 @@ } bool DumpSymbols::ReadCFI(google_breakpad::Module *module, const mach_o::Reader &macho_reader, const mach_o::Section §ion, bool eh_frame) const { // Find the appropriate set of register names for this file's // architecture. - vector register_names; + vector register_names; switch (macho_reader.cpu_type()) { case CPU_TYPE_X86: register_names = DwarfCFIToModule::RegisterNames::I386(); break; case CPU_TYPE_X86_64: register_names = DwarfCFIToModule::RegisterNames::X86_64(); break; case CPU_TYPE_ARM: diff --git a/src/common/module.cc b/src/common/module.cc --- a/src/common/module.cc +++ b/src/common/module.cc @@ -33,16 +33,17 @@ #include "common/module.h" #include #include #include #include +#include #include #include namespace google_breakpad { using std::dec; using std::endl; using std::hex; @@ -270,21 +271,35 @@ case Module::kExprInvalid: default: break; } return stream; } bool Module::WriteRuleMap(const RuleMap &rule_map, std::ostream &stream) { + // Visit the register rules in alphabetical order. Because + // rule_map has the elements in some arbitrary order, + // get the names out into a vector, sort them, and visit in + // sorted order. + std::vector rr_names; for (RuleMap::const_iterator it = rule_map.begin(); it != rule_map.end(); ++it) { - if (it != rule_map.begin()) - stream << ' '; - stream << it->first << ": " << it->second; + rr_names.push_back(it->first); + } + + std::sort(rr_names.begin(), rr_names.end(), LessThan_UniqueString); + + // Now visit the register rules in alphabetical order. + for (std::vector::const_iterator name = rr_names.begin(); + name != rr_names.end(); + ++name) { + if (name != rr_names.begin()) + stream << " "; + stream << FromUniqueString(*name) << ": " << rule_map.find(*name)->second; } return stream.good(); } bool Module::Write(std::ostream &stream, SymbolData symbol_data) { stream << "MODULE " << os_ << " " << architecture_ << " " << id_ << " " << name_ << endl; if (!stream.good()) diff --git a/src/common/module.h b/src/common/module.h --- a/src/common/module.h +++ b/src/common/module.h @@ -41,16 +41,17 @@ #include #include #include #include #include #include "common/symbol_data.h" #include "common/using_std_string.h" +#include "common/unique_string.h" #include "google_breakpad/common/breakpad_types.h" namespace google_breakpad { using std::set; using std::vector; using std::map; @@ -131,69 +132,69 @@ enum ExprHow { kExprInvalid = 1, kExprPostfix, kExprSimple, kExprSimpleMem }; struct Expr { // Construct a simple-form expression - Expr(string ident, long offset, bool deref) { - if (ident.empty()) { + Expr(const UniqueString* ident, long offset, bool deref) { + if (ident == ustr__empty()) { Expr(); } else { postfix_ = ""; ident_ = ident; offset_ = offset; how_ = deref ? kExprSimpleMem : kExprSimple; } } // Construct an expression from a postfix string Expr(string postfix) { if (postfix.empty()) { Expr(); } else { postfix_ = postfix; - ident_ = ""; + ident_ = NULL; offset_ = 0; how_ = kExprPostfix; } } // Construct an invalid expression Expr() { postfix_ = ""; - ident_ = ""; + ident_ = NULL; offset_ = 0; how_ = kExprInvalid; } bool invalid() const { return how_ == kExprInvalid; } bool operator==(const Expr& other) const { return how_ == other.how_ && ident_ == other.ident_ && offset_ == other.offset_ && postfix_ == other.postfix_; } // The identifier that gives the starting value for simple expressions. - string ident_; + const UniqueString* ident_; // The offset to add for simple expressions. long offset_; // The Postfix expression string to evaluate for non-simple expressions. string postfix_; // The operation expressed by this expression. ExprHow how_; friend std::ostream& operator<<(std::ostream& stream, const Expr& expr); }; // A map from register names to expressions that recover // their values. This can represent a complete set of rules to // follow at some address, or a set of changes to be applied to an // extant set of rules. - typedef map RuleMap; + typedef map RuleMap; // A map from addresses to RuleMaps, representing changes that take // effect at given addresses. typedef map RuleChangeMap; // A range of 'STACK CFI' stack walking information. An instance of // this structure corresponds to a 'STACK CFI INIT' record and the // subsequent 'STACK CFI' records that fall within its range. diff --git a/src/common/module_unittest.cc b/src/common/module_unittest.cc --- a/src/common/module_unittest.cc +++ b/src/common/module_unittest.cc @@ -40,16 +40,18 @@ #include #include #include "breakpad_googletest_includes.h" #include "common/module.h" #include "common/using_std_string.h" using google_breakpad::Module; +using google_breakpad::ToUniqueString; +using google_breakpad::ustr__ZDcfa; using std::stringstream; using std::vector; using testing::ContainerEq; static Module::Function *generate_duplicate_function(const string &name) { const Module::Address DUP_ADDRESS = 0xd35402aac7a7ad5cLL; const Module::Address DUP_SIZE = 0x200b26e605f99071LL; const Module::Address DUP_PARAMETER_SIZE = 0xf14ac4fed48c4a99LL; @@ -125,21 +127,23 @@ function->lines.push_back(line1); m.AddFunction(function); // Some stack information. Module::StackFrameEntry *entry = new Module::StackFrameEntry(); entry->address = 0x30f9e5c83323973dULL; entry->size = 0x49fc9ca7c7c13dc2ULL; - entry->initial_rules[".cfa"] = Module::Expr("he was a handsome man"); - entry->initial_rules["and"] = Module::Expr("what i want to know is"); - entry->rule_changes[0x30f9e5c83323973eULL]["how"] = - Module::Expr("do you like your blueeyed boy"); - entry->rule_changes[0x30f9e5c83323973eULL]["Mister"] = Module::Expr("Death"); + entry->initial_rules[ustr__ZDcfa()] = Module::Expr("he was a handsome man"); + entry->initial_rules[ToUniqueString("and")] = + Module::Expr("what i want to know is"); + entry->rule_changes[0x30f9e5c83323973eULL][ToUniqueString("how")] = + Module::Expr("do you like your blueeyed boy"); + entry->rule_changes[0x30f9e5c83323973eULL][ToUniqueString("Mister")] = + Module::Expr("Death"); m.AddStackFrameEntry(entry); // Set the load address. Doing this after adding all the data to // the module must work fine. m.SetLoadAddress(0x2ab698b0b6407073LL); m.Write(s, ALL_SYMBOL_DATA); string contents = s.str(); @@ -229,21 +233,23 @@ function->lines.push_back(line1); m.AddFunction(function); // Some stack information. Module::StackFrameEntry *entry = new Module::StackFrameEntry(); entry->address = 0x30f9e5c83323973dULL; entry->size = 0x49fc9ca7c7c13dc2ULL; - entry->initial_rules[".cfa"] = Module::Expr("he was a handsome man"); - entry->initial_rules["and"] = Module::Expr("what i want to know is"); - entry->rule_changes[0x30f9e5c83323973eULL]["how"] = - Module::Expr("do you like your blueeyed boy"); - entry->rule_changes[0x30f9e5c83323973eULL]["Mister"] = Module::Expr("Death"); + entry->initial_rules[ustr__ZDcfa()] = Module::Expr("he was a handsome man"); + entry->initial_rules[ToUniqueString("and")] = + Module::Expr("what i want to know is"); + entry->rule_changes[0x30f9e5c83323973eULL][ToUniqueString("how")] = + Module::Expr("do you like your blueeyed boy"); + entry->rule_changes[0x30f9e5c83323973eULL][ToUniqueString("Mister")] = + Module::Expr("Death"); m.AddStackFrameEntry(entry); // Set the load address. Doing this after adding all the data to // the module must work fine. m.SetLoadAddress(0x2ab698b0b6407073LL); m.Write(s, NO_CFI); string contents = s.str(); @@ -305,33 +311,36 @@ entry1->address = 0xddb5f41285aa7757ULL; entry1->size = 0x1486493370dc5073ULL; m.AddStackFrameEntry(entry1); // Second STACK CFI entry, with initial rules but no deltas. Module::StackFrameEntry *entry2 = new Module::StackFrameEntry(); entry2->address = 0x8064f3af5e067e38ULL; entry2->size = 0x0de2a5ee55509407ULL; - entry2->initial_rules[".cfa"] = Module::Expr("I think that I shall never see"); - entry2->initial_rules["stromboli"] = Module::Expr("a poem lovely as a tree"); - entry2->initial_rules["cannoli"] = Module::Expr("a tree whose hungry mouth is prest"); + entry2->initial_rules[ustr__ZDcfa()] = + Module::Expr("I think that I shall never see"); + entry2->initial_rules[ToUniqueString("stromboli")] = + Module::Expr("a poem lovely as a tree"); + entry2->initial_rules[ToUniqueString("cannoli")] = + Module::Expr("a tree whose hungry mouth is prest"); m.AddStackFrameEntry(entry2); // Third STACK CFI entry, with initial rules and deltas. Module::StackFrameEntry *entry3 = new Module::StackFrameEntry(); entry3->address = 0x5e8d0db0a7075c6cULL; entry3->size = 0x1c7edb12a7aea229ULL; - entry3->initial_rules[".cfa"] = Module::Expr("Whose woods are these"); - entry3->rule_changes[0x47ceb0f63c269d7fULL]["calzone"] = + entry3->initial_rules[ustr__ZDcfa()] = Module::Expr("Whose woods are these"); + entry3->rule_changes[0x47ceb0f63c269d7fULL][ToUniqueString("calzone")] = Module::Expr("the village though"); - entry3->rule_changes[0x47ceb0f63c269d7fULL]["cannoli"] = + entry3->rule_changes[0x47ceb0f63c269d7fULL][ToUniqueString("cannoli")] = Module::Expr("he will not see me stopping here"); - entry3->rule_changes[0x36682fad3763ffffULL]["stromboli"] = + entry3->rule_changes[0x36682fad3763ffffULL][ToUniqueString("stromboli")] = Module::Expr("his house is in"); - entry3->rule_changes[0x36682fad3763ffffULL][".cfa"] = + entry3->rule_changes[0x36682fad3763ffffULL][ustr__ZDcfa()] = Module::Expr("I think I know"); m.AddStackFrameEntry(entry3); // Check that Write writes STACK CFI records properly. m.Write(s, ALL_SYMBOL_DATA); string contents = s.str(); EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n" "STACK CFI INIT 5e8d0db0a7075c6c 1c7edb12a7aea229" @@ -352,33 +361,39 @@ // Check that GetStackFrameEntries works. vector entries; m.GetStackFrameEntries(&entries); ASSERT_EQ(3U, entries.size()); // Check first entry. EXPECT_EQ(0x5e8d0db0a7075c6cULL, entries[0]->address); EXPECT_EQ(0x1c7edb12a7aea229ULL, entries[0]->size); Module::RuleMap entry1_initial; - entry1_initial[".cfa"] = Module::Expr("Whose woods are these"); + entry1_initial[ustr__ZDcfa()] = Module::Expr("Whose woods are these"); EXPECT_THAT(entries[0]->initial_rules, ContainerEq(entry1_initial)); Module::RuleChangeMap entry1_changes; - entry1_changes[0x36682fad3763ffffULL][".cfa"] = Module::Expr("I think I know"); - entry1_changes[0x36682fad3763ffffULL]["stromboli"] = Module::Expr("his house is in"); - entry1_changes[0x47ceb0f63c269d7fULL]["calzone"] = Module::Expr("the village though"); - entry1_changes[0x47ceb0f63c269d7fULL]["cannoli"] = - Module::Expr("he will not see me stopping here"); + entry1_changes[0x36682fad3763ffffULL][ustr__ZDcfa()] = + Module::Expr("I think I know"); + entry1_changes[0x36682fad3763ffffULL][ToUniqueString("stromboli")] = + Module::Expr("his house is in"); + entry1_changes[0x47ceb0f63c269d7fULL][ToUniqueString("calzone")] = + Module::Expr("the village though"); + entry1_changes[0x47ceb0f63c269d7fULL][ToUniqueString("cannoli")] = + Module::Expr("he will not see me stopping here"); EXPECT_THAT(entries[0]->rule_changes, ContainerEq(entry1_changes)); // Check second entry. EXPECT_EQ(0x8064f3af5e067e38ULL, entries[1]->address); EXPECT_EQ(0x0de2a5ee55509407ULL, entries[1]->size); ASSERT_EQ(3U, entries[1]->initial_rules.size()); Module::RuleMap entry2_initial; - entry2_initial[".cfa"] = Module::Expr("I think that I shall never see"); - entry2_initial["stromboli"] = Module::Expr("a poem lovely as a tree"); - entry2_initial["cannoli"] = Module::Expr("a tree whose hungry mouth is prest"); + entry2_initial[ustr__ZDcfa()] = + Module::Expr("I think that I shall never see"); + entry2_initial[ToUniqueString("stromboli")] = + Module::Expr("a poem lovely as a tree"); + entry2_initial[ToUniqueString("cannoli")] = + Module::Expr("a tree whose hungry mouth is prest"); EXPECT_THAT(entries[1]->initial_rules, ContainerEq(entry2_initial)); ASSERT_EQ(0U, entries[1]->rule_changes.size()); // Check third entry. EXPECT_EQ(0xddb5f41285aa7757ULL, entries[2]->address); EXPECT_EQ(0x1486493370dc5073ULL, entries[2]->size); ASSERT_EQ(0U, entries[2]->initial_rules.size()); ASSERT_EQ(0U, entries[2]->rule_changes.size()); } @@ -585,33 +600,36 @@ entry1->address = 0x2000; entry1->size = 0x900; m.AddStackFrameEntry(entry1); // Second STACK CFI entry, with initial rules but no deltas. Module::StackFrameEntry *entry2 = new Module::StackFrameEntry(); entry2->address = 0x3000; entry2->size = 0x900; - entry2->initial_rules[".cfa"] = Module::Expr("I think that I shall never see"); - entry2->initial_rules["stromboli"] = Module::Expr("a poem lovely as a tree"); - entry2->initial_rules["cannoli"] = Module::Expr("a tree whose hungry mouth is prest"); + entry2->initial_rules[ustr__ZDcfa()] = + Module::Expr("I think that I shall never see"); + entry2->initial_rules[ToUniqueString("stromboli")] = + Module::Expr("a poem lovely as a tree"); + entry2->initial_rules[ToUniqueString("cannoli")] = + Module::Expr("a tree whose hungry mouth is prest"); m.AddStackFrameEntry(entry2); // Third STACK CFI entry, with initial rules and deltas. Module::StackFrameEntry *entry3 = new Module::StackFrameEntry(); entry3->address = 0x1000; entry3->size = 0x900; - entry3->initial_rules[".cfa"] = Module::Expr("Whose woods are these"); - entry3->rule_changes[0x47ceb0f63c269d7fULL]["calzone"] = + entry3->initial_rules[ustr__ZDcfa()] = Module::Expr("Whose woods are these"); + entry3->rule_changes[0x47ceb0f63c269d7fULL][ToUniqueString("calzone")] = Module::Expr("the village though"); - entry3->rule_changes[0x47ceb0f63c269d7fULL]["cannoli"] = + entry3->rule_changes[0x47ceb0f63c269d7fULL][ToUniqueString("cannoli")] = Module::Expr("he will not see me stopping here"); - entry3->rule_changes[0x36682fad3763ffffULL]["stromboli"] = + entry3->rule_changes[0x36682fad3763ffffULL][ToUniqueString("stromboli")] = Module::Expr("his house is in"); - entry3->rule_changes[0x36682fad3763ffffULL][".cfa"] = + entry3->rule_changes[0x36682fad3763ffffULL][ustr__ZDcfa()] = Module::Expr("I think I know"); m.AddStackFrameEntry(entry3); Module::StackFrameEntry* s = m.FindStackFrameEntryByAddress(0x1000); EXPECT_EQ(entry3, s); s = m.FindStackFrameEntryByAddress(0x18FF); EXPECT_EQ(entry3, s); diff --git a/src/common/unique_string.cc b/src/common/unique_string.cc new file mode 100644 --- /dev/null +++ b/src/common/unique_string.cc @@ -0,0 +1,110 @@ +// Copyright (c) 2013 Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include +#include + +#include +#include + +#include "common/unique_string.h" + +namespace google_breakpad { + +/////////////////////////////////////////////////////////////////// +// UniqueString +// +class UniqueString { + public: + UniqueString(string str) { str_ = strdup(str.c_str()); } + ~UniqueString() { free(reinterpret_cast(const_cast(str_))); } + const char* str_; +}; + +class UniqueStringUniverse { + public: + UniqueStringUniverse() {}; + const UniqueString* FindOrCopy(string str) { + std::map::iterator it = map_.find(str); + if (it == map_.end()) { + UniqueString* ustr = new UniqueString(str); + map_[str] = ustr; + return ustr; + } else { + return it->second; + } + } + private: + std::map map_; +}; + +// +/////////////////////////////////////////////////////////////////// + + +static UniqueStringUniverse* sUSU = NULL; + + +// This isn't threadsafe. +const UniqueString* ToUniqueString(string str) { + if (!sUSU) { + sUSU = new UniqueStringUniverse(); + } + return sUSU->FindOrCopy(str); +} + +// This isn't threadsafe. +const UniqueString* ToUniqueString_n(const char* str, size_t n) { + if (!sUSU) { + sUSU = new UniqueStringUniverse(); + } + string key(str, n); + return sUSU->FindOrCopy(key); +} + +const char Index(const UniqueString* us, int ix) +{ + return us->str_[ix]; +} + +const char* const FromUniqueString(const UniqueString* ustr) +{ + return ustr->str_; +} + +int StrcmpUniqueString(const UniqueString* us1, const UniqueString* us2) { + return strcmp(us1->str_, us2->str_); +} + +bool LessThan_UniqueString(const UniqueString* us1, const UniqueString* us2) { + int r = StrcmpUniqueString(us1, us2); + return r < 0; +} + +} // namespace google_breakpad diff --git a/src/common/unique_string.h b/src/common/unique_string.h new file mode 100644 --- /dev/null +++ b/src/common/unique_string.h @@ -0,0 +1,239 @@ +// Copyright (c) 2013 Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifndef COMMON_UNIQUE_STRING_H_ +#define COMMON_UNIQUE_STRING_H_ + +#include +#include "common/using_std_string.h" + +namespace google_breakpad { + +// Abstract type +class UniqueString; + +// Unique-ify a string. |ToUniqueString| can never return NULL. +const UniqueString* ToUniqueString(string); + +// ditto, starting instead from the first n characters of a C string +const UniqueString* ToUniqueString_n(const char* str, size_t n); + +// Pull chars out of the string. No range checking. +const char Index(const UniqueString*, int); + +// Get the contained C string (debugging only) +const char* const FromUniqueString(const UniqueString*); + +// Do a strcmp-style comparison on the contained C string +int StrcmpUniqueString(const UniqueString*, const UniqueString*); + +// Less-than comparison of two UniqueStrings, usable for std::sort. +bool LessThan_UniqueString(const UniqueString*, const UniqueString*); + +// Some handy pre-uniqified strings. Z is an escape character: +// ZS '$' +// ZD '.' +// Zeq '=' +// Zplus '+' +// Zstar '*' +// Zslash '/' +// Zpercent '%' +// Zat '@' +// Zcaret '^' + +// Note that ustr__empty and (UniqueString*)NULL are considered +// to be different. +// +// Unfortunately these have to be written as functions so as to +// make them safe to use in static initialisers. + +// "" +inline static const UniqueString* ustr__empty() { + static const UniqueString* us = NULL; + if (!us) us = ToUniqueString(""); + return us; +} + +// "$eip" +inline static const UniqueString* ustr__ZSeip() { + static const UniqueString* us = NULL; + if (!us) us = ToUniqueString("$eip"); + return us; +} + +// "$ebp" +inline static const UniqueString* ustr__ZSebp() { + static const UniqueString* us = NULL; + if (!us) us = ToUniqueString("$ebp"); + return us; +} + +// "$esp" +inline static const UniqueString* ustr__ZSesp() { + static const UniqueString* us = NULL; + if (!us) us = ToUniqueString("$esp"); + return us; +} + +// "$ebx" +inline static const UniqueString* ustr__ZSebx() { + static const UniqueString* us = NULL; + if (!us) us = ToUniqueString("$ebx"); + return us; +} + +// "$esi" +inline static const UniqueString* ustr__ZSesi() { + static const UniqueString* us = NULL; + if (!us) us = ToUniqueString("$esi"); + return us; +} + +// "$edi" +inline static const UniqueString* ustr__ZSedi() { + static const UniqueString* us = NULL; + if (!us) us = ToUniqueString("$edi"); + return us; +} + +// ".cbCalleeParams" +inline static const UniqueString* ustr__ZDcbCalleeParams() { + static const UniqueString* us = NULL; + if (!us) us = ToUniqueString(".cbCalleeParams"); + return us; +} + +// ".cbSavedRegs" +inline static const UniqueString* ustr__ZDcbSavedRegs() { + static const UniqueString* us = NULL; + if (!us) us = ToUniqueString(".cbSavedRegs"); + return us; +} + +// ".cbLocals" +inline static const UniqueString* ustr__ZDcbLocals() { + static const UniqueString* us = NULL; + if (!us) us = ToUniqueString(".cbLocals"); + return us; +} + +// ".raSearchStart" +inline static const UniqueString* ustr__ZDraSearchStart() { + static const UniqueString* us = NULL; + if (!us) us = ToUniqueString(".raSearchStart"); + return us; +} + +// ".raSearch" +inline static const UniqueString* ustr__ZDraSearch() { + static const UniqueString* us = NULL; + if (!us) us = ToUniqueString(".raSearch"); + return us; +} + +// ".cbParams" +inline static const UniqueString* ustr__ZDcbParams() { + static const UniqueString* us = NULL; + if (!us) us = ToUniqueString(".cbParams"); + return us; +} + +// "+" +inline static const UniqueString* ustr__Zplus() { + static const UniqueString* us = NULL; + if (!us) us = ToUniqueString("+"); + return us; +} + +// "-" +inline static const UniqueString* ustr__Zminus() { + static const UniqueString* us = NULL; + if (!us) us = ToUniqueString("-"); + return us; +} + +// "*" +inline static const UniqueString* ustr__Zstar() { + static const UniqueString* us = NULL; + if (!us) us = ToUniqueString("*"); + return us; +} + +// "/" +inline static const UniqueString* ustr__Zslash() { + static const UniqueString* us = NULL; + if (!us) us = ToUniqueString("/"); + return us; +} + +// "%" +inline static const UniqueString* ustr__Zpercent() { + static const UniqueString* us = NULL; + if (!us) us = ToUniqueString("%"); + return us; +} + +// "@" +inline static const UniqueString* ustr__Zat() { + static const UniqueString* us = NULL; + if (!us) us = ToUniqueString("@"); + return us; +} + +// "^" +inline static const UniqueString* ustr__Zcaret() { + static const UniqueString* us = NULL; + if (!us) us = ToUniqueString("^"); + return us; +} + +// "=" +inline static const UniqueString* ustr__Zeq() { + static const UniqueString* us = NULL; + if (!us) us = ToUniqueString("="); + return us; +} + +// ".cfa" +inline static const UniqueString* ustr__ZDcfa() { + static const UniqueString* us = NULL; + if (!us) us = ToUniqueString(".cfa"); + return us; +} + +// ".ra" +inline static const UniqueString* ustr__ZDra() { + static const UniqueString* us = NULL; + if (!us) us = ToUniqueString(".ra"); + return us; +} + +} // namespace google_breakpad + +#endif // COMMON_UNIQUE_STRING_H_ diff --git a/src/processor/basic_source_line_resolver_unittest.cc b/src/processor/basic_source_line_resolver_unittest.cc --- a/src/processor/basic_source_line_resolver_unittest.cc +++ b/src/processor/basic_source_line_resolver_unittest.cc @@ -43,21 +43,30 @@ #include "processor/windows_frame_info.h" #include "processor/cfi_frame_info.h" namespace { using google_breakpad::BasicSourceLineResolver; using google_breakpad::CFIFrameInfo; using google_breakpad::CodeModule; +using google_breakpad::FromUniqueString; using google_breakpad::MemoryRegion; using google_breakpad::StackFrame; +using google_breakpad::ToUniqueString; using google_breakpad::WindowsFrameInfo; using google_breakpad::linked_ptr; using google_breakpad::scoped_ptr; +using google_breakpad::ustr__ZDcfa; +using google_breakpad::ustr__ZDra; +using google_breakpad::ustr__ZSebx; +using google_breakpad::ustr__ZSebp; +using google_breakpad::ustr__ZSedi; +using google_breakpad::ustr__ZSesi; +using google_breakpad::ustr__ZSesp; class TestCodeModule : public CodeModule { public: TestCodeModule(string code_file) : code_file_(code_file) {} virtual ~TestCodeModule() {} virtual uint64_t base_address() const { return 0; } virtual uint64_t size() const { return 0xb000; } @@ -107,34 +116,34 @@ // association. (That is, ACTUAL's associations should be a subset of // EXPECTED's.) Also verify that ACTUAL has associations for ".ra" and // ".cfa". static bool VerifyRegisters( const char *file, int line, const CFIFrameInfo::RegisterValueMap &expected, const CFIFrameInfo::RegisterValueMap &actual) { CFIFrameInfo::RegisterValueMap::const_iterator a; - a = actual.find(".cfa"); + a = actual.find(ustr__ZDcfa()); if (a == actual.end()) return false; - a = actual.find(".ra"); + a = actual.find(ustr__ZDra()); if (a == actual.end()) return false; for (a = actual.begin(); a != actual.end(); a++) { CFIFrameInfo::RegisterValueMap::const_iterator e = expected.find(a->first); if (e == expected.end()) { fprintf(stderr, "%s:%d: unexpected register '%s' recovered, value 0x%x\n", - file, line, a->first.c_str(), a->second); + file, line, FromUniqueString(a->first), a->second); return false; } if (e->second != a->second) { fprintf(stderr, "%s:%d: register '%s' recovered value was 0x%x, expected 0x%x\n", - file, line, a->first.c_str(), a->second, e->second); + file, line, FromUniqueString(a->first), a->second, e->second); return false; } // Don't complain if this doesn't recover all registers. Although // the DWARF spec says that unmentioned registers are undefined, // GCC uses omission to mean that they are unchanged. } return true; } @@ -254,81 +263,81 @@ CFIFrameInfo::RegisterValueMap current_registers; CFIFrameInfo::RegisterValueMap caller_registers; CFIFrameInfo::RegisterValueMap expected_caller_registers; MockMemoryRegion memory; // Regardless of which instruction evaluation takes place at, it // should produce the same values for the caller's registers. - expected_caller_registers[".cfa"] = 0x1001c; - expected_caller_registers[".ra"] = 0xf6438648; - expected_caller_registers["$ebp"] = 0x10038; - expected_caller_registers["$ebx"] = 0x98ecadc3; - expected_caller_registers["$esi"] = 0x878f7524; - expected_caller_registers["$edi"] = 0x6312f9a5; + expected_caller_registers[ustr__ZDcfa()] = 0x1001c; + expected_caller_registers[ustr__ZDra()] = 0xf6438648; + expected_caller_registers[ustr__ZSebp()] = 0x10038; + expected_caller_registers[ustr__ZSebx()] = 0x98ecadc3; + expected_caller_registers[ustr__ZSesi()] = 0x878f7524; + expected_caller_registers[ustr__ZSedi()] = 0x6312f9a5; frame.instruction = 0x3d40; frame.module = &module1; current_registers.clear(); - current_registers["$esp"] = 0x10018; - current_registers["$ebp"] = 0x10038; - current_registers["$ebx"] = 0x98ecadc3; - current_registers["$esi"] = 0x878f7524; - current_registers["$edi"] = 0x6312f9a5; + current_registers[ustr__ZSesp()] = 0x10018; + current_registers[ustr__ZSebp()] = 0x10038; + current_registers[ustr__ZSebx()] = 0x98ecadc3; + current_registers[ustr__ZSesi()] = 0x878f7524; + current_registers[ustr__ZSedi()] = 0x6312f9a5; cfi_frame_info.reset(resolver.FindCFIFrameInfo(&frame)); ASSERT_TRUE(cfi_frame_info.get()); ASSERT_TRUE(cfi_frame_info.get() ->FindCallerRegs(current_registers, memory, &caller_registers)); ASSERT_TRUE(VerifyRegisters(__FILE__, __LINE__, expected_caller_registers, caller_registers)); frame.instruction = 0x3d41; - current_registers["$esp"] = 0x10014; + current_registers[ustr__ZSesp()] = 0x10014; cfi_frame_info.reset(resolver.FindCFIFrameInfo(&frame)); ASSERT_TRUE(cfi_frame_info.get()); ASSERT_TRUE(cfi_frame_info.get() ->FindCallerRegs(current_registers, memory, &caller_registers)); ASSERT_TRUE(VerifyRegisters(__FILE__, __LINE__, expected_caller_registers, caller_registers)); frame.instruction = 0x3d43; - current_registers["$ebp"] = 0x10014; + current_registers[ustr__ZSebp()] = 0x10014; cfi_frame_info.reset(resolver.FindCFIFrameInfo(&frame)); ASSERT_TRUE(cfi_frame_info.get()); ASSERT_TRUE(cfi_frame_info.get() ->FindCallerRegs(current_registers, memory, &caller_registers)); VerifyRegisters(__FILE__, __LINE__, expected_caller_registers, caller_registers); frame.instruction = 0x3d54; - current_registers["$ebx"] = 0x6864f054U; + current_registers[ustr__ZSebx()] = 0x6864f054U; cfi_frame_info.reset(resolver.FindCFIFrameInfo(&frame)); ASSERT_TRUE(cfi_frame_info.get()); ASSERT_TRUE(cfi_frame_info.get() ->FindCallerRegs(current_registers, memory, &caller_registers)); VerifyRegisters(__FILE__, __LINE__, expected_caller_registers, caller_registers); frame.instruction = 0x3d5a; - current_registers["$esi"] = 0x6285f79aU; + current_registers[ustr__ZSesi()] = 0x6285f79aU; cfi_frame_info.reset(resolver.FindCFIFrameInfo(&frame)); ASSERT_TRUE(cfi_frame_info.get()); ASSERT_TRUE(cfi_frame_info.get() ->FindCallerRegs(current_registers, memory, &caller_registers)); VerifyRegisters(__FILE__, __LINE__, expected_caller_registers, caller_registers); frame.instruction = 0x3d84; - current_registers["$edi"] = 0x64061449U; + current_registers[ustr__ZSedi()] = 0x64061449U; cfi_frame_info.reset(resolver.FindCFIFrameInfo(&frame)); ASSERT_TRUE(cfi_frame_info.get()); ASSERT_TRUE(cfi_frame_info.get() ->FindCallerRegs(current_registers, memory, &caller_registers)); VerifyRegisters(__FILE__, __LINE__, expected_caller_registers, caller_registers); diff --git a/src/processor/cfi_frame_info.cc b/src/processor/cfi_frame_info.cc --- a/src/processor/cfi_frame_info.cc +++ b/src/processor/cfi_frame_info.cc @@ -31,16 +31,17 @@ // cfi_frame_info.cc: Implementation of CFIFrameInfo class. // See cfi_frame_info.h for details. #include "processor/cfi_frame_info.h" #include +#include #include #include "common/scoped_ptr.h" #include "processor/postfix_evaluator-inl.h" namespace google_breakpad { #ifdef _WIN32 @@ -65,33 +66,33 @@ V cfa; working = registers; if (!evaluator.EvaluateForValue(cfa_rule_, &cfa)) return false; // Then, compute the return address. V ra; working = registers; - working[".cfa"] = cfa; + working[ustr__ZDcfa()] = cfa; if (!evaluator.EvaluateForValue(ra_rule_, &ra)) return false; // Now, compute values for all the registers register_rules_ mentions. for (RuleMap::const_iterator it = register_rules_.begin(); it != register_rules_.end(); it++) { V value; working = registers; - working[".cfa"] = cfa; + working[ustr__ZDcfa()] = cfa; if (!evaluator.EvaluateForValue(it->second, &value)) return false; (*caller_registers)[it->first] = value; } - (*caller_registers)[".ra"] = ra; - (*caller_registers)[".cfa"] = cfa; + (*caller_registers)[ustr__ZDra()] = ra; + (*caller_registers)[ustr__ZDcfa()] = cfa; return true; } // Explicit instantiations for 32-bit and 64-bit architectures. template bool CFIFrameInfo::FindCallerRegs( const RegisterValueMap ®isters, const MemoryRegion &memory, @@ -107,81 +108,98 @@ if (!cfa_rule_.invalid()) { stream << ".cfa: " << cfa_rule_; } if (!ra_rule_.invalid()) { if (static_cast(stream.tellp()) != 0) stream << " "; stream << ".ra: " << ra_rule_; } + + // Visit the register rules in alphabetical order. Because + // register_rules_ has the elements in some arbitrary order, + // get the names out into a vector, sort them, and visit in + // sorted order. + std::vector rr_names; for (RuleMap::const_iterator iter = register_rules_.begin(); iter != register_rules_.end(); ++iter) { + rr_names.push_back(iter->first); + } + + std::sort(rr_names.begin(), rr_names.end(), LessThan_UniqueString); + + // Now visit the register rules in alphabetical order. + for (std::vector::const_iterator name = rr_names.begin(); + name != rr_names.end(); + ++name) { + const UniqueString* nm = *name; + Module::Expr rule = register_rules_.find(nm)->second; if (static_cast(stream.tellp()) != 0) stream << " "; - stream << iter->first << ": " << iter->second; + stream << FromUniqueString(nm) << ": " << rule; } return stream.str(); } bool CFIRuleParser::Parse(const string &rule_set) { size_t rule_set_len = rule_set.size(); scoped_array working_copy(new char[rule_set_len + 1]); memcpy(working_copy.get(), rule_set.data(), rule_set_len); working_copy[rule_set_len] = '\0'; - name_.clear(); + name_ = ustr__empty(); expression_.clear(); char *cursor; static const char token_breaks[] = " \t\r\n"; char *token = strtok_r(working_copy.get(), token_breaks, &cursor); for (;;) { // End of rule set? if (!token) return Report(); // Register/pseudoregister name? size_t token_len = strlen(token); if (token_len >= 1 && token[token_len - 1] == ':') { // Names can't be empty. if (token_len < 2) return false; // If there is any pending content, report it. - if (!name_.empty() || !expression_.empty()) { + if (name_ != ustr__empty() || !expression_.empty()) { if (!Report()) return false; } - name_.assign(token, token_len - 1); + name_ = ToUniqueString_n(token, token_len - 1); expression_.clear(); } else { // Another expression component. assert(token_len > 0); // strtok_r guarantees this, I think. if (!expression_.empty()) expression_ += ' '; expression_ += token; } token = strtok_r(NULL, token_breaks, &cursor); } } bool CFIRuleParser::Report() { - if (name_.empty() || expression_.empty()) return false; - if (name_ == ".cfa") handler_->CFARule(expression_); - else if (name_ == ".ra") handler_->RARule(expression_); + if (name_ == ustr__empty() || expression_.empty()) return false; + if (name_ == ustr__ZDcfa()) handler_->CFARule(expression_); + else if (name_ == ustr__ZDra()) handler_->RARule(expression_); else handler_->RegisterRule(name_, expression_); return true; } void CFIFrameInfoParseHandler::CFARule(const string &expression) { // 'expression' is a postfix expression string. frame_info_->SetCFARule(Module::Expr(expression)); } void CFIFrameInfoParseHandler::RARule(const string &expression) { frame_info_->SetRARule(Module::Expr(expression)); } -void CFIFrameInfoParseHandler::RegisterRule(const string &name, +void CFIFrameInfoParseHandler::RegisterRule(const UniqueString* name, const string &expression) { frame_info_->SetRegisterRule(name, Module::Expr(expression)); } } // namespace google_breakpad diff --git a/src/processor/cfi_frame_info.h b/src/processor/cfi_frame_info.h --- a/src/processor/cfi_frame_info.h +++ b/src/processor/cfi_frame_info.h @@ -37,16 +37,17 @@ #ifndef PROCESSOR_CFI_FRAME_INFO_H_ #define PROCESSOR_CFI_FRAME_INFO_H_ #include #include #include "common/using_std_string.h" +#include "common/unique_string.h" #include "google_breakpad/common/breakpad_types.h" #include "common/module.h" namespace google_breakpad { using std::map; class MemoryRegion; @@ -63,24 +64,24 @@ // changes given by the 'STACK CFI' records up to our instruction's // address. Then, use the FindCallerRegs member function to apply the // rules to the callee frame's register values, yielding the caller // frame's register values. class CFIFrameInfo { public: // A map from register names onto values. template class RegisterValueMap: - public map { }; + public map { }; // Set the expression for computing a call frame address, return // address, or register's value. At least the CFA rule and the RA // rule must be set before calling FindCallerRegs. void SetCFARule(const Module::Expr& rule) { cfa_rule_ = rule; } void SetRARule(const Module::Expr& rule) { ra_rule_ = rule; } - void SetRegisterRule(const string& register_name, + void SetRegisterRule(const UniqueString* register_name, const Module::Expr& rule) { register_rules_[register_name] = rule; } // Compute the values of the calling frame's registers, according to // this rule set. Use ValueType in expression evaluation; this // should be uint32_t on machines with 32-bit addresses, or // uint64_t on machines with 64-bit addresses. @@ -104,17 +105,17 @@ // Serialize the rules in this object into a string in the format // of STACK CFI records. string Serialize() const; private: // A map from register names onto evaluation rules. - typedef map RuleMap; + typedef map RuleMap; // An expression for computing the current frame's CFA (call // frame address). The CFA is a reference address for the frame that // remains unchanged throughout the frame's lifetime. You should // evaluate this expression with a dictionary initially populated // with the values of the current frame's known registers. Module::Expr cfa_rule_; @@ -145,17 +146,18 @@ Handler() { } virtual ~Handler() { } // The input specifies EXPRESSION as the CFA/RA computation rule. virtual void CFARule(const string &expression) = 0; virtual void RARule(const string &expression) = 0; // The input specifies EXPRESSION as the recovery rule for register NAME. - virtual void RegisterRule(const string &name, const string &expression) = 0; + virtual void RegisterRule(const UniqueString* name, + const string &expression) = 0; }; // Construct a parser which feeds its results to HANDLER. CFIRuleParser(Handler *handler) : handler_(handler) { } // Parse RULE_SET as a set of CFA computation and RA/register // recovery rules, as appearing in STACK CFI records. Report the // results of parsing by making the appropriate calls to handler_. @@ -165,30 +167,31 @@ private: // Report any accumulated rule to handler_ bool Report(); // The handler to which the parser reports its findings. Handler *handler_; // Working data. - string name_, expression_; + const UniqueString* name_; + string expression_; }; // A handler for rule set parsing that populates a CFIFrameInfo with // the results. class CFIFrameInfoParseHandler: public CFIRuleParser::Handler { public: // Populate FRAME_INFO with the results of parsing. CFIFrameInfoParseHandler(CFIFrameInfo *frame_info) : frame_info_(frame_info) { } void CFARule(const string &expression); void RARule(const string &expression); - void RegisterRule(const string &name, const string &expression); + void RegisterRule(const UniqueString* name, const string &expression); private: CFIFrameInfo *frame_info_; }; // A utility class template for simple 'STACK CFI'-driven stack walkers. // Given a CFIFrameInfo instance, a table describing the architecture's // register set, and a context holding the last frame's registers, an @@ -205,24 +208,24 @@ // uint32_t or uint64_t. RawContextType should be the raw context // structure type for this architecture. template class SimpleCFIWalker { public: // A structure describing one architecture register. struct RegisterSet { // The register name, as it appears in STACK CFI rules. - const char *name; + const UniqueString* 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 UniqueString* alternate_name; // True if the callee is expected to preserve the value of this // register. If this flag is true for some register R, and the STACK // CFI records provide no rule to recover R, then SimpleCFIWalker // assumes that the callee has not changed R's value, and the caller's // value for R is that currently in the callee's context. bool callee_saves; diff --git a/src/processor/cfi_frame_info_unittest.cc b/src/processor/cfi_frame_info_unittest.cc --- a/src/processor/cfi_frame_info_unittest.cc +++ b/src/processor/cfi_frame_info_unittest.cc @@ -38,19 +38,24 @@ #include "common/module.h" #include "common/using_std_string.h" #include "processor/cfi_frame_info.h" #include "google_breakpad/processor/memory_region.h" using google_breakpad::CFIFrameInfo; using google_breakpad::CFIFrameInfoParseHandler; using google_breakpad::CFIRuleParser; +using google_breakpad::FromUniqueString; using google_breakpad::MemoryRegion; using google_breakpad::Module; using google_breakpad::SimpleCFIWalker; +using google_breakpad::ToUniqueString; +using google_breakpad::UniqueString; +using google_breakpad::ustr__ZDcfa; +using google_breakpad::ustr__ZDra; using testing::_; using testing::A; using testing::AtMost; using testing::DoAll; using testing::Return; using testing::SetArgumentPointee; using testing::Test; @@ -107,41 +112,47 @@ TEST_F(Simple, SetCFAAndRARule) { ExpectNoMemoryReferences(); cfi.SetCFARule(Module::Expr("330903416631436410")); cfi.SetRARule(Module::Expr("5870666104170902211")); ASSERT_TRUE(cfi.FindCallerRegs(registers, memory, &caller_registers)); ASSERT_EQ(2U, caller_registers.size()); - ASSERT_EQ(330903416631436410ULL, caller_registers[".cfa"]); - ASSERT_EQ(5870666104170902211ULL, caller_registers[".ra"]); + ASSERT_EQ(330903416631436410ULL, caller_registers[ustr__ZDcfa()]); + ASSERT_EQ(5870666104170902211ULL, caller_registers[ustr__ZDra()]); ASSERT_EQ(".cfa: 330903416631436410 .ra: 5870666104170902211", cfi.Serialize()); } TEST_F(Simple, SetManyRules) { ExpectNoMemoryReferences(); cfi.SetCFARule(Module::Expr("$temp1 68737028 = $temp2 61072337 = $temp1 $temp2 -")); cfi.SetRARule(Module::Expr(".cfa 99804755 +")); - cfi.SetRegisterRule("register1", Module::Expr(".cfa 54370437 *")); - cfi.SetRegisterRule("vodkathumbscrewingly", Module::Expr("24076308 .cfa +")); - cfi.SetRegisterRule("pubvexingfjordschmaltzy", Module::Expr(".cfa 29801007 -")); - cfi.SetRegisterRule("uncopyrightables", Module::Expr("92642917 .cfa /")); + + const UniqueString* reg1 = ToUniqueString("register1"); + const UniqueString* reg2 = ToUniqueString("vodkathumbscrewingly"); + const UniqueString* reg3 = ToUniqueString("pubvexingfjordschmaltzy"); + const UniqueString* reg4 = ToUniqueString("uncopyrightables"); + + cfi.SetRegisterRule(reg1, Module::Expr(".cfa 54370437 *")); + cfi.SetRegisterRule(reg2, Module::Expr("24076308 .cfa +")); + cfi.SetRegisterRule(reg3, Module::Expr(".cfa 29801007 -")); + cfi.SetRegisterRule(reg4, Module::Expr("92642917 .cfa /")); ASSERT_TRUE(cfi.FindCallerRegs(registers, memory, &caller_registers)); ASSERT_EQ(6U, caller_registers.size()); - ASSERT_EQ(7664691U, caller_registers[".cfa"]); - ASSERT_EQ(107469446U, caller_registers[".ra"]); - ASSERT_EQ(416732599139967ULL, caller_registers["register1"]); - ASSERT_EQ(31740999U, caller_registers["vodkathumbscrewingly"]); - ASSERT_EQ(-22136316ULL, caller_registers["pubvexingfjordschmaltzy"]); - ASSERT_EQ(12U, caller_registers["uncopyrightables"]); + ASSERT_EQ(7664691U, caller_registers[ustr__ZDcfa()]); + ASSERT_EQ(107469446U, caller_registers[ustr__ZDra()]); + ASSERT_EQ(416732599139967ULL, caller_registers[reg1]); + ASSERT_EQ(31740999U, caller_registers[reg2]); + ASSERT_EQ(-22136316ULL, caller_registers[reg3]); + ASSERT_EQ(12U, caller_registers[reg4]); ASSERT_EQ(".cfa: $temp1 68737028 = $temp2 61072337 = $temp1 $temp2 - " ".ra: .cfa 99804755 + " "pubvexingfjordschmaltzy: .cfa 29801007 - " "register1: .cfa 54370437 * " "uncopyrightables: 92642917 .cfa / " "vodkathumbscrewingly: 24076308 .cfa +", cfi.Serialize()); } @@ -150,18 +161,18 @@ ExpectNoMemoryReferences(); cfi.SetCFARule(Module::Expr("330903416631436410")); cfi.SetRARule(Module::Expr("5870666104170902211")); cfi.SetCFARule(Module::Expr("2828089117179001")); ASSERT_TRUE(cfi.FindCallerRegs(registers, memory, &caller_registers)); ASSERT_EQ(2U, caller_registers.size()); - ASSERT_EQ(2828089117179001ULL, caller_registers[".cfa"]); - ASSERT_EQ(5870666104170902211ULL, caller_registers[".ra"]); + ASSERT_EQ(2828089117179001ULL, caller_registers[ustr__ZDcfa()]); + ASSERT_EQ(5870666104170902211ULL, caller_registers[ustr__ZDra()]); ASSERT_EQ(".cfa: 2828089117179001 .ra: 5870666104170902211", cfi.Serialize()); } class Scope: public CFIFixture, public Test { }; // There should be no value for .cfa in scope when evaluating the CFA rule. TEST_F(Scope, CFALacksCFA) { @@ -183,37 +194,39 @@ &caller_registers)); } // The current frame's registers should be in scope when evaluating // the CFA rule. TEST_F(Scope, CFASeesCurrentRegs) { ExpectNoMemoryReferences(); - registers[".baraminology"] = 0x06a7bc63e4f13893ULL; - registers[".ornithorhynchus"] = 0x5e0bf850bafce9d2ULL; + const UniqueString* reg1 = ToUniqueString(".baraminology"); + const UniqueString* reg2 = ToUniqueString(".ornithorhynchus"); + registers[reg1] = 0x06a7bc63e4f13893ULL; + registers[reg2] = 0x5e0bf850bafce9d2ULL; cfi.SetCFARule(Module::Expr(".baraminology .ornithorhynchus +")); cfi.SetRARule(Module::Expr("0")); ASSERT_TRUE(cfi.FindCallerRegs(registers, memory, &caller_registers)); ASSERT_EQ(2U, caller_registers.size()); ASSERT_EQ(0x06a7bc63e4f13893ULL + 0x5e0bf850bafce9d2ULL, - caller_registers[".cfa"]); + caller_registers[ustr__ZDcfa()]); } // .cfa should be in scope in the return address expression. TEST_F(Scope, RASeesCFA) { ExpectNoMemoryReferences(); cfi.SetCFARule(Module::Expr("48364076")); cfi.SetRARule(Module::Expr(".cfa")); ASSERT_TRUE(cfi.FindCallerRegs(registers, memory, &caller_registers)); ASSERT_EQ(2U, caller_registers.size()); - ASSERT_EQ(48364076U, caller_registers[".ra"]); + ASSERT_EQ(48364076U, caller_registers[ustr__ZDra()]); } // There should be no value for .ra in scope when evaluating the CFA rule. TEST_F(Scope, RALacksRA) { ExpectNoMemoryReferences(); cfi.SetCFARule(Module::Expr("0")); cfi.SetRARule(Module::Expr(".ra")); @@ -221,64 +234,69 @@ &caller_registers)); } // The current frame's registers should be in scope in the return // address expression. TEST_F(Scope, RASeesCurrentRegs) { ExpectNoMemoryReferences(); - registers["noachian"] = 0x54dc4a5d8e5eb503ULL; cfi.SetCFARule(Module::Expr("10359370")); - cfi.SetRARule(Module::Expr("noachian")); + const UniqueString* reg1 = ToUniqueString("noachian"); + registers[reg1] = 0x54dc4a5d8e5eb503ULL; + cfi.SetRARule(Module::Expr(reg1, 0, false)); ASSERT_TRUE(cfi.FindCallerRegs(registers, memory, &caller_registers)); ASSERT_EQ(2U, caller_registers.size()); - ASSERT_EQ(0x54dc4a5d8e5eb503ULL, caller_registers[".ra"]); + ASSERT_EQ(0x54dc4a5d8e5eb503ULL, caller_registers[ustr__ZDra()]); } // .cfa should be in scope for register rules. TEST_F(Scope, RegistersSeeCFA) { ExpectNoMemoryReferences(); cfi.SetCFARule(Module::Expr("6515179")); cfi.SetRARule(Module::Expr(".cfa")); - cfi.SetRegisterRule("rogerian", Module::Expr(".cfa")); + const UniqueString* reg1 = ToUniqueString("rogerian"); + cfi.SetRegisterRule(reg1, Module::Expr(".cfa")); ASSERT_TRUE(cfi.FindCallerRegs(registers, memory, &caller_registers)); ASSERT_EQ(3U, caller_registers.size()); - ASSERT_EQ(6515179U, caller_registers["rogerian"]); + ASSERT_EQ(6515179U, caller_registers[reg1]); } // The return address should not be in scope for register rules. TEST_F(Scope, RegsLackRA) { ExpectNoMemoryReferences(); cfi.SetCFARule(Module::Expr("42740329")); cfi.SetRARule(Module::Expr("27045204")); - cfi.SetRegisterRule("$r1", Module::Expr(".ra")); + const UniqueString* reg1 = ToUniqueString("$r1"); + cfi.SetRegisterRule(reg1, Module::Expr(".ra")); ASSERT_FALSE(cfi.FindCallerRegs(registers, memory, &caller_registers)); } // Register rules can see the current frame's register values. TEST_F(Scope, RegsSeeRegs) { ExpectNoMemoryReferences(); - registers["$r1"] = 0x6ed3582c4bedb9adULL; - registers["$r2"] = 0xd27d9e742b8df6d0ULL; + const UniqueString* reg1 = ToUniqueString("$r1"); + const UniqueString* reg2 = ToUniqueString("$r2"); + registers[reg1] = 0x6ed3582c4bedb9adULL; + registers[reg2] = 0xd27d9e742b8df6d0ULL; cfi.SetCFARule(Module::Expr("88239303")); cfi.SetRARule(Module::Expr("30503835")); - cfi.SetRegisterRule("$r1", Module::Expr("$r1 42175211 = $r2")); - cfi.SetRegisterRule("$r2", Module::Expr("$r2 21357221 = $r1")); + cfi.SetRegisterRule(reg1, Module::Expr("$r1 42175211 = $r2")); + cfi.SetRegisterRule(reg2, Module::Expr("$r2 21357221 = $r1")); ASSERT_TRUE(cfi.FindCallerRegs(registers, memory, &caller_registers)); ASSERT_EQ(4U, caller_registers.size()); - ASSERT_EQ(0xd27d9e742b8df6d0ULL, caller_registers["$r1"]); - ASSERT_EQ(0x6ed3582c4bedb9adULL, caller_registers["$r2"]); + ASSERT_EQ(0xd27d9e742b8df6d0ULL, caller_registers[reg1]); + ASSERT_EQ(0x6ed3582c4bedb9adULL, caller_registers[reg2]); } // Each rule's temporaries are separate. TEST_F(Scope, SeparateTempsRA) { ExpectNoMemoryReferences(); cfi.SetCFARule(Module::Expr("$temp1 76569129 = $temp1")); cfi.SetRARule(Module::Expr("0")); @@ -290,17 +308,17 @@ ASSERT_FALSE(cfi.FindCallerRegs(registers, memory, &caller_registers)); } class MockCFIRuleParserHandler: public CFIRuleParser::Handler { public: MOCK_METHOD1(CFARule, void(const string &)); MOCK_METHOD1(RARule, void(const string &)); - MOCK_METHOD2(RegisterRule, void(const string &, const string &)); + MOCK_METHOD2(RegisterRule, void(const UniqueString*, const string &)); }; // A fixture class for testing CFIRuleParser. class CFIParserFixture { public: CFIParserFixture() : parser(&mock_handler) { // Expect no parsing results to be reported to mock_handler. Individual // tests can override this. @@ -361,100 +379,100 @@ } TEST_F(Parser, RA) { EXPECT_CALL(mock_handler, RARule("notoriety")).WillOnce(Return()); EXPECT_TRUE(parser.Parse(".ra: notoriety")); } TEST_F(Parser, Reg) { - EXPECT_CALL(mock_handler, RegisterRule("nemo", "mellifluous")) + EXPECT_CALL(mock_handler, RegisterRule(ToUniqueString("nemo"), "mellifluous")) .WillOnce(Return()); EXPECT_TRUE(parser.Parse("nemo: mellifluous")); } TEST_F(Parser, CFARARegs) { EXPECT_CALL(mock_handler, CFARule("cfa expression")).WillOnce(Return()); EXPECT_CALL(mock_handler, RARule("ra expression")).WillOnce(Return()); - EXPECT_CALL(mock_handler, RegisterRule("galba", "praetorian")) + EXPECT_CALL(mock_handler, RegisterRule(ToUniqueString("galba"), "praetorian")) .WillOnce(Return()); - EXPECT_CALL(mock_handler, RegisterRule("otho", "vitellius")) + EXPECT_CALL(mock_handler, RegisterRule(ToUniqueString("otho"), "vitellius")) .WillOnce(Return()); EXPECT_TRUE(parser.Parse(".cfa: cfa expression .ra: ra expression " "galba: praetorian otho: vitellius")); } TEST_F(Parser, Whitespace) { - EXPECT_CALL(mock_handler, RegisterRule("r1", "r1 expression")) + EXPECT_CALL(mock_handler, RegisterRule(ToUniqueString("r1"), "r1 expression")) .WillOnce(Return()); - EXPECT_CALL(mock_handler, RegisterRule("r2", "r2 expression")) + EXPECT_CALL(mock_handler, RegisterRule(ToUniqueString("r2"), "r2 expression")) .WillOnce(Return()); EXPECT_TRUE(parser.Parse(" r1:\tr1\nexpression \tr2:\t\rr2\r\n " "expression \n")); } TEST_F(Parser, WhitespaceLoneColon) { EXPECT_FALSE(parser.Parse(" \n:\t ")); } TEST_F(Parser, EmptyName) { - EXPECT_CALL(mock_handler, RegisterRule("reg", _)) + EXPECT_CALL(mock_handler, RegisterRule(ToUniqueString("reg"), _)) .Times(AtMost(1)) .WillRepeatedly(Return()); EXPECT_FALSE(parser.Parse("reg: expr1 : expr2")); } TEST_F(Parser, RuleLoneColon) { - EXPECT_CALL(mock_handler, RegisterRule("r1", "expr")) + EXPECT_CALL(mock_handler, RegisterRule(ToUniqueString("r1"), "expr")) .Times(AtMost(1)) .WillRepeatedly(Return()); EXPECT_FALSE(parser.Parse(" r1: expr :")); } TEST_F(Parser, RegNoExprRule) { - EXPECT_CALL(mock_handler, RegisterRule("r1", "expr")) + EXPECT_CALL(mock_handler, RegisterRule(ToUniqueString("r1"), "expr")) .Times(AtMost(1)) .WillRepeatedly(Return()); EXPECT_FALSE(parser.Parse("r0: r1: expr")); } class ParseHandlerFixture: public CFIFixture { public: ParseHandlerFixture() : CFIFixture(), handler(&cfi) { } CFIFrameInfoParseHandler handler; }; class ParseHandler: public ParseHandlerFixture, public Test { }; TEST_F(ParseHandler, CFARARule) { handler.CFARule("reg-for-cfa"); handler.RARule("reg-for-ra"); - registers["reg-for-cfa"] = 0x268a9a4a3821a797ULL; - registers["reg-for-ra"] = 0x6301b475b8b91c02ULL; + registers[ToUniqueString("reg-for-cfa")] = 0x268a9a4a3821a797ULL; + registers[ToUniqueString("reg-for-ra")] = 0x6301b475b8b91c02ULL; ASSERT_TRUE(cfi.FindCallerRegs(registers, memory, &caller_registers)); - ASSERT_EQ(0x268a9a4a3821a797ULL, caller_registers[".cfa"]); - ASSERT_EQ(0x6301b475b8b91c02ULL, caller_registers[".ra"]); + ASSERT_EQ(0x268a9a4a3821a797ULL, caller_registers[ustr__ZDcfa()]); + ASSERT_EQ(0x6301b475b8b91c02ULL, caller_registers[ustr__ZDra()]); } TEST_F(ParseHandler, RegisterRules) { handler.CFARule("reg-for-cfa"); handler.RARule("reg-for-ra"); - handler.RegisterRule("reg1", "reg-for-reg1"); - handler.RegisterRule("reg2", "reg-for-reg2"); - registers["reg-for-cfa"] = 0x268a9a4a3821a797ULL; - registers["reg-for-ra"] = 0x6301b475b8b91c02ULL; - registers["reg-for-reg1"] = 0x06cde8e2ff062481ULL; - registers["reg-for-reg2"] = 0xff0c4f76403173e2ULL; + handler.RegisterRule(ToUniqueString("reg1"), "reg-for-reg1"); + handler.RegisterRule(ToUniqueString("reg2"), "reg-for-reg2"); + registers[ToUniqueString("reg-for-cfa")] = 0x268a9a4a3821a797ULL; + registers[ToUniqueString("reg-for-ra")] = 0x6301b475b8b91c02ULL; + registers[ToUniqueString("reg-for-reg1")] = 0x06cde8e2ff062481ULL; + registers[ToUniqueString("reg-for-reg2")] = 0xff0c4f76403173e2ULL; ASSERT_TRUE(cfi.FindCallerRegs(registers, memory, &caller_registers)); - ASSERT_EQ(0x268a9a4a3821a797ULL, caller_registers[".cfa"]); - ASSERT_EQ(0x6301b475b8b91c02ULL, caller_registers[".ra"]); - ASSERT_EQ(0x06cde8e2ff062481ULL, caller_registers["reg1"]); - ASSERT_EQ(0xff0c4f76403173e2ULL, caller_registers["reg2"]); + ASSERT_EQ(0x268a9a4a3821a797ULL, caller_registers[ustr__ZDcfa()]); + ASSERT_EQ(0x6301b475b8b91c02ULL, caller_registers[ustr__ZDra()]); + ASSERT_EQ(0x06cde8e2ff062481ULL, caller_registers[ToUniqueString("reg1")]); + ASSERT_EQ(0xff0c4f76403173e2ULL, caller_registers[ToUniqueString("reg2")]); } struct SimpleCFIWalkerFixture { struct RawContext { uint64_t r0, r1, r2, r3, r4, sp, pc; }; enum Validity { R0_VALID = 0x01, @@ -475,23 +493,23 @@ CFIFrameInfo call_frame_info; CFIWalker walker; MockMemoryRegion memory; RawContext callee_context, caller_context; }; SimpleCFIWalkerFixture::CFIWalker::RegisterSet SimpleCFIWalkerFixture::register_map[7] = { - { "r0", NULL, true, R0_VALID, &RawContext::r0 }, - { "r1", NULL, true, R1_VALID, &RawContext::r1 }, - { "r2", NULL, false, R2_VALID, &RawContext::r2 }, - { "r3", NULL, false, R3_VALID, &RawContext::r3 }, - { "r4", NULL, true, R4_VALID, &RawContext::r4 }, - { "sp", ".cfa", true, SP_VALID, &RawContext::sp }, - { "pc", ".ra", true, PC_VALID, &RawContext::pc }, + { ToUniqueString("r0"), NULL, true, R0_VALID, &RawContext::r0 }, + { ToUniqueString("r1"), NULL, true, R1_VALID, &RawContext::r1 }, + { ToUniqueString("r2"), NULL, false, R2_VALID, &RawContext::r2 }, + { ToUniqueString("r3"), NULL, false, R3_VALID, &RawContext::r3 }, + { ToUniqueString("r4"), NULL, true, R4_VALID, &RawContext::r4 }, + { ToUniqueString("sp"), ustr__ZDcfa(), true, SP_VALID, &RawContext::sp }, + { ToUniqueString("pc"), ustr__ZDra(), true, PC_VALID, &RawContext::pc }, }; class SimpleWalker: public SimpleCFIWalkerFixture, public Test { }; TEST_F(SimpleWalker, Walk) { // Stack_top is the current stack pointer, pointing to the lowest // address of a frame that looks like this (all 64-bit words): // @@ -516,18 +534,20 @@ // Saved return address. EXPECT_CALL(memory, GetMemoryAtAddress(stack_top + 16, A())) .WillRepeatedly(DoAll(SetArgumentPointee<1>(0xba5ad6d9acce28deULL), Return(true))); call_frame_info.SetCFARule(Module::Expr("sp 24 +")); call_frame_info.SetRARule(Module::Expr(".cfa 8 - ^")); - call_frame_info.SetRegisterRule("r0", Module::Expr(".cfa 24 - ^")); - call_frame_info.SetRegisterRule("r1", Module::Expr("r2")); + call_frame_info.SetRegisterRule(ToUniqueString("r0"), + Module::Expr(".cfa 24 - ^")); + call_frame_info.SetRegisterRule(ToUniqueString("r1"), + Module::Expr("r2")); callee_context.r0 = 0x94e030ca79edd119ULL; callee_context.r1 = 0x937b4d7e95ce52d9ULL; callee_context.r2 = 0x5fe0027416b8b62aULL; // caller's r1 // callee_context.r3 is not valid in callee. // callee_context.r4 is not valid in callee. callee_context.sp = stack_top; callee_context.pc = 0x25b21b224311d280ULL; diff --git a/src/processor/fast_source_line_resolver_unittest.cc b/src/processor/fast_source_line_resolver_unittest.cc --- a/src/processor/fast_source_line_resolver_unittest.cc +++ b/src/processor/fast_source_line_resolver_unittest.cc @@ -51,25 +51,34 @@ #include "processor/module_serializer.h" #include "processor/module_comparer.h" namespace { using google_breakpad::SourceLineResolverBase; using google_breakpad::BasicSourceLineResolver; using google_breakpad::FastSourceLineResolver; +using google_breakpad::FromUniqueString; using google_breakpad::ModuleSerializer; using google_breakpad::ModuleComparer; using google_breakpad::CFIFrameInfo; using google_breakpad::CodeModule; using google_breakpad::MemoryRegion; using google_breakpad::StackFrame; +using google_breakpad::ToUniqueString; using google_breakpad::WindowsFrameInfo; using google_breakpad::linked_ptr; using google_breakpad::scoped_ptr; +using google_breakpad::ustr__ZDcfa; +using google_breakpad::ustr__ZDra; +using google_breakpad::ustr__ZSebx; +using google_breakpad::ustr__ZSebp; +using google_breakpad::ustr__ZSedi; +using google_breakpad::ustr__ZSesi; +using google_breakpad::ustr__ZSesp; class TestCodeModule : public CodeModule { public: explicit TestCodeModule(string code_file) : code_file_(code_file) {} virtual ~TestCodeModule() {} virtual uint64_t base_address() const { return 0; } virtual uint64_t size() const { return 0xb000; } @@ -119,34 +128,34 @@ // association. (That is, ACTUAL's associations should be a subset of // EXPECTED's.) Also verify that ACTUAL has associations for ".ra" and // ".cfa". static bool VerifyRegisters( const char *file, int line, const CFIFrameInfo::RegisterValueMap &expected, const CFIFrameInfo::RegisterValueMap &actual) { CFIFrameInfo::RegisterValueMap::const_iterator a; - a = actual.find(".cfa"); + a = actual.find(ustr__ZDcfa()); if (a == actual.end()) return false; - a = actual.find(".ra"); + a = actual.find(ustr__ZDra()); if (a == actual.end()) return false; for (a = actual.begin(); a != actual.end(); a++) { CFIFrameInfo::RegisterValueMap::const_iterator e = expected.find(a->first); if (e == expected.end()) { fprintf(stderr, "%s:%d: unexpected register '%s' recovered, value 0x%x\n", - file, line, a->first.c_str(), a->second); + file, line, FromUniqueString(a->first), a->second); return false; } if (e->second != a->second) { fprintf(stderr, "%s:%d: register '%s' recovered value was 0x%x, expected 0x%x\n", - file, line, a->first.c_str(), a->second, e->second); + file, line, FromUniqueString(a->first), a->second, e->second); return false; } // Don't complain if this doesn't recover all registers. Although // the DWARF spec says that unmentioned registers are undefined, // GCC uses omission to mean that they are unchanged. } return true; } @@ -282,81 +291,81 @@ CFIFrameInfo::RegisterValueMap current_registers; CFIFrameInfo::RegisterValueMap caller_registers; CFIFrameInfo::RegisterValueMap expected_caller_registers; MockMemoryRegion memory; // Regardless of which instruction evaluation takes place at, it // should produce the same values for the caller's registers. - expected_caller_registers[".cfa"] = 0x1001c; - expected_caller_registers[".ra"] = 0xf6438648; - expected_caller_registers["$ebp"] = 0x10038; - expected_caller_registers["$ebx"] = 0x98ecadc3; - expected_caller_registers["$esi"] = 0x878f7524; - expected_caller_registers["$edi"] = 0x6312f9a5; + expected_caller_registers[ustr__ZDcfa()] = 0x1001c; + expected_caller_registers[ustr__ZDra()] = 0xf6438648; + expected_caller_registers[ustr__ZSebp()] = 0x10038; + expected_caller_registers[ustr__ZSebx()] = 0x98ecadc3; + expected_caller_registers[ustr__ZSesi()] = 0x878f7524; + expected_caller_registers[ustr__ZSedi()] = 0x6312f9a5; frame.instruction = 0x3d40; frame.module = &module1; current_registers.clear(); - current_registers["$esp"] = 0x10018; - current_registers["$ebp"] = 0x10038; - current_registers["$ebx"] = 0x98ecadc3; - current_registers["$esi"] = 0x878f7524; - current_registers["$edi"] = 0x6312f9a5; + current_registers[ustr__ZSesp()] = 0x10018; + current_registers[ustr__ZSebp()] = 0x10038; + current_registers[ustr__ZSebx()] = 0x98ecadc3; + current_registers[ustr__ZSesi()] = 0x878f7524; + current_registers[ustr__ZSedi()] = 0x6312f9a5; cfi_frame_info.reset(fast_resolver.FindCFIFrameInfo(&frame)); ASSERT_TRUE(cfi_frame_info.get()); ASSERT_TRUE(cfi_frame_info.get() ->FindCallerRegs(current_registers, memory, &caller_registers)); ASSERT_TRUE(VerifyRegisters(__FILE__, __LINE__, expected_caller_registers, caller_registers)); frame.instruction = 0x3d41; - current_registers["$esp"] = 0x10014; + current_registers[ustr__ZSesp()] = 0x10014; cfi_frame_info.reset(fast_resolver.FindCFIFrameInfo(&frame)); ASSERT_TRUE(cfi_frame_info.get()); ASSERT_TRUE(cfi_frame_info.get() ->FindCallerRegs(current_registers, memory, &caller_registers)); ASSERT_TRUE(VerifyRegisters(__FILE__, __LINE__, expected_caller_registers, caller_registers)); frame.instruction = 0x3d43; - current_registers["$ebp"] = 0x10014; + current_registers[ustr__ZSebp()] = 0x10014; cfi_frame_info.reset(fast_resolver.FindCFIFrameInfo(&frame)); ASSERT_TRUE(cfi_frame_info.get()); ASSERT_TRUE(cfi_frame_info.get() ->FindCallerRegs(current_registers, memory, &caller_registers)); VerifyRegisters(__FILE__, __LINE__, expected_caller_registers, caller_registers); frame.instruction = 0x3d54; - current_registers["$ebx"] = 0x6864f054U; + current_registers[ustr__ZSebx()] = 0x6864f054U; cfi_frame_info.reset(fast_resolver.FindCFIFrameInfo(&frame)); ASSERT_TRUE(cfi_frame_info.get()); ASSERT_TRUE(cfi_frame_info.get() ->FindCallerRegs(current_registers, memory, &caller_registers)); VerifyRegisters(__FILE__, __LINE__, expected_caller_registers, caller_registers); frame.instruction = 0x3d5a; - current_registers["$esi"] = 0x6285f79aU; + current_registers[ustr__ZSesi()] = 0x6285f79aU; cfi_frame_info.reset(fast_resolver.FindCFIFrameInfo(&frame)); ASSERT_TRUE(cfi_frame_info.get()); ASSERT_TRUE(cfi_frame_info.get() ->FindCallerRegs(current_registers, memory, &caller_registers)); VerifyRegisters(__FILE__, __LINE__, expected_caller_registers, caller_registers); frame.instruction = 0x3d84; - current_registers["$edi"] = 0x64061449U; + current_registers[ustr__ZSedi()] = 0x64061449U; cfi_frame_info.reset(fast_resolver.FindCFIFrameInfo(&frame)); ASSERT_TRUE(cfi_frame_info.get()); ASSERT_TRUE(cfi_frame_info.get() ->FindCallerRegs(current_registers, memory, &caller_registers)); VerifyRegisters(__FILE__, __LINE__, expected_caller_registers, caller_registers); diff --git a/src/processor/postfix_evaluator-inl.h b/src/processor/postfix_evaluator-inl.h --- a/src/processor/postfix_evaluator-inl.h +++ b/src/processor/postfix_evaluator-inl.h @@ -51,23 +51,25 @@ namespace google_breakpad { using std::istringstream; using std::ostringstream; // A small class used in Evaluate to make sure to clean up the stack // before returning failure. +template class AutoStackClearer { public: - explicit AutoStackClearer(vector *stack) : stack_(stack) {} + explicit AutoStackClearer(vector > *stack) + : stack_(stack) {} ~AutoStackClearer() { stack_->clear(); } private: - vector *stack_; + vector > *stack_; }; template bool PostfixEvaluator::EvaluateToken( const string &token, const string &expression, DictionaryValidityType *assigned) { @@ -170,38 +172,57 @@ BPLOG(INFO) << "Could not PopValue to get value to assign: " << expression; return false; } // Assignment is only meaningful when assigning into an identifier. // The identifier must name a variable, not a constant. Variables // begin with '$'. - string identifier; + const UniqueString* identifier; if (PopValueOrIdentifier(NULL, &identifier) != POP_RESULT_IDENTIFIER) { BPLOG(ERROR) << "PopValueOrIdentifier returned a value, but an " "identifier is needed to assign " << HexString(value) << ": " << expression; return false; } - if (identifier.empty() || identifier[0] != '$') { + if (identifier == ustr__empty() || Index(identifier,0) != '$') { BPLOG(ERROR) << "Can't assign " << HexString(value) << " to " << identifier << ": " << expression; return false; } (*dictionary_)[identifier] = value; if (assigned) (*assigned)[identifier] = true; } else { - // The token is not an operator, it's a literal value or an identifier. - // Push it onto the stack as-is. Use push_back instead of PushValue - // because PushValue pushes ValueType as a string, but token is already - // a string. - stack_.push_back(token); + // Push it onto the stack as-is, but first convert it either to a + // ValueType (if a literal) or to a UniqueString* (if an identifier). + // + // First, try to treat the value as a literal. Literals may have leading + // '-' sign, and the entire remaining string must be parseable as + // ValueType. If this isn't possible, it can't be a literal, so treat it + // as an identifier instead. + // + // Some versions of the libstdc++, the GNU standard C++ library, have + // stream extractors for unsigned integer values that permit a leading + // '-' sign (6.0.13); others do not (6.0.9). Since we require it, we + // handle it explicitly here. + istringstream token_stream(token); + ValueType literal = ValueType(); + bool negative = false; + if (token_stream.peek() == '-') { + negative = true; + token_stream.get(); + } + if (token_stream >> literal && token_stream.peek() == EOF) { + PushValue(negative ? (-literal) : literal); + } else { + PushIdentifier(ToUniqueString(token)); + } } return true; } template bool PostfixEvaluator::EvaluateInternal( const string &expression, DictionaryValidityType *assigned) { @@ -236,17 +257,17 @@ // The expression is being exevaluated only for its side effects. Skip // expressions that denote values only. if (expr.how_ != Module::kExprPostfix) { BPLOG(ERROR) << "Can't evaluate for side-effects: " << expr; return false; } // Ensure that the stack is cleared before returning. - AutoStackClearer clearer(&stack_); + AutoStackClearer clearer(&stack_); if (!EvaluateInternal(expr.postfix_, assigned)) return false; // If there's anything left on the stack, it indicates incomplete execution. // This is a failure case. If the stack is empty, evalution was complete // and successful. if (stack_.empty()) @@ -260,17 +281,17 @@ bool PostfixEvaluator::EvaluateForValue(const Module::Expr& expr, ValueType* result) { switch (expr.how_) { // Postfix expression. Give to the evaluator and return the // one-and-only stack element that should be left over. case Module::kExprPostfix: { // Ensure that the stack is cleared before returning. - AutoStackClearer clearer(&stack_); + AutoStackClearer clearer(&stack_); if (!EvaluateInternal(expr.postfix_, NULL)) return false; // A successful execution should leave exactly one value on the stack. if (stack_.size() != 1) { BPLOG(ERROR) << "Expression yielded bad number of results: " << "'" << expr << "'"; @@ -314,77 +335,56 @@ return false; } } template typename PostfixEvaluator::PopResult PostfixEvaluator::PopValueOrIdentifier( - ValueType *value, string *identifier) { + ValueType *value, const UniqueString** identifier) { // There needs to be at least one element on the stack to pop. if (!stack_.size()) return POP_RESULT_FAIL; - string token = stack_.back(); + StackElem el = stack_.back(); stack_.pop_back(); - // First, try to treat the value as a literal. Literals may have leading - // '-' sign, and the entire remaining string must be parseable as - // ValueType. If this isn't possible, it can't be a literal, so treat it - // as an identifier instead. - // - // Some versions of the libstdc++, the GNU standard C++ library, have - // stream extractors for unsigned integer values that permit a leading - // '-' sign (6.0.13); others do not (6.0.9). Since we require it, we - // handle it explicitly here. - istringstream token_stream(token); - ValueType literal = ValueType(); - bool negative; - if (token_stream.peek() == '-') { - negative = true; - token_stream.get(); - } else { - negative = false; - } - if (token_stream >> literal && token_stream.peek() == EOF) { - if (value) { - *value = literal; - } - if (negative) - *value = -*value; + if (el.isValue) { + if (value) + *value = el.u.val; return POP_RESULT_VALUE; } else { - if (identifier) { - *identifier = token; - } + if (identifier) + *identifier = el.u.ustr; return POP_RESULT_IDENTIFIER; } } template bool PostfixEvaluator::PopValue(ValueType *value) { ValueType literal = ValueType(); - string token; + const UniqueString* token; PopResult result; if ((result = PopValueOrIdentifier(&literal, &token)) == POP_RESULT_FAIL) { return false; } else if (result == POP_RESULT_VALUE) { // This is the easy case. *value = literal; } else { // result == POP_RESULT_IDENTIFIER // There was an identifier at the top of the stack. Resolve it to a // value by looking it up in the dictionary. typename DictionaryType::const_iterator iterator = dictionary_->find(token); if (iterator == dictionary_->end()) { // The identifier wasn't found in the dictionary. Don't imply any // default value, just fail. - BPLOG(INFO) << "Identifier " << token << " not in dictionary"; + BPLOG(INFO) << "Identifier " << FromUniqueString(token) + << " not in dictionary"; return false; } *value = iterator->second; } return true; } @@ -394,18 +394,23 @@ bool PostfixEvaluator::PopValues(ValueType *value1, ValueType *value2) { return PopValue(value2) && PopValue(value1); } template void PostfixEvaluator::PushValue(const ValueType &value) { - ostringstream token_stream; - token_stream << value; - stack_.push_back(token_stream.str()); + StackElem el(value); + stack_.push_back(el); +} + +template +void PostfixEvaluator::PushIdentifier(const UniqueString* str) { + StackElem el(str); + stack_.push_back(el); } } // namespace google_breakpad #endif // PROCESSOR_POSTFIX_EVALUATOR_INL_H__ diff --git a/src/processor/postfix_evaluator.h b/src/processor/postfix_evaluator.h --- a/src/processor/postfix_evaluator.h +++ b/src/processor/postfix_evaluator.h @@ -70,30 +70,41 @@ #define PROCESSOR_POSTFIX_EVALUATOR_H__ #include #include #include #include "common/using_std_string.h" +#include "common/unique_string.h" #include "common/module.h" namespace google_breakpad { using std::map; using std::vector; class MemoryRegion; +// A union type for elements in the postfix evaluator's stack. +template +class StackElem { + public: + StackElem(ValueType val) { isValue = true; u.val = val; } + StackElem(const UniqueString* ustr) { isValue = false; u.ustr = ustr; } + bool isValue; + union { ValueType val; const UniqueString* ustr; } u; +}; + template class PostfixEvaluator { public: - typedef map DictionaryType; - typedef map DictionaryValidityType; + typedef map DictionaryType; + typedef map DictionaryValidityType; // Create a PostfixEvaluator object that may be used (with Evaluate) on // one or more expressions. PostfixEvaluator does not take ownership of // either argument. |memory| may be NULL, in which case dereferencing // (^) will not be supported. |dictionary| may be NULL, but evaluation // will fail in that case unless set_dictionary is used before calling // Evaluate. PostfixEvaluator(DictionaryType *dictionary, const MemoryRegion *memory) @@ -128,24 +139,28 @@ }; // Retrieves the topmost literal value, constant, or variable from the // stack. Returns POP_RESULT_VALUE if the topmost entry is a literal // value, and sets |value| accordingly. Returns POP_RESULT_IDENTIFIER // if the topmost entry is a constant or variable identifier, and sets // |identifier| accordingly. Returns POP_RESULT_FAIL on failure, such // as when the stack is empty. - PopResult PopValueOrIdentifier(ValueType *value, string *identifier); + PopResult PopValueOrIdentifier(ValueType *value, + const UniqueString** 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); + // Pushes a UniqueString* on the stack. + void PushIdentifier(const UniqueString* ustr); + // Retrieves the top two values on the stack, in the style of PopValue. // value2 is popped before value1, so that value1 corresponds to the // entry that was pushed prior to value2. Returns false on failure. bool PopValues(ValueType *value1, ValueType *value2); // Pushes a new value onto the stack. void PushValue(const ValueType &value); @@ -166,15 +181,15 @@ // If non-NULL, the MemoryRegion used for dereference (^) operations. // If NULL, dereferencing is unsupported and will fail. Weak pointer. const MemoryRegion *memory_; // The stack contains state information as execution progresses. Values // are pushed on to it as the expression string is read and as operations // yield values; values are popped when used as operands to operators. - vector stack_; + vector > stack_; }; } // namespace google_breakpad #endif // PROCESSOR_POSTFIX_EVALUATOR_H__ diff --git a/src/processor/postfix_evaluator_unittest.cc b/src/processor/postfix_evaluator_unittest.cc --- a/src/processor/postfix_evaluator_unittest.cc +++ b/src/processor/postfix_evaluator_unittest.cc @@ -43,18 +43,32 @@ #include "google_breakpad/processor/memory_region.h" #include "processor/logging.h" namespace { using std::map; +using google_breakpad::FromUniqueString; using google_breakpad::MemoryRegion; using google_breakpad::PostfixEvaluator; +using google_breakpad::ToUniqueString; +using google_breakpad::UniqueString; +using google_breakpad::ustr__ZDcbParams; +using google_breakpad::ustr__ZDcbSavedRegs; +using google_breakpad::ustr__ZDcfa; +using google_breakpad::ustr__ZDra; +using google_breakpad::ustr__ZDraSearchStart; +using google_breakpad::ustr__ZSebx; +using google_breakpad::ustr__ZSebp; +using google_breakpad::ustr__ZSedi; +using google_breakpad::ustr__ZSeip; +using google_breakpad::ustr__ZSesi; +using google_breakpad::ustr__ZSesp; // FakeMemoryRegion is used to test PostfixEvaluator's dereference (^) // operator. The result of dereferencing a value is one greater than // the value. class FakeMemoryRegion : public MemoryRegion { public: virtual uint64_t GetBase() const { return 0; } @@ -95,17 +109,17 @@ // The list of tests. const EvaluateTest *evaluate_tests; // The number of tests. unsigned int evaluate_test_count; // Identifiers and their expected values upon completion of the Evaluate // tests in the set. - map *validate_data; + map *validate_data; }; struct EvaluateForValueTest { // Expression passed to PostfixEvaluator::Evaluate. const string expression; // True if the expression is expected to be evaluable, false if evaluation @@ -147,39 +161,39 @@ { "$rMul 9 6 * =", true }, // $rMul = 9 * 6 = 54 { "$rSub 9 6 - =", true }, // $rSub = 9 - 6 = 3 { "$rDivQ 9 6 / =", true }, // $rDivQ = 9 / 6 = 1 { "$rDivM 9 6 % =", true }, // $rDivM = 9 % 6 = 3 { "$rDeref 9 ^ =", true }, // $rDeref = ^9 = 10 (FakeMemoryRegion) { "$rAlign 36 8 @ =", true }, // $rAlign = 36 @ 8 { "$rAdd3 2 2 + =$rMul2 9 6 * =", true } // smashed-equals tokenization }; - map validate_data_0; - validate_data_0["$rAdd"] = 8; - validate_data_0["$rAdd2"] = 4; - validate_data_0["$rSub"] = 3; - validate_data_0["$rMul"] = 54; - validate_data_0["$rDivQ"] = 1; - validate_data_0["$rDivM"] = 3; - validate_data_0["$rDeref"] = 10; - validate_data_0["$rAlign"] = 32; - validate_data_0["$rAdd3"] = 4; - validate_data_0["$rMul2"] = 54; + map validate_data_0; + validate_data_0[ToUniqueString("$rAdd")] = 8; + validate_data_0[ToUniqueString("$rAdd2")] = 4; + validate_data_0[ToUniqueString("$rSub")] = 3; + validate_data_0[ToUniqueString("$rMul")] = 54; + validate_data_0[ToUniqueString("$rDivQ")] = 1; + validate_data_0[ToUniqueString("$rDivM")] = 3; + validate_data_0[ToUniqueString("$rDeref")] = 10; + validate_data_0[ToUniqueString("$rAlign")] = 32; + validate_data_0[ToUniqueString("$rAdd3")] = 4; + validate_data_0[ToUniqueString("$rMul2")] = 54; // The second test set simulates a couple of MSVC program strings. // The data is fudged a little bit because the tests use FakeMemoryRegion // instead of a real stack snapshot, but the program strings are real and // the implementation doesn't know or care that the data is not real. PostfixEvaluator::DictionaryType dictionary_1; - dictionary_1["$ebp"] = 0xbfff0010; - dictionary_1["$eip"] = 0x10000000; - dictionary_1["$esp"] = 0xbfff0000; - dictionary_1[".cbSavedRegs"] = 4; - dictionary_1[".cbParams"] = 4; - dictionary_1[".raSearchStart"] = 0xbfff0020; + dictionary_1[ustr__ZSebp()] = 0xbfff0010; + dictionary_1[ustr__ZSeip()] = 0x10000000; + dictionary_1[ustr__ZSesp()] = 0xbfff0000; + dictionary_1[ustr__ZDcbSavedRegs()] = 4; + dictionary_1[ustr__ZDcbParams()] = 4; + dictionary_1[ustr__ZDraSearchStart()] = 0xbfff0020; const EvaluateTest evaluate_tests_1[] = { { "$T0 $ebp = $eip $T0 4 + ^ = $ebp $T0 ^ = $esp $T0 8 + = " "$L $T0 .cbSavedRegs - = $P $T0 8 + .cbParams + =", true }, // Intermediate state: $T0 = 0xbfff0010, $eip = 0xbfff0015, // $ebp = 0xbfff0011, $esp = 0xbfff0018, // $L = 0xbfff000c, $P = 0xbfff001c { "$T0 $ebp = $eip $T0 4 + ^ = $ebp $T0 ^ = $esp $T0 8 + = " "$L $T0 .cbSavedRegs - = $P $T0 8 + .cbParams + = $ebx $T0 28 - ^ =", @@ -188,28 +202,28 @@ // $ebp = 0xbfff0012, $esp = 0xbfff0019, // $L = 0xbfff000d, $P = 0xbfff001d, // $ebx = 0xbffefff6 { "$T0 $ebp = $T2 $esp = $T1 .raSearchStart = $eip $T1 ^ = $ebp $T0 = " "$esp $T1 4 + = $L $T0 .cbSavedRegs - = $P $T1 4 + .cbParams + = " "$ebx $T0 28 - ^ =", true } }; - map validate_data_1; - validate_data_1["$T0"] = 0xbfff0012; - validate_data_1["$T1"] = 0xbfff0020; - validate_data_1["$T2"] = 0xbfff0019; - validate_data_1["$eip"] = 0xbfff0021; - validate_data_1["$ebp"] = 0xbfff0012; - validate_data_1["$esp"] = 0xbfff0024; - validate_data_1["$L"] = 0xbfff000e; - validate_data_1["$P"] = 0xbfff0028; - validate_data_1["$ebx"] = 0xbffefff7; - validate_data_1[".cbSavedRegs"] = 4; - validate_data_1[".cbParams"] = 4; + map validate_data_1; + validate_data_1[ToUniqueString("$T0")] = 0xbfff0012; + validate_data_1[ToUniqueString("$T1")] = 0xbfff0020; + validate_data_1[ToUniqueString("$T2")] = 0xbfff0019; + validate_data_1[ustr__ZSeip()] = 0xbfff0021; + validate_data_1[ustr__ZSebp()] = 0xbfff0012; + validate_data_1[ustr__ZSesp()] = 0xbfff0024; + validate_data_1[ToUniqueString("$L")] = 0xbfff000e; + validate_data_1[ToUniqueString("$P")] = 0xbfff0028; + validate_data_1[ustr__ZSebx()] = 0xbffefff7; + validate_data_1[ustr__ZDcbSavedRegs()] = 4; + validate_data_1[ustr__ZDcbParams()] = 4; EvaluateTestSet evaluate_test_sets[] = { { &dictionary_0, evaluate_tests_0, sizeof(evaluate_tests_0) / sizeof(EvaluateTest), &validate_data_0 }, { &dictionary_1, evaluate_tests_1, sizeof(evaluate_tests_1) / sizeof(EvaluateTest), &validate_data_1 }, }; @@ -251,97 +265,100 @@ evaluate_test->expression.c_str(), evaluate_test->evaluable ? "evaluable" : "not evaluable", result ? "evaluted" : "not evaluated"); return false; } } // Validate the results. - for (map::const_iterator validate_iterator = + for (map::const_iterator + validate_iterator = evaluate_test_set->validate_data->begin(); validate_iterator != evaluate_test_set->validate_data->end(); ++validate_iterator) { - const string identifier = validate_iterator->first; + const UniqueString* identifier = validate_iterator->first; unsigned int expected_value = validate_iterator->second; - map::const_iterator dictionary_iterator = + map::const_iterator + dictionary_iterator = evaluate_test_set->dictionary->find(identifier); // The identifier must exist in the dictionary. if (dictionary_iterator == evaluate_test_set->dictionary->end()) { fprintf(stderr, "FAIL: evaluate test set %d/%d, " "validate identifier \"%s\", " "expected %d, observed not found\n", evaluate_test_set_index, evaluate_test_set_count, - identifier.c_str(), expected_value); + FromUniqueString(identifier), expected_value); return false; } // The value in the dictionary must be the same as the expected value. unsigned int observed_value = dictionary_iterator->second; if (expected_value != observed_value) { fprintf(stderr, "FAIL: evaluate test set %d/%d, " "validate identifier \"%s\", " "expected %d, observed %d\n", evaluate_test_set_index, evaluate_test_set_count, - identifier.c_str(), expected_value, observed_value); + FromUniqueString(identifier), expected_value, observed_value); return false; } // The value must be set in the "assigned" dictionary if it was a // variable. It must not have been assigned if it was a constant. - bool expected_assigned = identifier[0] == '$'; + bool expected_assigned = FromUniqueString(identifier)[0] == '$'; bool observed_assigned = false; PostfixEvaluator::DictionaryValidityType::const_iterator iterator_assigned = assigned.find(identifier); if (iterator_assigned != assigned.end()) { observed_assigned = iterator_assigned->second; } if (expected_assigned != observed_assigned) { fprintf(stderr, "FAIL: evaluate test set %d/%d, " "validate assignment of \"%s\", " "expected %d, observed %d\n", evaluate_test_set_index, evaluate_test_set_count, - identifier.c_str(), expected_assigned, observed_assigned); + FromUniqueString(identifier), expected_assigned, + observed_assigned); return false; } } } // EvaluateForValue tests. PostfixEvaluator::DictionaryType dictionary_2; - dictionary_2["$ebp"] = 0xbfff0010; - dictionary_2["$eip"] = 0x10000000; - dictionary_2["$esp"] = 0xbfff0000; - dictionary_2[".cbSavedRegs"] = 4; - dictionary_2[".cbParams"] = 4; - dictionary_2[".raSearchStart"] = 0xbfff0020; + dictionary_2[ustr__ZSebp()] = 0xbfff0010; + dictionary_2[ustr__ZSeip()] = 0x10000000; + dictionary_2[ustr__ZSesp()] = 0xbfff0000; + dictionary_2[ustr__ZDcbSavedRegs()] = 4; + dictionary_2[ustr__ZDcbParams()] = 4; + dictionary_2[ustr__ZDraSearchStart()] = 0xbfff0020; const EvaluateForValueTest evaluate_for_value_tests_2[] = { { "28907223", true, 28907223 }, // simple constant { "89854293 40010015 +", true, 89854293 + 40010015 }, // arithmetic { "-870245 8769343 +", true, 7899098 }, // negative constants { "$ebp $esp - $eip +", true, 0x10000010 }, // variable references { "18929794 34015074", false, 0 }, // too many values { "$ebp $ebp 4 - =", false, 0 }, // too few values { "$new $eip = $new", true, 0x10000000 }, // make new variable { "$new 4 +", true, 0x10000004 }, // see prior assignments { ".cfa 42 = 10", false, 0 } // can't set constants }; const int evaluate_for_value_tests_2_size = (sizeof (evaluate_for_value_tests_2) / sizeof (evaluate_for_value_tests_2[0])); - map validate_data_2; - validate_data_2["$eip"] = 0x10000000; - validate_data_2["$ebp"] = 0xbfff000c; - validate_data_2["$esp"] = 0xbfff0000; - validate_data_2["$new"] = 0x10000000; - validate_data_2[".cbSavedRegs"] = 4; - validate_data_2[".cbParams"] = 4; - validate_data_2[".raSearchStart"] = 0xbfff0020; + map validate_data_2; + validate_data_2[ustr__ZSeip()] = 0x10000000; + validate_data_2[ustr__ZSebp()] = 0xbfff000c; + validate_data_2[ustr__ZSesp()] = 0xbfff0000; + validate_data_2[ToUniqueString("$new")] = 0x10000000; + validate_data_2[ustr__ZDcbSavedRegs()] = 4; + validate_data_2[ustr__ZDcbParams()] = 4; + validate_data_2[ustr__ZDraSearchStart()] = 0xbfff0020; postfix_evaluator.set_dictionary(&dictionary_2); for (int i = 0; i < evaluate_for_value_tests_2_size; i++) { const EvaluateForValueTest *test = &evaluate_for_value_tests_2[i]; unsigned int result; if (postfix_evaluator.EvaluateForValue(test->expression, &result) != test->evaluable) { fprintf(stderr, "FAIL: evaluate for value test %d, " @@ -353,40 +370,43 @@ if (test->evaluable && result != test->value) { fprintf(stderr, "FAIL: evaluate for value test %d, " "expected value to be 0x%x, but it was 0x%x\n", i, test->value, result); return false; } } - for (map::iterator v = validate_data_2.begin(); + for (map::iterator v = + validate_data_2.begin(); v != validate_data_2.end(); v++) { - map::iterator a = dictionary_2.find(v->first); + map::iterator a = + dictionary_2.find(v->first); if (a == dictionary_2.end()) { fprintf(stderr, "FAIL: evaluate for value dictionary check: " "expected dict[\"%s\"] to be 0x%x, but it was unset\n", - v->first.c_str(), v->second); + FromUniqueString(v->first), v->second); return false; } else if (a->second != v->second) { fprintf(stderr, "FAIL: evaluate for value dictionary check: " "expected dict[\"%s\"] to be 0x%x, but it was 0x%x\n", - v->first.c_str(), v->second, a->second); + FromUniqueString(v->first), v->second, a->second); return false; } dictionary_2.erase(a); } - map::iterator remaining = dictionary_2.begin(); + map::iterator remaining = + dictionary_2.begin(); if (remaining != dictionary_2.end()) { fprintf(stderr, "FAIL: evaluation of test expressions put unexpected " "values in dictionary:\n"); for (; remaining != dictionary_2.end(); remaining++) fprintf(stderr, " dict[\"%s\"] == 0x%x\n", - remaining->first.c_str(), remaining->second); + FromUniqueString(remaining->first), remaining->second); return false; } return true; } } // namespace diff --git a/src/processor/stackwalker_amd64.cc b/src/processor/stackwalker_amd64.cc --- a/src/processor/stackwalker_amd64.cc +++ b/src/processor/stackwalker_amd64.cc @@ -49,49 +49,49 @@ const StackwalkerAMD64::CFIWalker::RegisterSet StackwalkerAMD64::cfi_register_map_[] = { // It may seem like $rip and $rsp are callee-saves, because the callee is // responsible for having them restored upon return. But the callee_saves // flags here really means that the walker should assume they're // unchanged if the CFI doesn't mention them --- clearly wrong for $rip // and $rsp. - { "$rax", NULL, false, + { ToUniqueString("$rax"), NULL, false, StackFrameAMD64::CONTEXT_VALID_RAX, &MDRawContextAMD64::rax }, - { "$rdx", NULL, false, + { ToUniqueString("$rdx"), NULL, false, StackFrameAMD64::CONTEXT_VALID_RDX, &MDRawContextAMD64::rdx }, - { "$rcx", NULL, false, + { ToUniqueString("$rcx"), NULL, false, StackFrameAMD64::CONTEXT_VALID_RCX, &MDRawContextAMD64::rcx }, - { "$rbx", NULL, true, + { ToUniqueString("$rbx"), NULL, true, StackFrameAMD64::CONTEXT_VALID_RBX, &MDRawContextAMD64::rbx }, - { "$rsi", NULL, false, + { ToUniqueString("$rsi"), NULL, false, StackFrameAMD64::CONTEXT_VALID_RSI, &MDRawContextAMD64::rsi }, - { "$rdi", NULL, false, + { ToUniqueString("$rdi"), NULL, false, StackFrameAMD64::CONTEXT_VALID_RDI, &MDRawContextAMD64::rdi }, - { "$rbp", NULL, true, + { ToUniqueString("$rbp"), NULL, true, StackFrameAMD64::CONTEXT_VALID_RBP, &MDRawContextAMD64::rbp }, - { "$rsp", ".cfa", false, + { ToUniqueString("$rsp"), ToUniqueString(".cfa"), false, StackFrameAMD64::CONTEXT_VALID_RSP, &MDRawContextAMD64::rsp }, - { "$r8", NULL, false, + { ToUniqueString("$r8"), NULL, false, StackFrameAMD64::CONTEXT_VALID_R8, &MDRawContextAMD64::r8 }, - { "$r9", NULL, false, + { ToUniqueString("$r9"), NULL, false, StackFrameAMD64::CONTEXT_VALID_R9, &MDRawContextAMD64::r9 }, - { "$r10", NULL, false, + { ToUniqueString("$r10"), NULL, false, StackFrameAMD64::CONTEXT_VALID_R10, &MDRawContextAMD64::r10 }, - { "$r11", NULL, false, + { ToUniqueString("$r11"), NULL, false, StackFrameAMD64::CONTEXT_VALID_R11, &MDRawContextAMD64::r11 }, - { "$r12", NULL, true, + { ToUniqueString("$r12"), NULL, true, StackFrameAMD64::CONTEXT_VALID_R12, &MDRawContextAMD64::r12 }, - { "$r13", NULL, true, + { ToUniqueString("$r13"), NULL, true, StackFrameAMD64::CONTEXT_VALID_R13, &MDRawContextAMD64::r13 }, - { "$r14", NULL, true, + { ToUniqueString("$r14"), NULL, true, StackFrameAMD64::CONTEXT_VALID_R14, &MDRawContextAMD64::r14 }, - { "$r15", NULL, true, + { ToUniqueString("$r15"), NULL, true, StackFrameAMD64::CONTEXT_VALID_R15, &MDRawContextAMD64::r15 }, - { "$rip", ".ra", false, + { ToUniqueString("$rip"), ToUniqueString(".ra"), false, StackFrameAMD64::CONTEXT_VALID_RIP, &MDRawContextAMD64::rip }, }; StackwalkerAMD64::StackwalkerAMD64(const SystemInfo* system_info, const MDRawContextAMD64* context, MemoryRegion* memory, const CodeModules* modules, StackFrameSymbolizer* resolver_helper) diff --git a/src/processor/stackwalker_arm.cc b/src/processor/stackwalker_arm.cc --- a/src/processor/stackwalker_arm.cc +++ b/src/processor/stackwalker_arm.cc @@ -76,21 +76,30 @@ return frame; } StackFrameARM* StackwalkerARM::GetCallerByCFIFrameInfo( const vector &frames, CFIFrameInfo* cfi_frame_info) { StackFrameARM* last_frame = static_cast(frames.back()); - static const char* register_names[] = { - "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", - "r8", "r9", "r10", "r11", "r12", "sp", "lr", "pc", - "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", - "fps", "cpsr", + static const UniqueString *register_names[] = { + ToUniqueString("r0"), ToUniqueString("r1"), + ToUniqueString("r2"), ToUniqueString("r3"), + ToUniqueString("r4"), ToUniqueString("r5"), + ToUniqueString("r6"), ToUniqueString("r7"), + ToUniqueString("r8"), ToUniqueString("r9"), + ToUniqueString("r10"), ToUniqueString("r11"), + ToUniqueString("r12"), ToUniqueString("sp"), + ToUniqueString("lr"), ToUniqueString("pc"), + ToUniqueString("f0"), ToUniqueString("f1"), + ToUniqueString("f2"), ToUniqueString("f3"), + ToUniqueString("f4"), ToUniqueString("f5"), + ToUniqueString("f6"), ToUniqueString("f7"), + ToUniqueString("fps"), ToUniqueString("cpsr"), NULL }; // Populate a dictionary with the valid register values in last_frame. CFIFrameInfo::RegisterValueMap callee_registers; for (int i = 0; register_names[i]; i++) if (last_frame->context_validity & StackFrameARM::RegisterValidFlag(i)) callee_registers[register_names[i]] = last_frame->context.iregs[i]; @@ -119,17 +128,17 @@ // Call Standard for the ARM Architecture, which the Linux ABI follows. frame->context_validity |= StackFrameARM::RegisterValidFlag(i); frame->context.iregs[i] = last_frame->context.iregs[i]; } } // If the CFI doesn't recover the PC explicitly, then use .ra. if (!(frame->context_validity & StackFrameARM::CONTEXT_VALID_PC)) { CFIFrameInfo::RegisterValueMap::iterator entry = - caller_registers.find(".ra"); + caller_registers.find(ustr__ZDra()); if (entry != caller_registers.end()) { if (fp_register_ == -1) { frame->context_validity |= StackFrameARM::CONTEXT_VALID_PC; frame->context.iregs[MD_CONTEXT_ARM_REG_PC] = entry->second; } else { // The CFI updated the link register and not the program counter. // Handle getting the program counter from the link register. frame->context_validity |= StackFrameARM::CONTEXT_VALID_PC; @@ -138,17 +147,17 @@ frame->context.iregs[MD_CONTEXT_ARM_REG_PC] = last_frame->context.iregs[MD_CONTEXT_ARM_REG_LR]; } } } // If the CFI doesn't recover the SP explicitly, then use .cfa. if (!(frame->context_validity & StackFrameARM::CONTEXT_VALID_SP)) { CFIFrameInfo::RegisterValueMap::iterator entry = - caller_registers.find(".cfa"); + caller_registers.find(ustr__ZDcfa()); if (entry != caller_registers.end()) { frame->context_validity |= StackFrameARM::CONTEXT_VALID_SP; frame->context.iregs[MD_CONTEXT_ARM_REG_SP] = entry->second; } } // If we didn't recover the PC and the SP, then the frame isn't very useful. static const int essentials = (StackFrameARM::CONTEXT_VALID_SP diff --git a/src/processor/stackwalker_x86.cc b/src/processor/stackwalker_x86.cc --- a/src/processor/stackwalker_x86.cc +++ b/src/processor/stackwalker_x86.cc @@ -53,33 +53,33 @@ const StackwalkerX86::CFIWalker::RegisterSet StackwalkerX86::cfi_register_map_[] = { // It may seem like $eip and $esp are callee-saves, because (with Unix or // cdecl calling conventions) the callee is responsible for having them // restored upon return. But the callee_saves flags here really means // that the walker should assume they're unchanged if the CFI doesn't // mention them, which is clearly wrong for $eip and $esp. - { "$eip", ".ra", false, + { ToUniqueString("$eip"), ToUniqueString(".ra"), false, StackFrameX86::CONTEXT_VALID_EIP, &MDRawContextX86::eip }, - { "$esp", ".cfa", false, + { ToUniqueString("$esp"), ToUniqueString(".cfa"), false, StackFrameX86::CONTEXT_VALID_ESP, &MDRawContextX86::esp }, - { "$ebp", NULL, true, + { ToUniqueString("$ebp"), NULL, true, StackFrameX86::CONTEXT_VALID_EBP, &MDRawContextX86::ebp }, - { "$eax", NULL, false, + { ToUniqueString("$eax"), NULL, false, StackFrameX86::CONTEXT_VALID_EAX, &MDRawContextX86::eax }, - { "$ebx", NULL, true, + { ToUniqueString("$ebx"), NULL, true, StackFrameX86::CONTEXT_VALID_EBX, &MDRawContextX86::ebx }, - { "$ecx", NULL, false, + { ToUniqueString("$ecx"), NULL, false, StackFrameX86::CONTEXT_VALID_ECX, &MDRawContextX86::ecx }, - { "$edx", NULL, false, + { ToUniqueString("$edx"), NULL, false, StackFrameX86::CONTEXT_VALID_EDX, &MDRawContextX86::edx }, - { "$esi", NULL, true, + { ToUniqueString("$esi"), NULL, true, StackFrameX86::CONTEXT_VALID_ESI, &MDRawContextX86::esi }, - { "$edi", NULL, true, + { ToUniqueString("$edi"), NULL, true, StackFrameX86::CONTEXT_VALID_EDI, &MDRawContextX86::edi }, }; StackwalkerX86::StackwalkerX86(const SystemInfo* system_info, const MDRawContextX86* context, MemoryRegion* memory, const CodeModules* modules, StackFrameSymbolizer* resolver_helper) @@ -194,26 +194,26 @@ } } // Set up the dictionary for the PostfixEvaluator. %ebp and %esp are used // in each program string, and their previous values are known, so set them // here. PostfixEvaluator::DictionaryType dictionary; // Provide the current register values. - dictionary["$ebp"] = last_frame->context.ebp; - dictionary["$esp"] = last_frame->context.esp; + dictionary[ustr__ZSebp()] = last_frame->context.ebp; + dictionary[ustr__ZSesp()] = last_frame->context.esp; // Provide constants from the debug info for last_frame and its callee. // .cbCalleeParams is a Breakpad extension that allows us to use the // PostfixEvaluator engine when certain types of debugging information // are present without having to write the constants into the program // string as literals. - dictionary[".cbCalleeParams"] = last_frame_callee_parameter_size; - dictionary[".cbSavedRegs"] = last_frame_info->saved_register_size; - dictionary[".cbLocals"] = last_frame_info->local_size; + dictionary[ustr__ZDcbCalleeParams()] = last_frame_callee_parameter_size; + dictionary[ustr__ZDcbSavedRegs()] = last_frame_info->saved_register_size; + dictionary[ustr__ZDcbLocals()] = last_frame_info->local_size; uint32_t raSearchStart = last_frame->context.esp + last_frame_callee_parameter_size + last_frame_info->local_size + last_frame_info->saved_register_size; uint32_t raSearchStartOld = raSearchStart; uint32_t found = 0; // dummy value @@ -232,20 +232,20 @@ // Skip one slot from the stack and do another scan in order to get the // actual return address. raSearchStart += 4; ScanForReturnAddress(raSearchStart, &raSearchStart, &found, 3); } // The difference between raSearch and raSearchStart is unknown, // but making them the same seems to work well in practice. - dictionary[".raSearchStart"] = raSearchStart; - dictionary[".raSearch"] = raSearchStart; + dictionary[ustr__ZDraSearchStart()] = raSearchStart; + dictionary[ustr__ZDraSearch()] = raSearchStart; - dictionary[".cbParams"] = last_frame_info->parameter_size; + dictionary[ustr__ZDcbParams()] = last_frame_info->parameter_size; // Decide what type of program string to use. The program string is in // postfix notation and will be passed to PostfixEvaluator::Evaluate. // Given the dictionary and the program string, it is possible to compute // the return address and the values of other registers in the calling // function. Because of bugs described below, the stack may need to be // scanned for these values. The results of program string evaluation // will be used to determine whether to scan for better values. @@ -325,18 +325,18 @@ } // Now crank it out, making sure that the program string set at least the // two required variables. PostfixEvaluator evaluator = PostfixEvaluator(&dictionary, memory_); PostfixEvaluator::DictionaryValidityType dictionary_validity; if (!evaluator.Evaluate(program_string, &dictionary_validity) || - dictionary_validity.find("$eip") == dictionary_validity.end() || - dictionary_validity.find("$esp") == dictionary_validity.end()) { + dictionary_validity.find(ustr__ZSeip()) == dictionary_validity.end() || + dictionary_validity.find(ustr__ZSesp()) == dictionary_validity.end()) { // Program string evaluation failed. It may be that %eip is not somewhere // with stack frame info, and %ebp is pointing to non-stack memory, so // our evaluation couldn't succeed. We'll scan the stack for a return // address. This can happen if the stack is in a module for which // we don't have symbols, and that module is compiled without a // frame pointer. uint32_t location_start = last_frame->context.esp; uint32_t location, eip; @@ -344,69 +344,69 @@ // if we can't find an instruction pointer even with stack scanning, // give up. return NULL; } // This seems like a reasonable return address. Since program string // evaluation failed, use it and set %esp to the location above the // one where the return address was found. - dictionary["$eip"] = eip; - dictionary["$esp"] = location + 4; + dictionary[ustr__ZSeip()] = eip; + dictionary[ustr__ZSesp()] = location + 4; trust = StackFrame::FRAME_TRUST_SCAN; } // Since this stack frame did not use %ebp in a traditional way, // locating the return address isn't entirely deterministic. In that // case, the stack can be scanned to locate the return address. // // However, if program string evaluation resulted in both %eip and // %ebp values of 0, trust that the end of the stack has been // reached and don't scan for anything else. - if (dictionary["$eip"] != 0 || dictionary["$ebp"] != 0) { + if (dictionary[ustr__ZSeip()] != 0 || dictionary[ustr__ZSebp()] != 0) { int offset = 0; // This scan can only be done if a CodeModules object is available, to // check that candidate return addresses are in fact inside a module. // // TODO(mmentovai): This ignores dynamically-generated code. One possible // solution is to check the minidump's memory map to see if the candidate // %eip value comes from a mapped executable page, although this would // require dumps that contain MINIDUMP_MEMORY_INFO, which the Breakpad // client doesn't currently write (it would need to call MiniDumpWriteDump // with the MiniDumpWithFullMemoryInfo type bit set). Even given this // ability, older OSes (pre-XP SP2) and CPUs (pre-P4) don't enforce // an independent execute privilege on memory pages. - uint32_t eip = dictionary["$eip"]; + uint32_t eip = dictionary[ustr__ZSeip()]; if (modules_ && !modules_->GetModuleForAddress(eip)) { // The instruction pointer at .raSearchStart was invalid, so start // looking one 32-bit word above that location. - uint32_t location_start = dictionary[".raSearchStart"] + 4; + uint32_t location_start = dictionary[ustr__ZDraSearchStart()] + 4; uint32_t location; if (ScanForReturnAddress(location_start, &location, &eip)) { // This is a better return address that what program string // evaluation found. Use it, and set %esp to the location above the // one where the return address was found. - dictionary["$eip"] = eip; - dictionary["$esp"] = location + 4; + dictionary[ustr__ZSeip()] = eip; + dictionary[ustr__ZSesp()] = location + 4; offset = location - location_start; trust = StackFrame::FRAME_TRUST_CFI_SCAN; } } if (recover_ebp) { // When trying to recover the previous value of the frame pointer (%ebp), // start looking at the lowest possible address in the saved-register // area, and look at the entire saved register area, increased by the // size of |offset| to account for additional data that may be on the // stack. The scan is performed from the highest possible address to // the lowest, because the expectation is that the function's prolog // would have saved %ebp early. - uint32_t ebp = dictionary["$ebp"]; + uint32_t ebp = dictionary[ustr__ZSebp()]; // When a scan for return address is used, it is possible to skip one or // more frames (when return address is not in a known module). One // indication for skipped frames is when the value of %ebp is lower than // the location of the return address on the stack bool has_skipped_frames = (trust != StackFrame::FRAME_TRUST_CFI && ebp <= raSearchStart + offset); @@ -420,49 +420,49 @@ location >= location_end; location -= 4) { if (!memory_->GetMemoryAtAddress(location, &ebp)) break; if (memory_->GetMemoryAtAddress(ebp, &value)) { // The candidate value is a pointer to the same memory region // (the stack). Prefer it as a recovered %ebp result. - dictionary["$ebp"] = ebp; + dictionary[ustr__ZSebp()] = ebp; break; } } } } } // Create a new stack frame (ownership will be transferred to the caller) // and fill it in. StackFrameX86* frame = new StackFrameX86(); frame->trust = trust; frame->context = last_frame->context; - frame->context.eip = dictionary["$eip"]; - frame->context.esp = dictionary["$esp"]; - frame->context.ebp = dictionary["$ebp"]; + frame->context.eip = dictionary[ustr__ZSeip()]; + frame->context.esp = dictionary[ustr__ZSesp()]; + frame->context.ebp = dictionary[ustr__ZSebp()]; frame->context_validity = StackFrameX86::CONTEXT_VALID_EIP | StackFrameX86::CONTEXT_VALID_ESP | StackFrameX86::CONTEXT_VALID_EBP; // These are nonvolatile (callee-save) registers, and the program string // may have filled them in. - if (dictionary_validity.find("$ebx") != dictionary_validity.end()) { - frame->context.ebx = dictionary["$ebx"]; + if (dictionary_validity.find(ustr__ZSebx()) != dictionary_validity.end()) { + frame->context.ebx = dictionary[ustr__ZSebx()]; frame->context_validity |= StackFrameX86::CONTEXT_VALID_EBX; } - if (dictionary_validity.find("$esi") != dictionary_validity.end()) { - frame->context.esi = dictionary["$esi"]; + if (dictionary_validity.find(ustr__ZSesi()) != dictionary_validity.end()) { + frame->context.esi = dictionary[ustr__ZSesi()]; frame->context_validity |= StackFrameX86::CONTEXT_VALID_ESI; } - if (dictionary_validity.find("$edi") != dictionary_validity.end()) { - frame->context.edi = dictionary["$edi"]; + if (dictionary_validity.find(ustr__ZSedi()) != dictionary_validity.end()) { + frame->context.edi = dictionary[ustr__ZSedi()]; frame->context_validity |= StackFrameX86::CONTEXT_VALID_EDI; } return frame; } StackFrameX86* StackwalkerX86::GetCallerByCFIFrameInfo( const vector &frames, diff --git a/src/tools/mac/dump_syms/dump_syms.xcodeproj/project.pbxproj b/src/tools/mac/dump_syms/dump_syms.xcodeproj/project.pbxproj --- a/src/tools/mac/dump_syms/dump_syms.xcodeproj/project.pbxproj +++ b/src/tools/mac/dump_syms/dump_syms.xcodeproj/project.pbxproj @@ -98,16 +98,22 @@ B8C5B51B1166534700D34F4E /* macho_id.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9BE650430B52F6D800611104 /* macho_id.cc */; }; B8C5B51C1166534700D34F4E /* macho_walker.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9BE650450B52F6D800611104 /* macho_walker.cc */; }; B8C5B51D1166534700D34F4E /* dump_syms.mm in Sources */ = {isa = PBXBuildFile; fileRef = 08FB7796FE84155DC02AAC07 /* dump_syms.mm */; }; B8C5B51E1166534700D34F4E /* dump_syms_tool.mm in Sources */ = {isa = PBXBuildFile; fileRef = 9BDF186E0B1BB43700F8391B /* dump_syms_tool.mm */; }; B8C5B523116653BA00D34F4E /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 08FB779EFE84155DC02AAC07 /* Foundation.framework */; }; D21F97D711CBA12300239E38 /* test_assembler_unittest.cc in Sources */ = {isa = PBXBuildFile; fileRef = B88FB0D9116CEC0600407530 /* test_assembler_unittest.cc */; }; D21F97D811CBA13D00239E38 /* libgtestmockall.a in Frameworks */ = {isa = PBXBuildFile; fileRef = B88FB024116BDFFF00407530 /* libgtestmockall.a */; }; D21F97E911CBA1FF00239E38 /* test_assembler.cc in Sources */ = {isa = PBXBuildFile; fileRef = B88FAE0911665B5700407530 /* test_assembler.cc */; }; + D24997CC16B6C16800E588C5 /* unique_string.cc in Sources */ = {isa = PBXBuildFile; fileRef = D24997CA16B6C16800E588C5 /* unique_string.cc */; }; + D24997CD16B6C16800E588C5 /* unique_string.cc in Sources */ = {isa = PBXBuildFile; fileRef = D24997CA16B6C16800E588C5 /* unique_string.cc */; }; + D24997CE16B6C16800E588C5 /* unique_string.cc in Sources */ = {isa = PBXBuildFile; fileRef = D24997CA16B6C16800E588C5 /* unique_string.cc */; }; + D2499A0016B9BA6A00E588C5 /* unique_string.cc in Sources */ = {isa = PBXBuildFile; fileRef = D24997CA16B6C16800E588C5 /* unique_string.cc */; }; + D2499A0216B9BA9600E588C5 /* unique_string.cc in Sources */ = {isa = PBXBuildFile; fileRef = D24997CA16B6C16800E588C5 /* unique_string.cc */; }; + D2499A0316B9BA9D00E588C5 /* unique_string.cc in Sources */ = {isa = PBXBuildFile; fileRef = D24997CA16B6C16800E588C5 /* unique_string.cc */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ 8B31051411F100CF00FCF3E4 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */; proxyType = 1; remoteGlobalIDString = D21F97D111CBA0F200239E38; @@ -338,16 +344,18 @@ B89E0E741166575200DD08C9 /* macho_dump */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = macho_dump; sourceTree = BUILT_PRODUCTS_DIR; }; B89E0E9511665A6400DD08C9 /* macho_reader_unittest */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = macho_reader_unittest; sourceTree = BUILT_PRODUCTS_DIR; }; B89E0E9F11665AC300DD08C9 /* gtest_main.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = gtest_main.cc; path = ../../../testing/gtest/src/gtest_main.cc; sourceTree = SOURCE_ROOT; }; B89E0EA011665AC300DD08C9 /* gtest-all.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = "gtest-all.cc"; path = "../../../testing/gtest/src/gtest-all.cc"; sourceTree = SOURCE_ROOT; }; B89E0EA311665AEA00DD08C9 /* gmock-all.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = "gmock-all.cc"; path = "../../../testing/src/gmock-all.cc"; sourceTree = SOURCE_ROOT; }; B8C5B5111166531A00D34F4E /* dump_syms */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = dump_syms; sourceTree = BUILT_PRODUCTS_DIR; }; B8E8CA0C1156C854009E61B2 /* byteswap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = byteswap.h; path = ../../../common/mac/byteswap.h; sourceTree = SOURCE_ROOT; }; D21F97D211CBA0F200239E38 /* test_assembler_unittest */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = test_assembler_unittest; sourceTree = BUILT_PRODUCTS_DIR; }; + D24997CA16B6C16800E588C5 /* unique_string.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = unique_string.cc; path = ../../../common/unique_string.cc; sourceTree = ""; }; + D24997CB16B6C16800E588C5 /* unique_string.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = unique_string.h; path = ../../../common/unique_string.h; sourceTree = ""; }; F95B422B0E0E22D100DBDE83 /* bytereader-inl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "bytereader-inl.h"; path = "../../../common/dwarf/bytereader-inl.h"; sourceTree = SOURCE_ROOT; }; F95B422C0E0E22D100DBDE83 /* bytereader.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = bytereader.cc; path = ../../../common/dwarf/bytereader.cc; sourceTree = SOURCE_ROOT; }; F95B422D0E0E22D100DBDE83 /* bytereader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = bytereader.h; path = ../../../common/dwarf/bytereader.h; sourceTree = SOURCE_ROOT; }; F95B422E0E0E22D100DBDE83 /* dwarf2enums.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dwarf2enums.h; path = ../../../common/dwarf/dwarf2enums.h; sourceTree = SOURCE_ROOT; }; F95B422F0E0E22D100DBDE83 /* dwarf2reader.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = dwarf2reader.cc; path = ../../../common/dwarf/dwarf2reader.cc; sourceTree = SOURCE_ROOT; }; F95B42300E0E22D100DBDE83 /* dwarf2reader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dwarf2reader.h; path = ../../../common/dwarf/dwarf2reader.h; sourceTree = SOURCE_ROOT; }; F95B42310E0E22D100DBDE83 /* line_state_machine.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = line_state_machine.h; path = ../../../common/dwarf/line_state_machine.h; sourceTree = SOURCE_ROOT; }; /* End PBXFileReference section */ @@ -531,16 +539,18 @@ D21F97D211CBA0F200239E38 /* test_assembler_unittest */, ); name = Products; sourceTree = ""; }; B88FAE1C11665FFD00407530 /* MODULE */ = { isa = PBXGroup; children = ( + D24997CA16B6C16800E588C5 /* unique_string.cc */, + D24997CB16B6C16800E588C5 /* unique_string.h */, B88FAE1E1166603300407530 /* dwarf_cu_to_module.cc */, B88FAE1F1166603300407530 /* dwarf_cu_to_module.h */, B88FB0D6116CEC0600407530 /* dwarf_cu_to_module_unittest.cc */, B88FAE201166603300407530 /* dwarf_line_to_module.cc */, B88FAE211166603300407530 /* dwarf_line_to_module.h */, B88FB0D7116CEC0600407530 /* dwarf_line_to_module_unittest.cc */, B88FAE221166603300407530 /* language.cc */, B88FAE231166603300407530 /* language.h */, @@ -940,16 +950,17 @@ }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ B84A91F1116CF784006C210E /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + D2499A0216B9BA9600E588C5 /* unique_string.cc in Sources */, B84A91FB116CF7AF006C210E /* module.cc in Sources */, B84A91FC116CF7AF006C210E /* stabs_to_module.cc in Sources */, B84A91FD116CF7AF006C210E /* stabs_to_module_unittest.cc in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; B88FAF2C116A591D00407530 /* Sources */ = { isa = PBXSourcesBuildPhase; @@ -983,56 +994,60 @@ runOnlyForDeploymentPostprocessing = 0; }; B88FB0B6116CEABF00407530 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( B88FB0BD116CEAE000407530 /* module_unittest.cc in Sources */, B88FB0C4116CEB4100407530 /* module.cc in Sources */, + D24997CE16B6C16800E588C5 /* unique_string.cc in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; B88FB0DC116CEEA800407530 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( B88FB0E5116CEED300407530 /* dwarf2diehandler.cc in Sources */, B88FB0E6116CEED300407530 /* dwarf2diehandler_unittest.cc in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; B88FB0EF116CEF1900407530 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + D2499A0316B9BA9D00E588C5 /* unique_string.cc in Sources */, B88FB0FA116CF00E00407530 /* dwarf_line_to_module.cc in Sources */, B88FB0FE116CF02400407530 /* module.cc in Sources */, B88FB0FB116CF00E00407530 /* dwarf_line_to_module_unittest.cc in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; B88FB107116CF07900407530 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + D2499A0016B9BA6A00E588C5 /* unique_string.cc in Sources */, B88FB112116CF1F000407530 /* dwarf_cu_to_module.cc in Sources */, B88FB113116CF1F000407530 /* dwarf_cu_to_module_unittest.cc in Sources */, B88FB114116CF1F000407530 /* language.cc in Sources */, B88FB115116CF1F000407530 /* module.cc in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; B88FB11C116CF27F00407530 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( B88FB129116CF2DD00407530 /* module.cc in Sources */, B88FB12A116CF2DD00407530 /* dwarf_cfi_to_module.cc in Sources */, B88FB12B116CF2DD00407530 /* dwarf_cfi_to_module_unittest.cc in Sources */, + D24997CD16B6C16800E588C5 /* unique_string.cc in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; B88FB132116CF30F00407530 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( B88FB13D116CF38300407530 /* cfi_assembler.cc in Sources */, @@ -1086,16 +1101,17 @@ B88FAE261166603300407530 /* dwarf_cu_to_module.cc in Sources */, B88FAE271166603300407530 /* dwarf_line_to_module.cc in Sources */, B88FAE281166603300407530 /* language.cc in Sources */, B88FAE291166603300407530 /* module.cc in Sources */, B88FAE351166673E00407530 /* dwarf_cfi_to_module.cc in Sources */, B88FAE3B11666C6F00407530 /* stabs_reader.cc in Sources */, B88FAE3E11666C8900407530 /* stabs_to_module.cc in Sources */, 4D72CAF513DFBAC2006CABE3 /* md5.cc in Sources */, + D24997CC16B6C16800E588C5 /* unique_string.cc in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; D21F97CF11CBA0F200239E38 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( D21F97E911CBA1FF00239E38 /* test_assembler.cc in Sources */,