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