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