toolkit/crashreporter/breakpad-patches/03-unique-string.patch

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/toolkit/crashreporter/breakpad-patches/03-unique-string.patch	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,4539 @@
     1.4 +# HG changeset patch
     1.5 +# User Ted Mielczarek <ted.mielczarek@gmail.com>
     1.6 +# Date 1360255134 18000
     1.7 +#      Thu Feb 07 11:38:54 2013 -0500
     1.8 +# Node ID 79cecfef3c2a10d719fe1af9fae2e5257109b028
     1.9 +# Parent 08f184a7e6d6d15ecc20abd56bc4e36669c0c68a
    1.10 +Rework PostfixEvaluator to use a UniqueString type
    1.11 +Patch by Julian Seward <jseward@acm.org>, R=ted
    1.12 +
    1.13 +diff --git a/Makefile.am b/Makefile.am
    1.14 +--- a/Makefile.am
    1.15 ++++ b/Makefile.am
    1.16 +@@ -134,16 +134,17 @@
    1.17 + 	src/google_breakpad/processor/source_line_resolver_interface.h \
    1.18 + 	src/google_breakpad/processor/stack_frame.h \
    1.19 + 	src/google_breakpad/processor/stack_frame_cpu.h \
    1.20 + 	src/google_breakpad/processor/stack_frame_symbolizer.h \
    1.21 + 	src/google_breakpad/processor/stackwalker.h \
    1.22 + 	src/google_breakpad/processor/symbol_supplier.h \
    1.23 + 	src/google_breakpad/processor/system_info.h \
    1.24 + 	src/common/module.cc \
    1.25 ++	src/common/unique_string.cc \
    1.26 + 	src/processor/address_map-inl.h \
    1.27 + 	src/processor/address_map.h \
    1.28 + 	src/processor/basic_code_module.h \
    1.29 + 	src/processor/basic_code_modules.cc \
    1.30 + 	src/processor/basic_code_modules.h \
    1.31 + 	src/processor/basic_source_line_resolver_types.h \
    1.32 + 	src/processor/basic_source_line_resolver.cc \
    1.33 + 	src/processor/binarystream.h \
    1.34 +@@ -430,16 +431,17 @@
    1.35 + src_tools_linux_dump_syms_dump_syms_SOURCES = \
    1.36 + 	src/common/dwarf_cfi_to_module.cc \
    1.37 + 	src/common/dwarf_cu_to_module.cc \
    1.38 + 	src/common/dwarf_line_to_module.cc \
    1.39 + 	src/common/language.cc \
    1.40 + 	src/common/module.cc \
    1.41 + 	src/common/stabs_reader.cc \
    1.42 + 	src/common/stabs_to_module.cc \
    1.43 ++	src/common/unique_string.cc \
    1.44 + 	src/common/dwarf/bytereader.cc \
    1.45 + 	src/common/dwarf/dwarf2diehandler.cc \
    1.46 + 	src/common/dwarf/dwarf2reader.cc \
    1.47 + 	src/common/linux/dump_symbols.cc \
    1.48 + 	src/common/linux/elf_symbols_to_module.cc \
    1.49 + 	src/common/linux/elfutils.cc \
    1.50 + 	src/common/linux/file_id.cc \
    1.51 + 	src/common/linux/linux_libc_support.cc \
    1.52 +@@ -473,16 +475,17 @@
    1.53 + 	src/common/memory_range_unittest.cc \
    1.54 + 	src/common/module.cc \
    1.55 + 	src/common/module_unittest.cc \
    1.56 + 	src/common/stabs_reader.cc \
    1.57 + 	src/common/stabs_reader_unittest.cc \
    1.58 + 	src/common/stabs_to_module.cc \
    1.59 + 	src/common/stabs_to_module_unittest.cc \
    1.60 + 	src/common/test_assembler.cc \
    1.61 ++	src/common/unique_string.cc \
    1.62 + 	src/common/dwarf/bytereader.cc \
    1.63 + 	src/common/dwarf/bytereader_unittest.cc \
    1.64 + 	src/common/dwarf/cfi_assembler.cc \
    1.65 + 	src/common/dwarf/dwarf2diehandler.cc \
    1.66 + 	src/common/dwarf/dwarf2diehandler_unittest.cc \
    1.67 + 	src/common/dwarf/dwarf2reader.cc \
    1.68 + 	src/common/dwarf/dwarf2reader_cfi_unittest.cc \
    1.69 + 	src/common/dwarf/dwarf2reader_die_unittest.cc \
    1.70 +@@ -561,31 +564,33 @@
    1.71 + src_processor_basic_source_line_resolver_unittest_CPPFLAGS = \
    1.72 + 	-I$(top_srcdir)/src \
    1.73 + 	-I$(top_srcdir)/src/testing/include \
    1.74 + 	-I$(top_srcdir)/src/testing/gtest/include \
    1.75 + 	-I$(top_srcdir)/src/testing/gtest \
    1.76 + 	-I$(top_srcdir)/src/testing
    1.77 + src_processor_basic_source_line_resolver_unittest_LDADD = \
    1.78 + 	src/common/module.o \
    1.79 ++	src/common/unique_string.o \
    1.80 + 	src/processor/basic_source_line_resolver.o \
    1.81 + 	src/processor/cfi_frame_info.o \
    1.82 + 	src/processor/pathname_stripper.o \
    1.83 + 	src/processor/logging.o \
    1.84 + 	src/processor/source_line_resolver_base.o \
    1.85 + 	src/processor/tokenize.o \
    1.86 + 	$(PTHREAD_CFLAGS) $(PTHREAD_LIBS)
    1.87 + 
    1.88 + src_processor_cfi_frame_info_unittest_SOURCES = \
    1.89 + 	src/processor/cfi_frame_info_unittest.cc \
    1.90 + 	src/testing/gtest/src/gtest-all.cc \
    1.91 + 	src/testing/gtest/src/gtest_main.cc \
    1.92 + 	src/testing/src/gmock-all.cc
    1.93 + src_processor_cfi_frame_info_unittest_LDADD = \
    1.94 + 	src/common/module.o \
    1.95 ++	src/common/unique_string.o \
    1.96 + 	src/processor/cfi_frame_info.o \
    1.97 + 	src/processor/logging.o \
    1.98 + 	src/processor/pathname_stripper.o \
    1.99 + 	$(PTHREAD_CFLAGS) $(PTHREAD_LIBS)
   1.100 + src_processor_cfi_frame_info_unittest_CPPFLAGS = \
   1.101 + 	-I$(top_srcdir)/src \
   1.102 + 	-I$(top_srcdir)/src/testing/include \
   1.103 + 	-I$(top_srcdir)/src/testing/gtest/include \
   1.104 +@@ -606,16 +611,17 @@
   1.105 + src_processor_exploitability_unittest_CPPFLAGS = \
   1.106 + 	-I$(top_srcdir)/src \
   1.107 + 	-I$(top_srcdir)/src/testing/include \
   1.108 + 	-I$(top_srcdir)/src/testing/gtest/include \
   1.109 + 	-I$(top_srcdir)/src/testing/gtest \
   1.110 + 	-I$(top_srcdir)/src/testing
   1.111 + src_processor_exploitability_unittest_LDADD = \
   1.112 + 	src/common/module.o \
   1.113 ++	src/common/unique_string.o \
   1.114 + 	src/processor/minidump_processor.o \
   1.115 + 	src/processor/process_state.o \
   1.116 + 	src/processor/disassembler_x86.o \
   1.117 + 	src/processor/exploitability.o \
   1.118 + 	src/processor/exploitability_win.o \
   1.119 + 	src/processor/basic_code_modules.o \
   1.120 + 	src/processor/basic_source_line_resolver.o \
   1.121 + 	src/processor/call_stack.o \
   1.122 +@@ -659,16 +665,17 @@
   1.123 + src_processor_fast_source_line_resolver_unittest_CPPFLAGS = \
   1.124 + 	-I$(top_srcdir)/src \
   1.125 + 	-I$(top_srcdir)/src/testing/include \
   1.126 + 	-I$(top_srcdir)/src/testing/gtest/include \
   1.127 + 	-I$(top_srcdir)/src/testing/gtest \
   1.128 + 	-I$(top_srcdir)/src/testing
   1.129 + src_processor_fast_source_line_resolver_unittest_LDADD = \
   1.130 + 	src/common/module.o \
   1.131 ++	src/common/unique_string.o \
   1.132 + 	src/processor/fast_source_line_resolver.o \
   1.133 + 	src/processor/basic_source_line_resolver.o \
   1.134 + 	src/processor/cfi_frame_info.o \
   1.135 + 	src/processor/module_comparer.o \
   1.136 + 	src/processor/module_serializer.o \
   1.137 + 	src/processor/pathname_stripper.o \
   1.138 + 	src/processor/logging.o \
   1.139 + 	src/processor/source_line_resolver_base.o \
   1.140 +@@ -697,16 +704,17 @@
   1.141 + src_processor_minidump_processor_unittest_CPPFLAGS = \
   1.142 + 	-I$(top_srcdir)/src \
   1.143 + 	-I$(top_srcdir)/src/testing/include \
   1.144 + 	-I$(top_srcdir)/src/testing/gtest/include \
   1.145 + 	-I$(top_srcdir)/src/testing/gtest \
   1.146 + 	-I$(top_srcdir)/src/testing
   1.147 + src_processor_minidump_processor_unittest_LDADD = \
   1.148 + 	src/common/module.o \
   1.149 ++	src/common/unique_string.o \
   1.150 + 	src/processor/basic_code_modules.o \
   1.151 + 	src/processor/basic_source_line_resolver.o \
   1.152 + 	src/processor/call_stack.o \
   1.153 + 	src/processor/cfi_frame_info.o \
   1.154 + 	src/processor/disassembler_x86.o \
   1.155 + 	src/processor/exploitability.o \
   1.156 + 	src/processor/exploitability_win.o \
   1.157 + 	src/processor/logging.o \
   1.158 +@@ -812,16 +820,17 @@
   1.159 + src_processor_pathname_stripper_unittest_LDADD = \
   1.160 + 	src/processor/pathname_stripper.o \
   1.161 + 	$(PTHREAD_CFLAGS) $(PTHREAD_LIBS)
   1.162 + 
   1.163 + src_processor_postfix_evaluator_unittest_SOURCES = \
   1.164 + 	src/processor/postfix_evaluator_unittest.cc
   1.165 + src_processor_postfix_evaluator_unittest_LDADD = \
   1.166 + 	src/common/module.o \
   1.167 ++	src/common/unique_string.o \
   1.168 + 	src/processor/logging.o \
   1.169 + 	src/processor/pathname_stripper.o \
   1.170 + 	$(PTHREAD_CFLAGS) $(PTHREAD_LIBS)
   1.171 + 
   1.172 + src_processor_range_map_unittest_SOURCES = \
   1.173 + 	src/processor/range_map_unittest.cc
   1.174 + src_processor_range_map_unittest_LDADD = \
   1.175 + 	src/processor/logging.o \
   1.176 +@@ -943,16 +952,17 @@
   1.177 + 	src/processor/logging.o \
   1.178 + 	src/processor/minidump.o \
   1.179 + 	src/processor/pathname_stripper.o
   1.180 + 
   1.181 + src_processor_minidump_stackwalk_SOURCES = \
   1.182 + 	src/processor/minidump_stackwalk.cc
   1.183 + src_processor_minidump_stackwalk_LDADD = \
   1.184 + 	src/common/module.o \
   1.185 ++	src/common/unique_string.o \
   1.186 + 	src/processor/basic_code_modules.o \
   1.187 + 	src/processor/basic_source_line_resolver.o \
   1.188 + 	src/processor/binarystream.o \
   1.189 + 	src/processor/call_stack.o \
   1.190 + 	src/processor/cfi_frame_info.o \
   1.191 + 	src/processor/disassembler_x86.o \
   1.192 + 	src/processor/exploitability.o \
   1.193 + 	src/processor/exploitability_win.o \
   1.194 +diff --git a/Makefile.in b/Makefile.in
   1.195 +--- a/Makefile.in
   1.196 ++++ b/Makefile.in
   1.197 +@@ -267,18 +267,19 @@
   1.198 + 	src/google_breakpad/processor/source_line_resolver_base.h \
   1.199 + 	src/google_breakpad/processor/source_line_resolver_interface.h \
   1.200 + 	src/google_breakpad/processor/stack_frame.h \
   1.201 + 	src/google_breakpad/processor/stack_frame_cpu.h \
   1.202 + 	src/google_breakpad/processor/stack_frame_symbolizer.h \
   1.203 + 	src/google_breakpad/processor/stackwalker.h \
   1.204 + 	src/google_breakpad/processor/symbol_supplier.h \
   1.205 + 	src/google_breakpad/processor/system_info.h \
   1.206 +-	src/common/module.cc src/processor/address_map-inl.h \
   1.207 +-	src/processor/address_map.h src/processor/basic_code_module.h \
   1.208 ++	src/common/module.cc src/common/unique_string.cc \
   1.209 ++	src/processor/address_map-inl.h src/processor/address_map.h \
   1.210 ++	src/processor/basic_code_module.h \
   1.211 + 	src/processor/basic_code_modules.cc \
   1.212 + 	src/processor/basic_code_modules.h \
   1.213 + 	src/processor/basic_source_line_resolver_types.h \
   1.214 + 	src/processor/basic_source_line_resolver.cc \
   1.215 + 	src/processor/binarystream.h src/processor/binarystream.cc \
   1.216 + 	src/processor/call_stack.cc src/processor/cfi_frame_info.cc \
   1.217 + 	src/processor/cfi_frame_info.h \
   1.218 + 	src/processor/contained_range_map-inl.h \
   1.219 +@@ -332,16 +333,17 @@
   1.220 + 	src/processor/static_map_iterator-inl.h \
   1.221 + 	src/processor/static_map_iterator.h \
   1.222 + 	src/processor/static_map-inl.h src/processor/static_map.h \
   1.223 + 	src/processor/static_range_map-inl.h \
   1.224 + 	src/processor/static_range_map.h src/processor/tokenize.cc \
   1.225 + 	src/processor/tokenize.h
   1.226 + @DISABLE_PROCESSOR_FALSE@am_src_libbreakpad_a_OBJECTS =  \
   1.227 + @DISABLE_PROCESSOR_FALSE@	src/common/module.$(OBJEXT) \
   1.228 ++@DISABLE_PROCESSOR_FALSE@	src/common/unique_string.$(OBJEXT) \
   1.229 + @DISABLE_PROCESSOR_FALSE@	src/processor/basic_code_modules.$(OBJEXT) \
   1.230 + @DISABLE_PROCESSOR_FALSE@	src/processor/basic_source_line_resolver.$(OBJEXT) \
   1.231 + @DISABLE_PROCESSOR_FALSE@	src/processor/binarystream.$(OBJEXT) \
   1.232 + @DISABLE_PROCESSOR_FALSE@	src/processor/call_stack.$(OBJEXT) \
   1.233 + @DISABLE_PROCESSOR_FALSE@	src/processor/cfi_frame_info.$(OBJEXT) \
   1.234 + @DISABLE_PROCESSOR_FALSE@	src/processor/disassembler_x86.$(OBJEXT) \
   1.235 + @DISABLE_PROCESSOR_FALSE@	src/processor/exploitability.$(OBJEXT) \
   1.236 + @DISABLE_PROCESSOR_FALSE@	src/processor/exploitability_win.$(OBJEXT) \
   1.237 +@@ -525,17 +527,18 @@
   1.238 + 	src/common/dwarf_cu_to_module_unittest.cc \
   1.239 + 	src/common/dwarf_line_to_module.cc \
   1.240 + 	src/common/dwarf_line_to_module_unittest.cc \
   1.241 + 	src/common/language.cc src/common/memory_range_unittest.cc \
   1.242 + 	src/common/module.cc src/common/module_unittest.cc \
   1.243 + 	src/common/stabs_reader.cc src/common/stabs_reader_unittest.cc \
   1.244 + 	src/common/stabs_to_module.cc \
   1.245 + 	src/common/stabs_to_module_unittest.cc \
   1.246 +-	src/common/test_assembler.cc src/common/dwarf/bytereader.cc \
   1.247 ++	src/common/test_assembler.cc src/common/unique_string.cc \
   1.248 ++	src/common/dwarf/bytereader.cc \
   1.249 + 	src/common/dwarf/bytereader_unittest.cc \
   1.250 + 	src/common/dwarf/cfi_assembler.cc \
   1.251 + 	src/common/dwarf/dwarf2diehandler.cc \
   1.252 + 	src/common/dwarf/dwarf2diehandler_unittest.cc \
   1.253 + 	src/common/dwarf/dwarf2reader.cc \
   1.254 + 	src/common/dwarf/dwarf2reader_cfi_unittest.cc \
   1.255 + 	src/common/dwarf/dwarf2reader_die_unittest.cc \
   1.256 + 	src/common/linux/dump_symbols.cc \
   1.257 +@@ -569,16 +572,17 @@
   1.258 + @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@	src/common/src_common_dumper_unittest-memory_range_unittest.$(OBJEXT) \
   1.259 + @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@	src/common/src_common_dumper_unittest-module.$(OBJEXT) \
   1.260 + @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@	src/common/src_common_dumper_unittest-module_unittest.$(OBJEXT) \
   1.261 + @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@	src/common/src_common_dumper_unittest-stabs_reader.$(OBJEXT) \
   1.262 + @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@	src/common/src_common_dumper_unittest-stabs_reader_unittest.$(OBJEXT) \
   1.263 + @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@	src/common/src_common_dumper_unittest-stabs_to_module.$(OBJEXT) \
   1.264 + @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@	src/common/src_common_dumper_unittest-stabs_to_module_unittest.$(OBJEXT) \
   1.265 + @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@	src/common/src_common_dumper_unittest-test_assembler.$(OBJEXT) \
   1.266 ++@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@	src/common/src_common_dumper_unittest-unique_string.$(OBJEXT) \
   1.267 + @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@	src/common/dwarf/src_common_dumper_unittest-bytereader.$(OBJEXT) \
   1.268 + @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@	src/common/dwarf/src_common_dumper_unittest-bytereader_unittest.$(OBJEXT) \
   1.269 + @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@	src/common/dwarf/src_common_dumper_unittest-cfi_assembler.$(OBJEXT) \
   1.270 + @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@	src/common/dwarf/src_common_dumper_unittest-dwarf2diehandler.$(OBJEXT) \
   1.271 + @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@	src/common/dwarf/src_common_dumper_unittest-dwarf2diehandler_unittest.$(OBJEXT) \
   1.272 + @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@	src/common/dwarf/src_common_dumper_unittest-dwarf2reader.$(OBJEXT) \
   1.273 + @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@	src/common/dwarf/src_common_dumper_unittest-dwarf2reader_cfi_unittest.$(OBJEXT) \
   1.274 + @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@	src/common/dwarf/src_common_dumper_unittest-dwarf2reader_die_unittest.$(OBJEXT) \
   1.275 +@@ -637,16 +641,17 @@
   1.276 + 	src/testing/gtest/src/gtest-all.cc \
   1.277 + 	src/testing/src/gmock-all.cc
   1.278 + @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) \
   1.279 + @DISABLE_PROCESSOR_FALSE@	src/testing/gtest/src/src_processor_basic_source_line_resolver_unittest-gtest-all.$(OBJEXT) \
   1.280 + @DISABLE_PROCESSOR_FALSE@	src/testing/src/src_processor_basic_source_line_resolver_unittest-gmock-all.$(OBJEXT)
   1.281 + src_processor_basic_source_line_resolver_unittest_OBJECTS = $(am_src_processor_basic_source_line_resolver_unittest_OBJECTS)
   1.282 + @DISABLE_PROCESSOR_FALSE@src_processor_basic_source_line_resolver_unittest_DEPENDENCIES =  \
   1.283 + @DISABLE_PROCESSOR_FALSE@	src/common/module.o \
   1.284 ++@DISABLE_PROCESSOR_FALSE@	src/common/unique_string.o \
   1.285 + @DISABLE_PROCESSOR_FALSE@	src/processor/basic_source_line_resolver.o \
   1.286 + @DISABLE_PROCESSOR_FALSE@	src/processor/cfi_frame_info.o \
   1.287 + @DISABLE_PROCESSOR_FALSE@	src/processor/pathname_stripper.o \
   1.288 + @DISABLE_PROCESSOR_FALSE@	src/processor/logging.o \
   1.289 + @DISABLE_PROCESSOR_FALSE@	src/processor/source_line_resolver_base.o \
   1.290 + @DISABLE_PROCESSOR_FALSE@	src/processor/tokenize.o \
   1.291 + @DISABLE_PROCESSOR_FALSE@	$(am__DEPENDENCIES_1) \
   1.292 + @DISABLE_PROCESSOR_FALSE@	$(am__DEPENDENCIES_1)
   1.293 +@@ -671,16 +676,17 @@
   1.294 + @DISABLE_PROCESSOR_FALSE@am_src_processor_cfi_frame_info_unittest_OBJECTS = src/processor/src_processor_cfi_frame_info_unittest-cfi_frame_info_unittest.$(OBJEXT) \
   1.295 + @DISABLE_PROCESSOR_FALSE@	src/testing/gtest/src/src_processor_cfi_frame_info_unittest-gtest-all.$(OBJEXT) \
   1.296 + @DISABLE_PROCESSOR_FALSE@	src/testing/gtest/src/src_processor_cfi_frame_info_unittest-gtest_main.$(OBJEXT) \
   1.297 + @DISABLE_PROCESSOR_FALSE@	src/testing/src/src_processor_cfi_frame_info_unittest-gmock-all.$(OBJEXT)
   1.298 + src_processor_cfi_frame_info_unittest_OBJECTS =  \
   1.299 + 	$(am_src_processor_cfi_frame_info_unittest_OBJECTS)
   1.300 + @DISABLE_PROCESSOR_FALSE@src_processor_cfi_frame_info_unittest_DEPENDENCIES =  \
   1.301 + @DISABLE_PROCESSOR_FALSE@	src/common/module.o \
   1.302 ++@DISABLE_PROCESSOR_FALSE@	src/common/unique_string.o \
   1.303 + @DISABLE_PROCESSOR_FALSE@	src/processor/cfi_frame_info.o \
   1.304 + @DISABLE_PROCESSOR_FALSE@	src/processor/logging.o \
   1.305 + @DISABLE_PROCESSOR_FALSE@	src/processor/pathname_stripper.o \
   1.306 + @DISABLE_PROCESSOR_FALSE@	$(am__DEPENDENCIES_1) \
   1.307 + @DISABLE_PROCESSOR_FALSE@	$(am__DEPENDENCIES_1)
   1.308 + am__src_processor_contained_range_map_unittest_SOURCES_DIST =  \
   1.309 + 	src/processor/contained_range_map_unittest.cc
   1.310 + @DISABLE_PROCESSOR_FALSE@am_src_processor_contained_range_map_unittest_OBJECTS = src/processor/contained_range_map_unittest.$(OBJEXT)
   1.311 +@@ -713,16 +719,17 @@
   1.312 + @DISABLE_PROCESSOR_FALSE@am_src_processor_exploitability_unittest_OBJECTS = src/processor/src_processor_exploitability_unittest-exploitability_unittest.$(OBJEXT) \
   1.313 + @DISABLE_PROCESSOR_FALSE@	src/testing/gtest/src/src_processor_exploitability_unittest-gtest-all.$(OBJEXT) \
   1.314 + @DISABLE_PROCESSOR_FALSE@	src/testing/gtest/src/src_processor_exploitability_unittest-gtest_main.$(OBJEXT) \
   1.315 + @DISABLE_PROCESSOR_FALSE@	src/testing/src/src_processor_exploitability_unittest-gmock-all.$(OBJEXT)
   1.316 + src_processor_exploitability_unittest_OBJECTS =  \
   1.317 + 	$(am_src_processor_exploitability_unittest_OBJECTS)
   1.318 + @DISABLE_PROCESSOR_FALSE@src_processor_exploitability_unittest_DEPENDENCIES =  \
   1.319 + @DISABLE_PROCESSOR_FALSE@	src/common/module.o \
   1.320 ++@DISABLE_PROCESSOR_FALSE@	src/common/unique_string.o \
   1.321 + @DISABLE_PROCESSOR_FALSE@	src/processor/minidump_processor.o \
   1.322 + @DISABLE_PROCESSOR_FALSE@	src/processor/process_state.o \
   1.323 + @DISABLE_PROCESSOR_FALSE@	src/processor/disassembler_x86.o \
   1.324 + @DISABLE_PROCESSOR_FALSE@	src/processor/exploitability.o \
   1.325 + @DISABLE_PROCESSOR_FALSE@	src/processor/exploitability_win.o \
   1.326 + @DISABLE_PROCESSOR_FALSE@	src/processor/basic_code_modules.o \
   1.327 + @DISABLE_PROCESSOR_FALSE@	src/processor/basic_source_line_resolver.o \
   1.328 + @DISABLE_PROCESSOR_FALSE@	src/processor/call_stack.o \
   1.329 +@@ -748,16 +755,17 @@
   1.330 + 	src/testing/gtest/src/gtest-all.cc \
   1.331 + 	src/testing/src/gmock-all.cc
   1.332 + @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) \
   1.333 + @DISABLE_PROCESSOR_FALSE@	src/testing/gtest/src/src_processor_fast_source_line_resolver_unittest-gtest-all.$(OBJEXT) \
   1.334 + @DISABLE_PROCESSOR_FALSE@	src/testing/src/src_processor_fast_source_line_resolver_unittest-gmock-all.$(OBJEXT)
   1.335 + src_processor_fast_source_line_resolver_unittest_OBJECTS = $(am_src_processor_fast_source_line_resolver_unittest_OBJECTS)
   1.336 + @DISABLE_PROCESSOR_FALSE@src_processor_fast_source_line_resolver_unittest_DEPENDENCIES =  \
   1.337 + @DISABLE_PROCESSOR_FALSE@	src/common/module.o \
   1.338 ++@DISABLE_PROCESSOR_FALSE@	src/common/unique_string.o \
   1.339 + @DISABLE_PROCESSOR_FALSE@	src/processor/fast_source_line_resolver.o \
   1.340 + @DISABLE_PROCESSOR_FALSE@	src/processor/basic_source_line_resolver.o \
   1.341 + @DISABLE_PROCESSOR_FALSE@	src/processor/cfi_frame_info.o \
   1.342 + @DISABLE_PROCESSOR_FALSE@	src/processor/module_comparer.o \
   1.343 + @DISABLE_PROCESSOR_FALSE@	src/processor/module_serializer.o \
   1.344 + @DISABLE_PROCESSOR_FALSE@	src/processor/pathname_stripper.o \
   1.345 + @DISABLE_PROCESSOR_FALSE@	src/processor/logging.o \
   1.346 + @DISABLE_PROCESSOR_FALSE@	src/processor/source_line_resolver_base.o \
   1.347 +@@ -794,16 +802,17 @@
   1.348 + 	src/testing/src/gmock-all.cc
   1.349 + @DISABLE_PROCESSOR_FALSE@am_src_processor_minidump_processor_unittest_OBJECTS = src/processor/src_processor_minidump_processor_unittest-minidump_processor_unittest.$(OBJEXT) \
   1.350 + @DISABLE_PROCESSOR_FALSE@	src/testing/gtest/src/src_processor_minidump_processor_unittest-gtest-all.$(OBJEXT) \
   1.351 + @DISABLE_PROCESSOR_FALSE@	src/testing/src/src_processor_minidump_processor_unittest-gmock-all.$(OBJEXT)
   1.352 + src_processor_minidump_processor_unittest_OBJECTS =  \
   1.353 + 	$(am_src_processor_minidump_processor_unittest_OBJECTS)
   1.354 + @DISABLE_PROCESSOR_FALSE@src_processor_minidump_processor_unittest_DEPENDENCIES =  \
   1.355 + @DISABLE_PROCESSOR_FALSE@	src/common/module.o \
   1.356 ++@DISABLE_PROCESSOR_FALSE@	src/common/unique_string.o \
   1.357 + @DISABLE_PROCESSOR_FALSE@	src/processor/basic_code_modules.o \
   1.358 + @DISABLE_PROCESSOR_FALSE@	src/processor/basic_source_line_resolver.o \
   1.359 + @DISABLE_PROCESSOR_FALSE@	src/processor/call_stack.o \
   1.360 + @DISABLE_PROCESSOR_FALSE@	src/processor/cfi_frame_info.o \
   1.361 + @DISABLE_PROCESSOR_FALSE@	src/processor/disassembler_x86.o \
   1.362 + @DISABLE_PROCESSOR_FALSE@	src/processor/exploitability.o \
   1.363 + @DISABLE_PROCESSOR_FALSE@	src/processor/exploitability_win.o \
   1.364 + @DISABLE_PROCESSOR_FALSE@	src/processor/logging.o \
   1.365 +@@ -826,16 +835,17 @@
   1.366 + @DISABLE_PROCESSOR_FALSE@	$(am__DEPENDENCIES_1)
   1.367 + am__src_processor_minidump_stackwalk_SOURCES_DIST =  \
   1.368 + 	src/processor/minidump_stackwalk.cc
   1.369 + @DISABLE_PROCESSOR_FALSE@am_src_processor_minidump_stackwalk_OBJECTS = src/processor/minidump_stackwalk.$(OBJEXT)
   1.370 + src_processor_minidump_stackwalk_OBJECTS =  \
   1.371 + 	$(am_src_processor_minidump_stackwalk_OBJECTS)
   1.372 + @DISABLE_PROCESSOR_FALSE@src_processor_minidump_stackwalk_DEPENDENCIES =  \
   1.373 + @DISABLE_PROCESSOR_FALSE@	src/common/module.o \
   1.374 ++@DISABLE_PROCESSOR_FALSE@	src/common/unique_string.o \
   1.375 + @DISABLE_PROCESSOR_FALSE@	src/processor/basic_code_modules.o \
   1.376 + @DISABLE_PROCESSOR_FALSE@	src/processor/basic_source_line_resolver.o \
   1.377 + @DISABLE_PROCESSOR_FALSE@	src/processor/binarystream.o \
   1.378 + @DISABLE_PROCESSOR_FALSE@	src/processor/call_stack.o \
   1.379 + @DISABLE_PROCESSOR_FALSE@	src/processor/cfi_frame_info.o \
   1.380 + @DISABLE_PROCESSOR_FALSE@	src/processor/disassembler_x86.o \
   1.381 + @DISABLE_PROCESSOR_FALSE@	src/processor/exploitability.o \
   1.382 + @DISABLE_PROCESSOR_FALSE@	src/processor/exploitability_win.o \
   1.383 +@@ -889,16 +899,17 @@
   1.384 + @DISABLE_PROCESSOR_FALSE@	$(am__DEPENDENCIES_1)
   1.385 + am__src_processor_postfix_evaluator_unittest_SOURCES_DIST =  \
   1.386 + 	src/processor/postfix_evaluator_unittest.cc
   1.387 + @DISABLE_PROCESSOR_FALSE@am_src_processor_postfix_evaluator_unittest_OBJECTS = src/processor/postfix_evaluator_unittest.$(OBJEXT)
   1.388 + src_processor_postfix_evaluator_unittest_OBJECTS =  \
   1.389 + 	$(am_src_processor_postfix_evaluator_unittest_OBJECTS)
   1.390 + @DISABLE_PROCESSOR_FALSE@src_processor_postfix_evaluator_unittest_DEPENDENCIES =  \
   1.391 + @DISABLE_PROCESSOR_FALSE@	src/common/module.o \
   1.392 ++@DISABLE_PROCESSOR_FALSE@	src/common/unique_string.o \
   1.393 + @DISABLE_PROCESSOR_FALSE@	src/processor/logging.o \
   1.394 + @DISABLE_PROCESSOR_FALSE@	src/processor/pathname_stripper.o \
   1.395 + @DISABLE_PROCESSOR_FALSE@	$(am__DEPENDENCIES_1) \
   1.396 + @DISABLE_PROCESSOR_FALSE@	$(am__DEPENDENCIES_1)
   1.397 + am__src_processor_range_map_unittest_SOURCES_DIST =  \
   1.398 + 	src/processor/range_map_unittest.cc
   1.399 + @DISABLE_PROCESSOR_FALSE@am_src_processor_range_map_unittest_OBJECTS = src/processor/range_map_unittest.$(OBJEXT)
   1.400 + src_processor_range_map_unittest_OBJECTS =  \
   1.401 +@@ -1069,33 +1080,35 @@
   1.402 + src_tools_linux_core2md_core2md_OBJECTS =  \
   1.403 + 	$(am_src_tools_linux_core2md_core2md_OBJECTS)
   1.404 + @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@src_tools_linux_core2md_core2md_DEPENDENCIES = src/client/linux/libbreakpad_client.a
   1.405 + am__src_tools_linux_dump_syms_dump_syms_SOURCES_DIST =  \
   1.406 + 	src/common/dwarf_cfi_to_module.cc \
   1.407 + 	src/common/dwarf_cu_to_module.cc \
   1.408 + 	src/common/dwarf_line_to_module.cc src/common/language.cc \
   1.409 + 	src/common/module.cc src/common/stabs_reader.cc \
   1.410 +-	src/common/stabs_to_module.cc src/common/dwarf/bytereader.cc \
   1.411 ++	src/common/stabs_to_module.cc src/common/unique_string.cc \
   1.412 ++	src/common/dwarf/bytereader.cc \
   1.413 + 	src/common/dwarf/dwarf2diehandler.cc \
   1.414 + 	src/common/dwarf/dwarf2reader.cc \
   1.415 + 	src/common/linux/dump_symbols.cc \
   1.416 + 	src/common/linux/elf_symbols_to_module.cc \
   1.417 + 	src/common/linux/elfutils.cc src/common/linux/file_id.cc \
   1.418 + 	src/common/linux/linux_libc_support.cc \
   1.419 + 	src/common/linux/memory_mapped_file.cc \
   1.420 + 	src/common/linux/safe_readlink.cc \
   1.421 + 	src/tools/linux/dump_syms/dump_syms.cc
   1.422 + @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@am_src_tools_linux_dump_syms_dump_syms_OBJECTS = src/common/dwarf_cfi_to_module.$(OBJEXT) \
   1.423 + @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@	src/common/dwarf_cu_to_module.$(OBJEXT) \
   1.424 + @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@	src/common/dwarf_line_to_module.$(OBJEXT) \
   1.425 + @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@	src/common/language.$(OBJEXT) \
   1.426 + @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@	src/common/module.$(OBJEXT) \
   1.427 + @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@	src/common/stabs_reader.$(OBJEXT) \
   1.428 + @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@	src/common/stabs_to_module.$(OBJEXT) \
   1.429 ++@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@	src/common/unique_string.$(OBJEXT) \
   1.430 + @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@	src/common/dwarf/bytereader.$(OBJEXT) \
   1.431 + @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@	src/common/dwarf/dwarf2diehandler.$(OBJEXT) \
   1.432 + @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@	src/common/dwarf/dwarf2reader.$(OBJEXT) \
   1.433 + @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@	src/common/linux/dump_symbols.$(OBJEXT) \
   1.434 + @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@	src/common/linux/elf_symbols_to_module.$(OBJEXT) \
   1.435 + @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@	src/common/linux/elfutils.$(OBJEXT) \
   1.436 + @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@	src/common/linux/file_id.$(OBJEXT) \
   1.437 + @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@	src/common/linux/linux_libc_support.$(OBJEXT) \
   1.438 +@@ -1416,16 +1429,17 @@
   1.439 + @DISABLE_PROCESSOR_FALSE@	src/google_breakpad/processor/source_line_resolver_interface.h \
   1.440 + @DISABLE_PROCESSOR_FALSE@	src/google_breakpad/processor/stack_frame.h \
   1.441 + @DISABLE_PROCESSOR_FALSE@	src/google_breakpad/processor/stack_frame_cpu.h \
   1.442 + @DISABLE_PROCESSOR_FALSE@	src/google_breakpad/processor/stack_frame_symbolizer.h \
   1.443 + @DISABLE_PROCESSOR_FALSE@	src/google_breakpad/processor/stackwalker.h \
   1.444 + @DISABLE_PROCESSOR_FALSE@	src/google_breakpad/processor/symbol_supplier.h \
   1.445 + @DISABLE_PROCESSOR_FALSE@	src/google_breakpad/processor/system_info.h \
   1.446 + @DISABLE_PROCESSOR_FALSE@	src/common/module.cc \
   1.447 ++@DISABLE_PROCESSOR_FALSE@	src/common/unique_string.cc \
   1.448 + @DISABLE_PROCESSOR_FALSE@	src/processor/address_map-inl.h \
   1.449 + @DISABLE_PROCESSOR_FALSE@	src/processor/address_map.h \
   1.450 + @DISABLE_PROCESSOR_FALSE@	src/processor/basic_code_module.h \
   1.451 + @DISABLE_PROCESSOR_FALSE@	src/processor/basic_code_modules.cc \
   1.452 + @DISABLE_PROCESSOR_FALSE@	src/processor/basic_code_modules.h \
   1.453 + @DISABLE_PROCESSOR_FALSE@	src/processor/basic_source_line_resolver_types.h \
   1.454 + @DISABLE_PROCESSOR_FALSE@	src/processor/basic_source_line_resolver.cc \
   1.455 + @DISABLE_PROCESSOR_FALSE@	src/processor/binarystream.h \
   1.456 +@@ -1618,16 +1632,17 @@
   1.457 + @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@src_tools_linux_dump_syms_dump_syms_SOURCES = \
   1.458 + @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@	src/common/dwarf_cfi_to_module.cc \
   1.459 + @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@	src/common/dwarf_cu_to_module.cc \
   1.460 + @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@	src/common/dwarf_line_to_module.cc \
   1.461 + @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@	src/common/language.cc \
   1.462 + @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@	src/common/module.cc \
   1.463 + @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@	src/common/stabs_reader.cc \
   1.464 + @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@	src/common/stabs_to_module.cc \
   1.465 ++@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@	src/common/unique_string.cc \
   1.466 + @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@	src/common/dwarf/bytereader.cc \
   1.467 + @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@	src/common/dwarf/dwarf2diehandler.cc \
   1.468 + @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@	src/common/dwarf/dwarf2reader.cc \
   1.469 + @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@	src/common/linux/dump_symbols.cc \
   1.470 + @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@	src/common/linux/elf_symbols_to_module.cc \
   1.471 + @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@	src/common/linux/elfutils.cc \
   1.472 + @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@	src/common/linux/file_id.cc \
   1.473 + @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@	src/common/linux/linux_libc_support.cc \
   1.474 +@@ -1661,16 +1676,17 @@
   1.475 + @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@	src/common/memory_range_unittest.cc \
   1.476 + @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@	src/common/module.cc \
   1.477 + @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@	src/common/module_unittest.cc \
   1.478 + @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@	src/common/stabs_reader.cc \
   1.479 + @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@	src/common/stabs_reader_unittest.cc \
   1.480 + @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@	src/common/stabs_to_module.cc \
   1.481 + @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@	src/common/stabs_to_module_unittest.cc \
   1.482 + @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@	src/common/test_assembler.cc \
   1.483 ++@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@	src/common/unique_string.cc \
   1.484 + @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@	src/common/dwarf/bytereader.cc \
   1.485 + @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@	src/common/dwarf/bytereader_unittest.cc \
   1.486 + @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@	src/common/dwarf/cfi_assembler.cc \
   1.487 + @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@	src/common/dwarf/dwarf2diehandler.cc \
   1.488 + @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@	src/common/dwarf/dwarf2diehandler_unittest.cc \
   1.489 + @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@	src/common/dwarf/dwarf2reader.cc \
   1.490 + @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@	src/common/dwarf/dwarf2reader_cfi_unittest.cc \
   1.491 + @DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@	src/common/dwarf/dwarf2reader_die_unittest.cc \
   1.492 +@@ -1753,32 +1769,34 @@
   1.493 + @DISABLE_PROCESSOR_FALSE@	-I$(top_srcdir)/src \
   1.494 + @DISABLE_PROCESSOR_FALSE@	-I$(top_srcdir)/src/testing/include \
   1.495 + @DISABLE_PROCESSOR_FALSE@	-I$(top_srcdir)/src/testing/gtest/include \
   1.496 + @DISABLE_PROCESSOR_FALSE@	-I$(top_srcdir)/src/testing/gtest \
   1.497 + @DISABLE_PROCESSOR_FALSE@	-I$(top_srcdir)/src/testing
   1.498 + 
   1.499 + @DISABLE_PROCESSOR_FALSE@src_processor_basic_source_line_resolver_unittest_LDADD = \
   1.500 + @DISABLE_PROCESSOR_FALSE@	src/common/module.o \
   1.501 ++@DISABLE_PROCESSOR_FALSE@	src/common/unique_string.o \
   1.502 + @DISABLE_PROCESSOR_FALSE@	src/processor/basic_source_line_resolver.o \
   1.503 + @DISABLE_PROCESSOR_FALSE@	src/processor/cfi_frame_info.o \
   1.504 + @DISABLE_PROCESSOR_FALSE@	src/processor/pathname_stripper.o \
   1.505 + @DISABLE_PROCESSOR_FALSE@	src/processor/logging.o \
   1.506 + @DISABLE_PROCESSOR_FALSE@	src/processor/source_line_resolver_base.o \
   1.507 + @DISABLE_PROCESSOR_FALSE@	src/processor/tokenize.o \
   1.508 + @DISABLE_PROCESSOR_FALSE@	$(PTHREAD_CFLAGS) $(PTHREAD_LIBS)
   1.509 + 
   1.510 + @DISABLE_PROCESSOR_FALSE@src_processor_cfi_frame_info_unittest_SOURCES = \
   1.511 + @DISABLE_PROCESSOR_FALSE@	src/processor/cfi_frame_info_unittest.cc \
   1.512 + @DISABLE_PROCESSOR_FALSE@	src/testing/gtest/src/gtest-all.cc \
   1.513 + @DISABLE_PROCESSOR_FALSE@	src/testing/gtest/src/gtest_main.cc \
   1.514 + @DISABLE_PROCESSOR_FALSE@	src/testing/src/gmock-all.cc
   1.515 + 
   1.516 + @DISABLE_PROCESSOR_FALSE@src_processor_cfi_frame_info_unittest_LDADD = \
   1.517 + @DISABLE_PROCESSOR_FALSE@	src/common/module.o \
   1.518 ++@DISABLE_PROCESSOR_FALSE@	src/common/unique_string.o \
   1.519 + @DISABLE_PROCESSOR_FALSE@	src/processor/cfi_frame_info.o \
   1.520 + @DISABLE_PROCESSOR_FALSE@	src/processor/logging.o \
   1.521 + @DISABLE_PROCESSOR_FALSE@	src/processor/pathname_stripper.o \
   1.522 + @DISABLE_PROCESSOR_FALSE@	$(PTHREAD_CFLAGS) $(PTHREAD_LIBS)
   1.523 + 
   1.524 + @DISABLE_PROCESSOR_FALSE@src_processor_cfi_frame_info_unittest_CPPFLAGS = \
   1.525 + @DISABLE_PROCESSOR_FALSE@	-I$(top_srcdir)/src \
   1.526 + @DISABLE_PROCESSOR_FALSE@	-I$(top_srcdir)/src/testing/include \
   1.527 +@@ -1803,16 +1821,17 @@
   1.528 + @DISABLE_PROCESSOR_FALSE@	-I$(top_srcdir)/src \
   1.529 + @DISABLE_PROCESSOR_FALSE@	-I$(top_srcdir)/src/testing/include \
   1.530 + @DISABLE_PROCESSOR_FALSE@	-I$(top_srcdir)/src/testing/gtest/include \
   1.531 + @DISABLE_PROCESSOR_FALSE@	-I$(top_srcdir)/src/testing/gtest \
   1.532 + @DISABLE_PROCESSOR_FALSE@	-I$(top_srcdir)/src/testing
   1.533 + 
   1.534 + @DISABLE_PROCESSOR_FALSE@src_processor_exploitability_unittest_LDADD = \
   1.535 + @DISABLE_PROCESSOR_FALSE@	src/common/module.o \
   1.536 ++@DISABLE_PROCESSOR_FALSE@	src/common/unique_string.o \
   1.537 + @DISABLE_PROCESSOR_FALSE@	src/processor/minidump_processor.o \
   1.538 + @DISABLE_PROCESSOR_FALSE@	src/processor/process_state.o \
   1.539 + @DISABLE_PROCESSOR_FALSE@	src/processor/disassembler_x86.o \
   1.540 + @DISABLE_PROCESSOR_FALSE@	src/processor/exploitability.o \
   1.541 + @DISABLE_PROCESSOR_FALSE@	src/processor/exploitability_win.o \
   1.542 + @DISABLE_PROCESSOR_FALSE@	src/processor/basic_code_modules.o \
   1.543 + @DISABLE_PROCESSOR_FALSE@	src/processor/basic_source_line_resolver.o \
   1.544 + @DISABLE_PROCESSOR_FALSE@	src/processor/call_stack.o \
   1.545 +@@ -1860,16 +1879,17 @@
   1.546 + @DISABLE_PROCESSOR_FALSE@	-I$(top_srcdir)/src \
   1.547 + @DISABLE_PROCESSOR_FALSE@	-I$(top_srcdir)/src/testing/include \
   1.548 + @DISABLE_PROCESSOR_FALSE@	-I$(top_srcdir)/src/testing/gtest/include \
   1.549 + @DISABLE_PROCESSOR_FALSE@	-I$(top_srcdir)/src/testing/gtest \
   1.550 + @DISABLE_PROCESSOR_FALSE@	-I$(top_srcdir)/src/testing
   1.551 + 
   1.552 + @DISABLE_PROCESSOR_FALSE@src_processor_fast_source_line_resolver_unittest_LDADD = \
   1.553 + @DISABLE_PROCESSOR_FALSE@	src/common/module.o \
   1.554 ++@DISABLE_PROCESSOR_FALSE@	src/common/unique_string.o \
   1.555 + @DISABLE_PROCESSOR_FALSE@	src/processor/fast_source_line_resolver.o \
   1.556 + @DISABLE_PROCESSOR_FALSE@	src/processor/basic_source_line_resolver.o \
   1.557 + @DISABLE_PROCESSOR_FALSE@	src/processor/cfi_frame_info.o \
   1.558 + @DISABLE_PROCESSOR_FALSE@	src/processor/module_comparer.o \
   1.559 + @DISABLE_PROCESSOR_FALSE@	src/processor/module_serializer.o \
   1.560 + @DISABLE_PROCESSOR_FALSE@	src/processor/pathname_stripper.o \
   1.561 + @DISABLE_PROCESSOR_FALSE@	src/processor/logging.o \
   1.562 + @DISABLE_PROCESSOR_FALSE@	src/processor/source_line_resolver_base.o \
   1.563 +@@ -1902,16 +1922,17 @@
   1.564 + @DISABLE_PROCESSOR_FALSE@	-I$(top_srcdir)/src \
   1.565 + @DISABLE_PROCESSOR_FALSE@	-I$(top_srcdir)/src/testing/include \
   1.566 + @DISABLE_PROCESSOR_FALSE@	-I$(top_srcdir)/src/testing/gtest/include \
   1.567 + @DISABLE_PROCESSOR_FALSE@	-I$(top_srcdir)/src/testing/gtest \
   1.568 + @DISABLE_PROCESSOR_FALSE@	-I$(top_srcdir)/src/testing
   1.569 + 
   1.570 + @DISABLE_PROCESSOR_FALSE@src_processor_minidump_processor_unittest_LDADD = \
   1.571 + @DISABLE_PROCESSOR_FALSE@	src/common/module.o \
   1.572 ++@DISABLE_PROCESSOR_FALSE@	src/common/unique_string.o \
   1.573 + @DISABLE_PROCESSOR_FALSE@	src/processor/basic_code_modules.o \
   1.574 + @DISABLE_PROCESSOR_FALSE@	src/processor/basic_source_line_resolver.o \
   1.575 + @DISABLE_PROCESSOR_FALSE@	src/processor/call_stack.o \
   1.576 + @DISABLE_PROCESSOR_FALSE@	src/processor/cfi_frame_info.o \
   1.577 + @DISABLE_PROCESSOR_FALSE@	src/processor/disassembler_x86.o \
   1.578 + @DISABLE_PROCESSOR_FALSE@	src/processor/exploitability.o \
   1.579 + @DISABLE_PROCESSOR_FALSE@	src/processor/exploitability_win.o \
   1.580 + @DISABLE_PROCESSOR_FALSE@	src/processor/logging.o \
   1.581 +@@ -2029,16 +2050,17 @@
   1.582 + @DISABLE_PROCESSOR_FALSE@	src/processor/pathname_stripper.o \
   1.583 + @DISABLE_PROCESSOR_FALSE@	$(PTHREAD_CFLAGS) $(PTHREAD_LIBS)
   1.584 + 
   1.585 + @DISABLE_PROCESSOR_FALSE@src_processor_postfix_evaluator_unittest_SOURCES = \
   1.586 + @DISABLE_PROCESSOR_FALSE@	src/processor/postfix_evaluator_unittest.cc
   1.587 + 
   1.588 + @DISABLE_PROCESSOR_FALSE@src_processor_postfix_evaluator_unittest_LDADD = \
   1.589 + @DISABLE_PROCESSOR_FALSE@	src/common/module.o \
   1.590 ++@DISABLE_PROCESSOR_FALSE@	src/common/unique_string.o \
   1.591 + @DISABLE_PROCESSOR_FALSE@	src/processor/logging.o \
   1.592 + @DISABLE_PROCESSOR_FALSE@	src/processor/pathname_stripper.o \
   1.593 + @DISABLE_PROCESSOR_FALSE@	$(PTHREAD_CFLAGS) $(PTHREAD_LIBS)
   1.594 + 
   1.595 + @DISABLE_PROCESSOR_FALSE@src_processor_range_map_unittest_SOURCES = \
   1.596 + @DISABLE_PROCESSOR_FALSE@	src/processor/range_map_unittest.cc
   1.597 + 
   1.598 + @DISABLE_PROCESSOR_FALSE@src_processor_range_map_unittest_LDADD = \
   1.599 +@@ -2169,16 +2191,17 @@
   1.600 + @DISABLE_PROCESSOR_FALSE@	src/processor/minidump.o \
   1.601 + @DISABLE_PROCESSOR_FALSE@	src/processor/pathname_stripper.o
   1.602 + 
   1.603 + @DISABLE_PROCESSOR_FALSE@src_processor_minidump_stackwalk_SOURCES = \
   1.604 + @DISABLE_PROCESSOR_FALSE@	src/processor/minidump_stackwalk.cc
   1.605 + 
   1.606 + @DISABLE_PROCESSOR_FALSE@src_processor_minidump_stackwalk_LDADD = \
   1.607 + @DISABLE_PROCESSOR_FALSE@	src/common/module.o \
   1.608 ++@DISABLE_PROCESSOR_FALSE@	src/common/unique_string.o \
   1.609 + @DISABLE_PROCESSOR_FALSE@	src/processor/basic_code_modules.o \
   1.610 + @DISABLE_PROCESSOR_FALSE@	src/processor/basic_source_line_resolver.o \
   1.611 + @DISABLE_PROCESSOR_FALSE@	src/processor/binarystream.o \
   1.612 + @DISABLE_PROCESSOR_FALSE@	src/processor/call_stack.o \
   1.613 + @DISABLE_PROCESSOR_FALSE@	src/processor/cfi_frame_info.o \
   1.614 + @DISABLE_PROCESSOR_FALSE@	src/processor/disassembler_x86.o \
   1.615 + @DISABLE_PROCESSOR_FALSE@	src/processor/exploitability.o \
   1.616 + @DISABLE_PROCESSOR_FALSE@	src/processor/exploitability_win.o \
   1.617 +@@ -2527,16 +2550,18 @@
   1.618 + 	@$(MKDIR_P) src/client/linux
   1.619 + 	@: > src/client/linux/$(am__dirstamp)
   1.620 + 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)
   1.621 + 	-rm -f src/client/linux/libbreakpad_client.a
   1.622 + 	$(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)
   1.623 + 	$(RANLIB) src/client/linux/libbreakpad_client.a
   1.624 + src/common/module.$(OBJEXT): src/common/$(am__dirstamp) \
   1.625 + 	src/common/$(DEPDIR)/$(am__dirstamp)
   1.626 ++src/common/unique_string.$(OBJEXT): src/common/$(am__dirstamp) \
   1.627 ++	src/common/$(DEPDIR)/$(am__dirstamp)
   1.628 + src/processor/$(am__dirstamp):
   1.629 + 	@$(MKDIR_P) src/processor
   1.630 + 	@: > src/processor/$(am__dirstamp)
   1.631 + src/processor/$(DEPDIR)/$(am__dirstamp):
   1.632 + 	@$(MKDIR_P) src/processor/$(DEPDIR)
   1.633 + 	@: > src/processor/$(DEPDIR)/$(am__dirstamp)
   1.634 + src/processor/basic_code_modules.$(OBJEXT):  \
   1.635 + 	src/processor/$(am__dirstamp) \
   1.636 +@@ -2863,16 +2888,19 @@
   1.637 + 	src/common/$(am__dirstamp) \
   1.638 + 	src/common/$(DEPDIR)/$(am__dirstamp)
   1.639 + src/common/src_common_dumper_unittest-stabs_to_module_unittest.$(OBJEXT):  \
   1.640 + 	src/common/$(am__dirstamp) \
   1.641 + 	src/common/$(DEPDIR)/$(am__dirstamp)
   1.642 + src/common/src_common_dumper_unittest-test_assembler.$(OBJEXT):  \
   1.643 + 	src/common/$(am__dirstamp) \
   1.644 + 	src/common/$(DEPDIR)/$(am__dirstamp)
   1.645 ++src/common/src_common_dumper_unittest-unique_string.$(OBJEXT):  \
   1.646 ++	src/common/$(am__dirstamp) \
   1.647 ++	src/common/$(DEPDIR)/$(am__dirstamp)
   1.648 + src/common/dwarf/$(am__dirstamp):
   1.649 + 	@$(MKDIR_P) src/common/dwarf
   1.650 + 	@: > src/common/dwarf/$(am__dirstamp)
   1.651 + src/common/dwarf/$(DEPDIR)/$(am__dirstamp):
   1.652 + 	@$(MKDIR_P) src/common/dwarf/$(DEPDIR)
   1.653 + 	@: > src/common/dwarf/$(DEPDIR)/$(am__dirstamp)
   1.654 + src/common/dwarf/src_common_dumper_unittest-bytereader.$(OBJEXT):  \
   1.655 + 	src/common/dwarf/$(am__dirstamp) \
   1.656 +@@ -3470,28 +3498,30 @@
   1.657 + 	-rm -f src/common/src_common_dumper_unittest-memory_range_unittest.$(OBJEXT)
   1.658 + 	-rm -f src/common/src_common_dumper_unittest-module.$(OBJEXT)
   1.659 + 	-rm -f src/common/src_common_dumper_unittest-module_unittest.$(OBJEXT)
   1.660 + 	-rm -f src/common/src_common_dumper_unittest-stabs_reader.$(OBJEXT)
   1.661 + 	-rm -f src/common/src_common_dumper_unittest-stabs_reader_unittest.$(OBJEXT)
   1.662 + 	-rm -f src/common/src_common_dumper_unittest-stabs_to_module.$(OBJEXT)
   1.663 + 	-rm -f src/common/src_common_dumper_unittest-stabs_to_module_unittest.$(OBJEXT)
   1.664 + 	-rm -f src/common/src_common_dumper_unittest-test_assembler.$(OBJEXT)
   1.665 ++	-rm -f src/common/src_common_dumper_unittest-unique_string.$(OBJEXT)
   1.666 + 	-rm -f src/common/src_common_test_assembler_unittest-test_assembler.$(OBJEXT)
   1.667 + 	-rm -f src/common/src_common_test_assembler_unittest-test_assembler_unittest.$(OBJEXT)
   1.668 + 	-rm -f src/common/src_processor_minidump_unittest-test_assembler.$(OBJEXT)
   1.669 + 	-rm -f src/common/src_processor_stackwalker_amd64_unittest-test_assembler.$(OBJEXT)
   1.670 + 	-rm -f src/common/src_processor_stackwalker_arm_unittest-test_assembler.$(OBJEXT)
   1.671 + 	-rm -f src/common/src_processor_stackwalker_x86_unittest-test_assembler.$(OBJEXT)
   1.672 + 	-rm -f src/common/src_processor_synth_minidump_unittest-test_assembler.$(OBJEXT)
   1.673 + 	-rm -f src/common/stabs_reader.$(OBJEXT)
   1.674 + 	-rm -f src/common/stabs_to_module.$(OBJEXT)
   1.675 + 	-rm -f src/common/string_conversion.$(OBJEXT)
   1.676 + 	-rm -f src/common/tests/src_client_linux_linux_client_unittest_shlib-file_utils.$(OBJEXT)
   1.677 + 	-rm -f src/common/tests/src_common_dumper_unittest-file_utils.$(OBJEXT)
   1.678 ++	-rm -f src/common/unique_string.$(OBJEXT)
   1.679 + 	-rm -f src/processor/address_map_unittest.$(OBJEXT)
   1.680 + 	-rm -f src/processor/basic_code_modules.$(OBJEXT)
   1.681 + 	-rm -f src/processor/basic_source_line_resolver.$(OBJEXT)
   1.682 + 	-rm -f src/processor/binarystream.$(OBJEXT)
   1.683 + 	-rm -f src/processor/call_stack.$(OBJEXT)
   1.684 + 	-rm -f src/processor/cfi_frame_info.$(OBJEXT)
   1.685 + 	-rm -f src/processor/contained_range_map_unittest.$(OBJEXT)
   1.686 + 	-rm -f src/processor/disassembler_x86.$(OBJEXT)
   1.687 +@@ -3663,26 +3693,28 @@
   1.688 + @AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/src_common_dumper_unittest-memory_range_unittest.Po@am__quote@
   1.689 + @AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/src_common_dumper_unittest-module.Po@am__quote@
   1.690 + @AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/src_common_dumper_unittest-module_unittest.Po@am__quote@
   1.691 + @AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/src_common_dumper_unittest-stabs_reader.Po@am__quote@
   1.692 + @AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/src_common_dumper_unittest-stabs_reader_unittest.Po@am__quote@
   1.693 + @AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/src_common_dumper_unittest-stabs_to_module.Po@am__quote@
   1.694 + @AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/src_common_dumper_unittest-stabs_to_module_unittest.Po@am__quote@
   1.695 + @AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/src_common_dumper_unittest-test_assembler.Po@am__quote@
   1.696 ++@AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/src_common_dumper_unittest-unique_string.Po@am__quote@
   1.697 + @AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/src_common_test_assembler_unittest-test_assembler.Po@am__quote@
   1.698 + @AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/src_common_test_assembler_unittest-test_assembler_unittest.Po@am__quote@
   1.699 + @AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/src_processor_minidump_unittest-test_assembler.Po@am__quote@
   1.700 + @AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/src_processor_stackwalker_amd64_unittest-test_assembler.Po@am__quote@
   1.701 + @AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/src_processor_stackwalker_arm_unittest-test_assembler.Po@am__quote@
   1.702 + @AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/src_processor_stackwalker_x86_unittest-test_assembler.Po@am__quote@
   1.703 + @AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/src_processor_synth_minidump_unittest-test_assembler.Po@am__quote@
   1.704 + @AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/stabs_reader.Po@am__quote@
   1.705 + @AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/stabs_to_module.Po@am__quote@
   1.706 + @AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/string_conversion.Po@am__quote@
   1.707 ++@AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/unique_string.Po@am__quote@
   1.708 + @AMDEP_TRUE@@am__include@ @am__quote@src/common/android/$(DEPDIR)/breakpad_getcontext.Po@am__quote@
   1.709 + @AMDEP_TRUE@@am__include@ @am__quote@src/common/android/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-breakpad_getcontext.Po@am__quote@
   1.710 + @AMDEP_TRUE@@am__include@ @am__quote@src/common/android/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-breakpad_getcontext_unittest.Po@am__quote@
   1.711 + @AMDEP_TRUE@@am__include@ @am__quote@src/common/dwarf/$(DEPDIR)/bytereader.Po@am__quote@
   1.712 + @AMDEP_TRUE@@am__include@ @am__quote@src/common/dwarf/$(DEPDIR)/dwarf2diehandler.Po@am__quote@
   1.713 + @AMDEP_TRUE@@am__include@ @am__quote@src/common/dwarf/$(DEPDIR)/dwarf2reader.Po@am__quote@
   1.714 + @AMDEP_TRUE@@am__include@ @am__quote@src/common/dwarf/$(DEPDIR)/src_common_dumper_unittest-bytereader.Po@am__quote@
   1.715 + @AMDEP_TRUE@@am__include@ @am__quote@src/common/dwarf/$(DEPDIR)/src_common_dumper_unittest-bytereader_unittest.Po@am__quote@
   1.716 +@@ -4474,16 +4506,30 @@
   1.717 + 
   1.718 + src/common/src_common_dumper_unittest-test_assembler.obj: src/common/test_assembler.cc
   1.719 + @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`
   1.720 + @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
   1.721 + @AMDEP_TRUE@@am__fastdepCXX_FALSE@	source='src/common/test_assembler.cc' object='src/common/src_common_dumper_unittest-test_assembler.obj' libtool=no @AMDEPBACKSLASH@
   1.722 + @AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
   1.723 + @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`
   1.724 + 
   1.725 ++src/common/src_common_dumper_unittest-unique_string.o: src/common/unique_string.cc
   1.726 ++@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
   1.727 ++@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
   1.728 ++@AMDEP_TRUE@@am__fastdepCXX_FALSE@	source='src/common/unique_string.cc' object='src/common/src_common_dumper_unittest-unique_string.o' libtool=no @AMDEPBACKSLASH@
   1.729 ++@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
   1.730 ++@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
   1.731 ++
   1.732 ++src/common/src_common_dumper_unittest-unique_string.obj: src/common/unique_string.cc
   1.733 ++@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`
   1.734 ++@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
   1.735 ++@AMDEP_TRUE@@am__fastdepCXX_FALSE@	source='src/common/unique_string.cc' object='src/common/src_common_dumper_unittest-unique_string.obj' libtool=no @AMDEPBACKSLASH@
   1.736 ++@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
   1.737 ++@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`
   1.738 ++
   1.739 + src/common/dwarf/src_common_dumper_unittest-bytereader.o: src/common/dwarf/bytereader.cc
   1.740 + @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
   1.741 + @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
   1.742 + @AMDEP_TRUE@@am__fastdepCXX_FALSE@	source='src/common/dwarf/bytereader.cc' object='src/common/dwarf/src_common_dumper_unittest-bytereader.o' libtool=no @AMDEPBACKSLASH@
   1.743 + @AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
   1.744 + @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
   1.745 + 
   1.746 + src/common/dwarf/src_common_dumper_unittest-bytereader.obj: src/common/dwarf/bytereader.cc
   1.747 +diff --git a/src/common/dwarf_cfi_to_module.cc b/src/common/dwarf_cfi_to_module.cc
   1.748 +--- a/src/common/dwarf_cfi_to_module.cc
   1.749 ++++ b/src/common/dwarf_cfi_to_module.cc
   1.750 +@@ -37,40 +37,44 @@
   1.751 + #include <sstream>
   1.752 + 
   1.753 + #include "common/dwarf_cfi_to_module.h"
   1.754 + 
   1.755 + namespace google_breakpad {
   1.756 + 
   1.757 + using std::ostringstream;
   1.758 + 
   1.759 +-vector<string> DwarfCFIToModule::RegisterNames::MakeVector(
   1.760 +-    const char * const *strings,
   1.761 ++vector<const UniqueString*> DwarfCFIToModule::RegisterNames::MakeVector(
   1.762 ++    const char* const* strings,
   1.763 +     size_t size) {
   1.764 +-  vector<string> names(strings, strings + size);
   1.765 ++  vector<const UniqueString*> names(size, NULL);
   1.766 ++  for (size_t i = 0; i < size; ++i) {
   1.767 ++    names[i] = ToUniqueString(strings[i]);
   1.768 ++  }
   1.769 ++
   1.770 +   return names;
   1.771 + }
   1.772 + 
   1.773 +-vector<string> DwarfCFIToModule::RegisterNames::I386() {
   1.774 ++vector<const UniqueString*> DwarfCFIToModule::RegisterNames::I386() {
   1.775 +   static const char *const names[] = {
   1.776 +     "$eax", "$ecx", "$edx", "$ebx", "$esp", "$ebp", "$esi", "$edi",
   1.777 +     "$eip", "$eflags", "$unused1",
   1.778 +     "$st0", "$st1", "$st2", "$st3", "$st4", "$st5", "$st6", "$st7",
   1.779 +     "$unused2", "$unused3",
   1.780 +     "$xmm0", "$xmm1", "$xmm2", "$xmm3", "$xmm4", "$xmm5", "$xmm6", "$xmm7",
   1.781 +     "$mm0", "$mm1", "$mm2", "$mm3", "$mm4", "$mm5", "$mm6", "$mm7",
   1.782 +     "$fcw", "$fsw", "$mxcsr",
   1.783 +     "$es", "$cs", "$ss", "$ds", "$fs", "$gs", "$unused4", "$unused5",
   1.784 +     "$tr", "$ldtr"
   1.785 +   };
   1.786 + 
   1.787 +   return MakeVector(names, sizeof(names) / sizeof(names[0]));
   1.788 + }
   1.789 + 
   1.790 +-vector<string> DwarfCFIToModule::RegisterNames::X86_64() {
   1.791 ++vector<const UniqueString*> DwarfCFIToModule::RegisterNames::X86_64() {
   1.792 +   static const char *const names[] = {
   1.793 +     "$rax", "$rdx", "$rcx", "$rbx", "$rsi", "$rdi", "$rbp", "$rsp",
   1.794 +     "$r8",  "$r9",  "$r10", "$r11", "$r12", "$r13", "$r14", "$r15",
   1.795 +     "$rip",
   1.796 +     "$xmm0","$xmm1","$xmm2", "$xmm3", "$xmm4", "$xmm5", "$xmm6", "$xmm7",
   1.797 +     "$xmm8","$xmm9","$xmm10","$xmm11","$xmm12","$xmm13","$xmm14","$xmm15",
   1.798 +     "$st0", "$st1", "$st2", "$st3", "$st4", "$st5", "$st6", "$st7",
   1.799 +     "$mm0", "$mm1", "$mm2", "$mm3", "$mm4", "$mm5", "$mm6", "$mm7",
   1.800 +@@ -80,17 +84,17 @@
   1.801 +     "$tr", "$ldtr",
   1.802 +     "$mxcsr", "$fcw", "$fsw"
   1.803 +   };
   1.804 + 
   1.805 +   return MakeVector(names, sizeof(names) / sizeof(names[0]));
   1.806 + }
   1.807 + 
   1.808 + // Per ARM IHI 0040A, section 3.1
   1.809 +-vector<string> DwarfCFIToModule::RegisterNames::ARM() {
   1.810 ++vector<const UniqueString*> DwarfCFIToModule::RegisterNames::ARM() {
   1.811 +   static const char *const names[] = {
   1.812 +     "r0",  "r1",  "r2",  "r3",  "r4",  "r5",  "r6",  "r7",
   1.813 +     "r8",  "r9",  "r10", "r11", "r12", "sp",  "lr",  "pc",
   1.814 +     "f0",  "f1",  "f2",  "f3",  "f4",  "f5",  "f6",  "f7",
   1.815 +     "fps", "cpsr", "",   "",    "",    "",    "",    "",
   1.816 +     "",    "",    "",    "",    "",    "",    "",    "",
   1.817 +     "",    "",    "",    "",    "",    "",    "",    "",
   1.818 +     "",    "",    "",    "",    "",    "",    "",    "",
   1.819 +@@ -122,40 +126,40 @@
   1.820 +   return_address_ = return_address;
   1.821 + 
   1.822 +   // Breakpad STACK CFI records must provide a .ra rule, but DWARF CFI
   1.823 +   // may not establish any rule for .ra if the return address column
   1.824 +   // is an ordinary register, and that register holds the return
   1.825 +   // address on entry to the function. So establish an initial .ra
   1.826 +   // rule citing the return address register.
   1.827 +   if (return_address_ < register_names_.size())
   1.828 +-    entry_->initial_rules[ra_name_]
   1.829 ++    entry_->initial_rules[ustr__ZDra()]
   1.830 +       = Module::Expr(register_names_[return_address_], 0, false);
   1.831 + 
   1.832 +   return true;
   1.833 + }
   1.834 + 
   1.835 +-string DwarfCFIToModule::RegisterName(int i) {
   1.836 ++const UniqueString* DwarfCFIToModule::RegisterName(int i) {
   1.837 +   assert(entry_);
   1.838 +   if (i < 0) {
   1.839 +     assert(i == kCFARegister);
   1.840 +-    return cfa_name_;
   1.841 ++    return ustr__ZDcfa();
   1.842 +   }
   1.843 +   unsigned reg = i;
   1.844 +   if (reg == return_address_)
   1.845 +-    return ra_name_;
   1.846 ++    return ustr__ZDra();
   1.847 + 
   1.848 +   // Ensure that a non-empty name exists for this register value.
   1.849 +-  if (reg < register_names_.size() && !register_names_[reg].empty())
   1.850 ++  if (reg < register_names_.size() && register_names_[reg] != ustr__empty())
   1.851 +     return register_names_[reg];
   1.852 + 
   1.853 +   reporter_->UnnamedRegister(entry_offset_, reg);
   1.854 +   char buf[30];
   1.855 +   sprintf(buf, "unnamed_register%u", reg);
   1.856 +-  return buf;
   1.857 ++  return ToUniqueString(buf);
   1.858 + }
   1.859 + 
   1.860 + void DwarfCFIToModule::Record(Module::Address address, int reg,
   1.861 +                               const Module::Expr &rule) {
   1.862 +   assert(entry_);
   1.863 + 
   1.864 +   // Is this one of this entry's initial rules?
   1.865 +   if (address == entry_->address)
   1.866 +@@ -228,28 +232,30 @@
   1.867 + 
   1.868 + void DwarfCFIToModule::Reporter::UnnamedRegister(size_t offset, int reg) {
   1.869 +   fprintf(stderr, "%s, section '%s': "
   1.870 +           "the call frame entry at offset 0x%zx refers to register %d,"
   1.871 +           " whose name we don't know\n",
   1.872 +           file_.c_str(), section_.c_str(), offset, reg);
   1.873 + }
   1.874 + 
   1.875 +-void DwarfCFIToModule::Reporter::UndefinedNotSupported(size_t offset,
   1.876 +-                                                       const string &reg) {
   1.877 ++void DwarfCFIToModule::Reporter::UndefinedNotSupported(
   1.878 ++    size_t offset,
   1.879 ++    const UniqueString* reg) {
   1.880 +   fprintf(stderr, "%s, section '%s': "
   1.881 +           "the call frame entry at offset 0x%zx sets the rule for "
   1.882 +           "register '%s' to 'undefined', but the Breakpad symbol file format"
   1.883 +           " cannot express this\n",
   1.884 +-          file_.c_str(), section_.c_str(), offset, reg.c_str());
   1.885 ++          file_.c_str(), section_.c_str(), offset, FromUniqueString(reg));
   1.886 + }
   1.887 + 
   1.888 +-void DwarfCFIToModule::Reporter::ExpressionsNotSupported(size_t offset,
   1.889 +-                                                         const string &reg) {
   1.890 ++void DwarfCFIToModule::Reporter::ExpressionsNotSupported(
   1.891 ++    size_t offset,
   1.892 ++    const UniqueString* reg) {
   1.893 +   fprintf(stderr, "%s, section '%s': "
   1.894 +           "the call frame entry at offset 0x%zx uses a DWARF expression to"
   1.895 +           " describe how to recover register '%s', "
   1.896 +           " but this translator cannot yet translate DWARF expressions to"
   1.897 +           " Breakpad postfix expressions\n",
   1.898 +-          file_.c_str(), section_.c_str(), offset, reg.c_str());
   1.899 ++          file_.c_str(), section_.c_str(), offset, FromUniqueString(reg));
   1.900 + }
   1.901 + 
   1.902 + } // namespace google_breakpad
   1.903 +diff --git a/src/common/dwarf_cfi_to_module.h b/src/common/dwarf_cfi_to_module.h
   1.904 +--- a/src/common/dwarf_cfi_to_module.h
   1.905 ++++ b/src/common/dwarf_cfi_to_module.h
   1.906 +@@ -44,16 +44,17 @@
   1.907 + 
   1.908 + #include <set>
   1.909 + #include <string>
   1.910 + #include <vector>
   1.911 + 
   1.912 + #include "common/module.h"
   1.913 + #include "common/dwarf/dwarf2reader.h"
   1.914 + #include "common/using_std_string.h"
   1.915 ++#include "common/unique_string.h"
   1.916 + 
   1.917 + namespace google_breakpad {
   1.918 + 
   1.919 + using dwarf2reader::CallFrameInfo;
   1.920 + using google_breakpad::Module;
   1.921 + using std::set;
   1.922 + using std::vector;
   1.923 + 
   1.924 +@@ -78,61 +79,65 @@
   1.925 +     // The DWARF CFI entry at OFFSET cites register REG, but REG is not
   1.926 +     // covered by the vector of register names passed to the
   1.927 +     // DwarfCFIToModule constructor, nor does it match the return
   1.928 +     // address column number for this entry.
   1.929 +     virtual void UnnamedRegister(size_t offset, int reg);
   1.930 + 
   1.931 +     // The DWARF CFI entry at OFFSET says that REG is undefined, but the
   1.932 +     // Breakpad symbol file format cannot express this.
   1.933 +-    virtual void UndefinedNotSupported(size_t offset, const string &reg);
   1.934 ++    virtual void UndefinedNotSupported(size_t offset,
   1.935 ++                                       const UniqueString* reg);
   1.936 + 
   1.937 +     // The DWARF CFI entry at OFFSET says that REG uses a DWARF
   1.938 +     // expression to find its value, but DwarfCFIToModule is not
   1.939 +     // capable of translating DWARF expressions to Breakpad postfix
   1.940 +     // expressions.
   1.941 +-    virtual void ExpressionsNotSupported(size_t offset, const string &reg);
   1.942 ++    virtual void ExpressionsNotSupported(size_t offset,
   1.943 ++                                         const UniqueString* reg);
   1.944 + 
   1.945 +   protected:
   1.946 +     string file_, section_;
   1.947 +   };
   1.948 + 
   1.949 +   // Register name tables. If TABLE is a vector returned by one of these
   1.950 +   // functions, then TABLE[R] is the name of the register numbered R in
   1.951 +   // DWARF call frame information.
   1.952 +   class RegisterNames {
   1.953 +    public:
   1.954 +     // Intel's "x86" or IA-32.
   1.955 +-    static vector<string> I386();
   1.956 ++    static vector<const UniqueString*> I386();
   1.957 + 
   1.958 +     // AMD x86_64, AMD64, Intel EM64T, or Intel 64
   1.959 +-    static vector<string> X86_64();
   1.960 ++    static vector<const UniqueString*> X86_64();
   1.961 + 
   1.962 +     // ARM.
   1.963 +-    static vector<string> ARM();
   1.964 ++    static vector<const UniqueString*> ARM();
   1.965 + 
   1.966 +    private:
   1.967 +     // Given STRINGS, an array of C strings with SIZE elements, return an
   1.968 +     // equivalent vector<string>.
   1.969 +-    static vector<string> MakeVector(const char * const *strings, size_t size);
   1.970 ++    static vector<const UniqueString*> MakeVector(const char * const *strings,
   1.971 ++                                                  size_t size);
   1.972 +   };
   1.973 + 
   1.974 +   // Create a handler for the dwarf2reader::CallFrameInfo parser that
   1.975 +   // records the stack unwinding information it receives in MODULE.
   1.976 +   //
   1.977 +   // Use REGISTER_NAMES[I] as the name of register number I; *this
   1.978 +   // keeps a reference to the vector, so the vector should remain
   1.979 +   // alive for as long as the DwarfCFIToModule does.
   1.980 +   //
   1.981 +   // Use REPORTER for reporting problems encountered in the conversion
   1.982 +   // process.
   1.983 +-  DwarfCFIToModule(Module *module, const vector<string> &register_names,
   1.984 ++  DwarfCFIToModule(Module *module,
   1.985 ++                   const vector<const UniqueString*> &register_names,
   1.986 +                    Reporter *reporter)
   1.987 +       : module_(module), register_names_(register_names), reporter_(reporter),
   1.988 +-        entry_(NULL), return_address_(-1), cfa_name_(".cfa"), ra_name_(".ra") {
   1.989 ++        entry_(NULL), return_address_(-1) {
   1.990 +   }
   1.991 +   virtual ~DwarfCFIToModule() { delete entry_; }
   1.992 + 
   1.993 +   virtual bool Entry(size_t offset, uint64 address, uint64 length,
   1.994 +                      uint8 version, const string &augmentation,
   1.995 +                      unsigned return_address);
   1.996 +   virtual bool UndefinedRule(uint64 address, int reg);
   1.997 +   virtual bool SameValueRule(uint64 address, int reg);
   1.998 +@@ -144,53 +149,36 @@
   1.999 +   virtual bool ExpressionRule(uint64 address, int reg,
  1.1000 +                               const string &expression);
  1.1001 +   virtual bool ValExpressionRule(uint64 address, int reg,
  1.1002 +                                  const string &expression);
  1.1003 +   virtual bool End();
  1.1004 + 
  1.1005 +  private:
  1.1006 +   // Return the name to use for register REG.
  1.1007 +-  string RegisterName(int i);
  1.1008 ++  const UniqueString* RegisterName(int i);
  1.1009 + 
  1.1010 +   // Record RULE for register REG at ADDRESS.
  1.1011 +   void Record(Module::Address address, int reg, const Module::Expr &rule);
  1.1012 + 
  1.1013 +   // The module to which we should add entries.
  1.1014 +   Module *module_;
  1.1015 + 
  1.1016 +   // Map from register numbers to register names.
  1.1017 +-  const vector<string> &register_names_;
  1.1018 ++  const vector<const UniqueString*> &register_names_;
  1.1019 + 
  1.1020 +   // The reporter to use to report problems.
  1.1021 +   Reporter *reporter_;
  1.1022 + 
  1.1023 +   // The current entry we're constructing.
  1.1024 +   Module::StackFrameEntry *entry_;
  1.1025 + 
  1.1026 +   // The section offset of the current frame description entry, for
  1.1027 +   // use in error messages.
  1.1028 +   size_t entry_offset_;
  1.1029 + 
  1.1030 +   // The return address column for that entry.
  1.1031 +   unsigned return_address_;
  1.1032 +-
  1.1033 +-  // The names of the return address and canonical frame address. Putting
  1.1034 +-  // these here instead of using string literals allows us to share their
  1.1035 +-  // texts in reference-counted std::string implementations (all the
  1.1036 +-  // popular ones). Many, many rules cite these strings.
  1.1037 +-  string cfa_name_, ra_name_;
  1.1038 +-
  1.1039 +-  // A set of strings used by this CFI. Before storing a string in one of
  1.1040 +-  // our data structures, insert it into this set, and then use the string
  1.1041 +-  // from the set.
  1.1042 +-  // 
  1.1043 +-  // Because std::string uses reference counting internally, simply using
  1.1044 +-  // strings from this set, even if passed by value, assigned, or held
  1.1045 +-  // directly in structures and containers (map<string, ...>, for example),
  1.1046 +-  // causes those strings to share a single instance of each distinct piece
  1.1047 +-  // of text.
  1.1048 +-  set<string> common_strings_;
  1.1049 + };
  1.1050 + 
  1.1051 + } // namespace google_breakpad
  1.1052 + 
  1.1053 + #endif // COMMON_LINUX_DWARF_CFI_TO_MODULE_H
  1.1054 +diff --git a/src/common/dwarf_cfi_to_module_unittest.cc b/src/common/dwarf_cfi_to_module_unittest.cc
  1.1055 +--- a/src/common/dwarf_cfi_to_module_unittest.cc
  1.1056 ++++ b/src/common/dwarf_cfi_to_module_unittest.cc
  1.1057 +@@ -37,52 +37,59 @@
  1.1058 + #include "breakpad_googletest_includes.h"
  1.1059 + #include "common/dwarf_cfi_to_module.h"
  1.1060 + #include "common/using_std_string.h"
  1.1061 + 
  1.1062 + using std::vector;
  1.1063 + 
  1.1064 + using google_breakpad::Module;
  1.1065 + using google_breakpad::DwarfCFIToModule;
  1.1066 ++using google_breakpad::ToUniqueString;
  1.1067 ++using google_breakpad::UniqueString;
  1.1068 ++using google_breakpad::ustr__ZDcfa;
  1.1069 ++using google_breakpad::ustr__ZDra;
  1.1070 ++using google_breakpad::ustr__empty;
  1.1071 + using testing::ContainerEq;
  1.1072 + using testing::Test;
  1.1073 + using testing::_;
  1.1074 + 
  1.1075 + struct MockCFIReporter: public DwarfCFIToModule::Reporter {
  1.1076 +   MockCFIReporter(const string &file, const string &section)
  1.1077 +       : Reporter(file, section) { }
  1.1078 +   MOCK_METHOD2(UnnamedRegister, void(size_t offset, int reg));
  1.1079 +-  MOCK_METHOD2(UndefinedNotSupported, void(size_t offset, const string &reg));
  1.1080 +-  MOCK_METHOD2(ExpressionsNotSupported, void(size_t offset, const string &reg));
  1.1081 ++  MOCK_METHOD2(UndefinedNotSupported, void(size_t offset,
  1.1082 ++                                           const UniqueString* reg));
  1.1083 ++  MOCK_METHOD2(ExpressionsNotSupported, void(size_t offset,
  1.1084 ++                                             const UniqueString* reg));
  1.1085 + };
  1.1086 + 
  1.1087 + struct DwarfCFIToModuleFixture {
  1.1088 +   DwarfCFIToModuleFixture()
  1.1089 +       : module("module name", "module os", "module arch", "module id"),
  1.1090 +         reporter("reporter file", "reporter section"),
  1.1091 +         handler(&module, register_names, &reporter) {
  1.1092 +-    register_names.push_back("reg0");
  1.1093 +-    register_names.push_back("reg1");
  1.1094 +-    register_names.push_back("reg2");
  1.1095 +-    register_names.push_back("reg3");
  1.1096 +-    register_names.push_back("reg4");
  1.1097 +-    register_names.push_back("reg5");
  1.1098 +-    register_names.push_back("reg6");
  1.1099 +-    register_names.push_back("reg7");
  1.1100 +-    register_names.push_back("sp");
  1.1101 +-    register_names.push_back("pc");
  1.1102 +-    register_names.push_back("");
  1.1103 ++    register_names.push_back(ToUniqueString("reg0"));
  1.1104 ++    register_names.push_back(ToUniqueString("reg1"));
  1.1105 ++    register_names.push_back(ToUniqueString("reg2"));
  1.1106 ++    register_names.push_back(ToUniqueString("reg3"));
  1.1107 ++    register_names.push_back(ToUniqueString("reg4"));
  1.1108 ++    register_names.push_back(ToUniqueString("reg5"));
  1.1109 ++    register_names.push_back(ToUniqueString("reg6"));
  1.1110 ++    register_names.push_back(ToUniqueString("reg7"));
  1.1111 ++    register_names.push_back(ToUniqueString("sp"));
  1.1112 ++    register_names.push_back(ToUniqueString("pc"));
  1.1113 ++    register_names.push_back(ustr__empty());
  1.1114 + 
  1.1115 +     EXPECT_CALL(reporter, UnnamedRegister(_, _)).Times(0);
  1.1116 +     EXPECT_CALL(reporter, UndefinedNotSupported(_, _)).Times(0);
  1.1117 +     EXPECT_CALL(reporter, ExpressionsNotSupported(_, _)).Times(0);
  1.1118 +   }
  1.1119 + 
  1.1120 +   Module module;
  1.1121 +-  vector<string> register_names;
  1.1122 ++  vector<const UniqueString*> register_names;
  1.1123 +   MockCFIReporter reporter;
  1.1124 +   DwarfCFIToModule handler;
  1.1125 +   vector<Module::StackFrameEntry *> entries;
  1.1126 + };
  1.1127 + 
  1.1128 + class Entry: public DwarfCFIToModuleFixture, public Test { };
  1.1129 + 
  1.1130 + TEST_F(Entry, Accept) {
  1.1131 +@@ -127,183 +134,190 @@
  1.1132 +   }
  1.1133 +   uint64 entry_address, entry_size;
  1.1134 +   unsigned return_reg;
  1.1135 + };
  1.1136 + 
  1.1137 + class Rule: public RuleFixture, public Test { };
  1.1138 + 
  1.1139 + TEST_F(Rule, UndefinedRule) {
  1.1140 +-  EXPECT_CALL(reporter, UndefinedNotSupported(_, "reg7"));
  1.1141 ++  EXPECT_CALL(reporter, UndefinedNotSupported(_, ToUniqueString("reg7")));
  1.1142 +   StartEntry();
  1.1143 +   ASSERT_TRUE(handler.UndefinedRule(entry_address, 7));
  1.1144 +   ASSERT_TRUE(handler.End());
  1.1145 +   CheckEntry();
  1.1146 +   EXPECT_EQ(0U, entries[0]->initial_rules.size());
  1.1147 +   EXPECT_EQ(0U, entries[0]->rule_changes.size());
  1.1148 + }
  1.1149 + 
  1.1150 + TEST_F(Rule, RegisterWithEmptyName) {
  1.1151 +   EXPECT_CALL(reporter, UnnamedRegister(_, 10));
  1.1152 +-  EXPECT_CALL(reporter, UndefinedNotSupported(_, "unnamed_register10"));
  1.1153 ++  EXPECT_CALL(reporter,
  1.1154 ++              UndefinedNotSupported(_, ToUniqueString("unnamed_register10")));
  1.1155 +   StartEntry();
  1.1156 +   ASSERT_TRUE(handler.UndefinedRule(entry_address, 10));
  1.1157 +   ASSERT_TRUE(handler.End());
  1.1158 +   CheckEntry();
  1.1159 +   EXPECT_EQ(0U, entries[0]->initial_rules.size());
  1.1160 +   EXPECT_EQ(0U, entries[0]->rule_changes.size());
  1.1161 + }
  1.1162 + 
  1.1163 + TEST_F(Rule, SameValueRule) {
  1.1164 +   StartEntry();
  1.1165 +   ASSERT_TRUE(handler.SameValueRule(entry_address, 6));
  1.1166 +   ASSERT_TRUE(handler.End());
  1.1167 +   CheckEntry();
  1.1168 +   Module::RuleMap expected_initial;
  1.1169 +-  expected_initial["reg6"] = Module::Expr("reg6", 0, false);
  1.1170 ++  const UniqueString* reg6 = ToUniqueString("reg6");
  1.1171 ++  expected_initial[reg6] = Module::Expr(reg6, 0, false);
  1.1172 +   EXPECT_THAT(entries[0]->initial_rules, ContainerEq(expected_initial));
  1.1173 +   EXPECT_EQ(0U, entries[0]->rule_changes.size());
  1.1174 + }
  1.1175 + 
  1.1176 + TEST_F(Rule, OffsetRule) {
  1.1177 +   StartEntry();
  1.1178 +   ASSERT_TRUE(handler.OffsetRule(entry_address + 1, return_reg,
  1.1179 +                                  DwarfCFIToModule::kCFARegister,
  1.1180 +                                  16927065));
  1.1181 +   ASSERT_TRUE(handler.End());
  1.1182 +   CheckEntry();
  1.1183 +   EXPECT_EQ(0U, entries[0]->initial_rules.size());
  1.1184 +   Module::RuleChangeMap expected_changes;
  1.1185 +-  expected_changes[entry_address + 1][".ra"] =
  1.1186 +-      Module::Expr(".cfa", 16927065, true);
  1.1187 ++  expected_changes[entry_address + 1][ustr__ZDra()] =
  1.1188 ++      Module::Expr(ustr__ZDcfa(), 16927065, true);
  1.1189 +   EXPECT_THAT(entries[0]->rule_changes, ContainerEq(expected_changes));
  1.1190 + }
  1.1191 + 
  1.1192 + TEST_F(Rule, OffsetRuleNegative) {
  1.1193 +   StartEntry();
  1.1194 +   ASSERT_TRUE(handler.OffsetRule(entry_address + 1,
  1.1195 +                                  DwarfCFIToModule::kCFARegister, 4, -34530721));
  1.1196 +   ASSERT_TRUE(handler.End());
  1.1197 +   CheckEntry();
  1.1198 +   EXPECT_EQ(0U, entries[0]->initial_rules.size());
  1.1199 +   Module::RuleChangeMap expected_changes;
  1.1200 +-  expected_changes[entry_address + 1][".cfa"] =
  1.1201 +-      Module::Expr("reg4", -34530721, true);
  1.1202 ++  expected_changes[entry_address + 1][ustr__ZDcfa()] =
  1.1203 ++      Module::Expr(ToUniqueString("reg4"), -34530721, true);
  1.1204 +   EXPECT_THAT(entries[0]->rule_changes, ContainerEq(expected_changes));
  1.1205 + }
  1.1206 + 
  1.1207 + TEST_F(Rule, ValOffsetRule) {
  1.1208 +   // Use an unnamed register number, to exercise that branch of RegisterName.
  1.1209 +   EXPECT_CALL(reporter, UnnamedRegister(_, 11));
  1.1210 +   StartEntry();
  1.1211 +   ASSERT_TRUE(handler.ValOffsetRule(entry_address + 0x5ab7,
  1.1212 +                                     DwarfCFIToModule::kCFARegister,
  1.1213 +                                     11, 61812979));
  1.1214 +   ASSERT_TRUE(handler.End());
  1.1215 +   CheckEntry();
  1.1216 +   EXPECT_EQ(0U, entries[0]->initial_rules.size());
  1.1217 +   Module::RuleChangeMap expected_changes;
  1.1218 +-  expected_changes[entry_address + 0x5ab7][".cfa"] =
  1.1219 +-      Module::Expr("unnamed_register11", 61812979, false);
  1.1220 ++  expected_changes[entry_address + 0x5ab7][ustr__ZDcfa()] =
  1.1221 ++      Module::Expr(ToUniqueString("unnamed_register11"), 61812979, false);
  1.1222 +   EXPECT_THAT(entries[0]->rule_changes, ContainerEq(expected_changes));
  1.1223 + }
  1.1224 + 
  1.1225 + TEST_F(Rule, RegisterRule) {
  1.1226 +   StartEntry();
  1.1227 +   ASSERT_TRUE(handler.RegisterRule(entry_address, return_reg, 3));
  1.1228 +   ASSERT_TRUE(handler.End());
  1.1229 +   CheckEntry();
  1.1230 +   Module::RuleMap expected_initial;
  1.1231 +-  expected_initial[".ra"] = Module::Expr("reg3", 0, false);
  1.1232 ++  expected_initial[ustr__ZDra()] =
  1.1233 ++      Module::Expr(ToUniqueString("reg3"), 0, false);
  1.1234 +   EXPECT_THAT(entries[0]->initial_rules, ContainerEq(expected_initial));
  1.1235 +   EXPECT_EQ(0U, entries[0]->rule_changes.size());
  1.1236 + }
  1.1237 + 
  1.1238 + TEST_F(Rule, ExpressionRule) {
  1.1239 +-  EXPECT_CALL(reporter, ExpressionsNotSupported(_, "reg2"));
  1.1240 ++  EXPECT_CALL(reporter, ExpressionsNotSupported(_, ToUniqueString("reg2")));
  1.1241 +   StartEntry();
  1.1242 +   ASSERT_TRUE(handler.ExpressionRule(entry_address + 0xf326, 2,
  1.1243 +                                      "it takes two to tango"));
  1.1244 +   ASSERT_TRUE(handler.End());
  1.1245 +   CheckEntry();
  1.1246 +   EXPECT_EQ(0U, entries[0]->initial_rules.size());
  1.1247 +   EXPECT_EQ(0U, entries[0]->rule_changes.size());
  1.1248 + }
  1.1249 + 
  1.1250 + TEST_F(Rule, ValExpressionRule) {
  1.1251 +-  EXPECT_CALL(reporter, ExpressionsNotSupported(_, "reg0"));
  1.1252 ++  EXPECT_CALL(reporter, ExpressionsNotSupported(_, ToUniqueString("reg0")));
  1.1253 +   StartEntry();
  1.1254 +   ASSERT_TRUE(handler.ValExpressionRule(entry_address + 0x6367, 0,
  1.1255 +                                         "bit off more than he could chew"));
  1.1256 +   ASSERT_TRUE(handler.End());
  1.1257 +   CheckEntry();
  1.1258 +   EXPECT_EQ(0U, entries[0]->initial_rules.size());
  1.1259 +   EXPECT_EQ(0U, entries[0]->rule_changes.size());
  1.1260 + }
  1.1261 + 
  1.1262 + TEST_F(Rule, DefaultReturnAddressRule) {
  1.1263 +   return_reg = 2;
  1.1264 +   StartEntry();
  1.1265 +   ASSERT_TRUE(handler.RegisterRule(entry_address, 0, 1));
  1.1266 +   ASSERT_TRUE(handler.End());
  1.1267 +   CheckEntry();
  1.1268 +   Module::RuleMap expected_initial;
  1.1269 +-  expected_initial[".ra"] = Module::Expr("reg2", 0, false);
  1.1270 +-  expected_initial["reg0"] = Module::Expr("reg1", 0, false);
  1.1271 ++  expected_initial[ustr__ZDra()] =
  1.1272 ++      Module::Expr(ToUniqueString("reg2"), 0, false);
  1.1273 ++  expected_initial[ToUniqueString("reg0")] =
  1.1274 ++      Module::Expr(ToUniqueString("reg1"), 0, false);
  1.1275 +   EXPECT_THAT(entries[0]->initial_rules, ContainerEq(expected_initial));
  1.1276 +   EXPECT_EQ(0U, entries[0]->rule_changes.size());
  1.1277 + }
  1.1278 + 
  1.1279 + TEST_F(Rule, DefaultReturnAddressRuleOverride) {
  1.1280 +   return_reg = 2;
  1.1281 +   StartEntry();
  1.1282 +   ASSERT_TRUE(handler.RegisterRule(entry_address, return_reg, 1));
  1.1283 +   ASSERT_TRUE(handler.End());
  1.1284 +   CheckEntry();
  1.1285 +   Module::RuleMap expected_initial;
  1.1286 +-  expected_initial[".ra"] = Module::Expr("reg1", 0, false);
  1.1287 ++  expected_initial[ustr__ZDra()] =
  1.1288 ++      Module::Expr(ToUniqueString("reg1"), 0, false);
  1.1289 +   EXPECT_THAT(entries[0]->initial_rules, ContainerEq(expected_initial));
  1.1290 +   EXPECT_EQ(0U, entries[0]->rule_changes.size());
  1.1291 + }
  1.1292 + 
  1.1293 + TEST_F(Rule, DefaultReturnAddressRuleLater) {
  1.1294 +   return_reg = 2;
  1.1295 +   StartEntry();
  1.1296 +   ASSERT_TRUE(handler.RegisterRule(entry_address + 1, return_reg, 1));
  1.1297 +   ASSERT_TRUE(handler.End());
  1.1298 +   CheckEntry();
  1.1299 +   Module::RuleMap expected_initial;
  1.1300 +-  expected_initial[".ra"] = Module::Expr("reg2", 0, false);
  1.1301 ++  expected_initial[ustr__ZDra()] =
  1.1302 ++      Module::Expr(ToUniqueString("reg2"), 0, false);
  1.1303 +   EXPECT_THAT(entries[0]->initial_rules, ContainerEq(expected_initial));
  1.1304 +   Module::RuleChangeMap expected_changes;
  1.1305 +-  expected_changes[entry_address + 1][".ra"] =
  1.1306 +-      Module::Expr("reg1", 0, false);
  1.1307 ++  expected_changes[entry_address + 1][ustr__ZDra()] =
  1.1308 ++      Module::Expr(ToUniqueString("reg1"), 0, false);
  1.1309 +   EXPECT_THAT(entries[0]->rule_changes, ContainerEq(expected_changes));
  1.1310 + }
  1.1311 + 
  1.1312 + TEST(RegisterNames, I386) {
  1.1313 +-  vector<string> names = DwarfCFIToModule::RegisterNames::I386();
  1.1314 ++  vector<const UniqueString*> names = DwarfCFIToModule::RegisterNames::I386();
  1.1315 + 
  1.1316 +-  EXPECT_EQ("$eax", names[0]);
  1.1317 +-  EXPECT_EQ("$ecx", names[1]);
  1.1318 +-  EXPECT_EQ("$esp", names[4]);
  1.1319 +-  EXPECT_EQ("$eip", names[8]);
  1.1320 ++  EXPECT_EQ(ToUniqueString("$eax"), names[0]);
  1.1321 ++  EXPECT_EQ(ToUniqueString("$ecx"), names[1]);
  1.1322 ++  EXPECT_EQ(ToUniqueString("$esp"), names[4]);
  1.1323 ++  EXPECT_EQ(ToUniqueString("$eip"), names[8]);
  1.1324 + }
  1.1325 + 
  1.1326 + TEST(RegisterNames, ARM) {
  1.1327 +-  vector<string> names = DwarfCFIToModule::RegisterNames::ARM();
  1.1328 ++  vector<const UniqueString*> names = DwarfCFIToModule::RegisterNames::ARM();
  1.1329 + 
  1.1330 +-  EXPECT_EQ("r0", names[0]);
  1.1331 +-  EXPECT_EQ("r10", names[10]);
  1.1332 +-  EXPECT_EQ("sp", names[13]);
  1.1333 +-  EXPECT_EQ("lr", names[14]);
  1.1334 +-  EXPECT_EQ("pc", names[15]);
  1.1335 ++  EXPECT_EQ(ToUniqueString("r0"), names[0]);
  1.1336 ++  EXPECT_EQ(ToUniqueString("r10"), names[10]);
  1.1337 ++  EXPECT_EQ(ToUniqueString("sp"), names[13]);
  1.1338 ++  EXPECT_EQ(ToUniqueString("lr"), names[14]);
  1.1339 ++  EXPECT_EQ(ToUniqueString("pc"), names[15]);
  1.1340 + }
  1.1341 + 
  1.1342 + TEST(RegisterNames, X86_64) {
  1.1343 +-  vector<string> names = DwarfCFIToModule::RegisterNames::X86_64();
  1.1344 ++  vector<const UniqueString*> names = DwarfCFIToModule::RegisterNames::X86_64();
  1.1345 + 
  1.1346 +-  EXPECT_EQ("$rax", names[0]);
  1.1347 +-  EXPECT_EQ("$rdx", names[1]);
  1.1348 +-  EXPECT_EQ("$rbp", names[6]);
  1.1349 +-  EXPECT_EQ("$rsp", names[7]);
  1.1350 +-  EXPECT_EQ("$rip", names[16]);
  1.1351 ++  EXPECT_EQ(ToUniqueString("$rax"), names[0]);
  1.1352 ++  EXPECT_EQ(ToUniqueString("$rdx"), names[1]);
  1.1353 ++  EXPECT_EQ(ToUniqueString("$rbp"), names[6]);
  1.1354 ++  EXPECT_EQ(ToUniqueString("$rsp"), names[7]);
  1.1355 ++  EXPECT_EQ(ToUniqueString("$rip"), names[16]);
  1.1356 + }
  1.1357 +diff --git a/src/common/linux/dump_symbols.cc b/src/common/linux/dump_symbols.cc
  1.1358 +--- a/src/common/linux/dump_symbols.cc
  1.1359 ++++ b/src/common/linux/dump_symbols.cc
  1.1360 +@@ -81,16 +81,17 @@
  1.1361 + using google_breakpad::ElfClass64;
  1.1362 + using google_breakpad::FindElfSectionByName;
  1.1363 + using google_breakpad::GetOffset;
  1.1364 + using google_breakpad::IsValidElf;
  1.1365 + using google_breakpad::Module;
  1.1366 + #ifndef NO_STABS_SUPPORT
  1.1367 + using google_breakpad::StabsToModule;
  1.1368 + #endif
  1.1369 ++using google_breakpad::UniqueString;
  1.1370 + using google_breakpad::scoped_ptr;
  1.1371 + 
  1.1372 + //
  1.1373 + // FDWrapper
  1.1374 + //
  1.1375 + // Wrapper class to make sure opened file is closed.
  1.1376 + //
  1.1377 + class FDWrapper {
  1.1378 +@@ -278,17 +279,17 @@
  1.1379 + 
  1.1380 + // Fill REGISTER_NAMES with the register names appropriate to the
  1.1381 + // machine architecture given in HEADER, indexed by the register
  1.1382 + // numbers used in DWARF call frame information. Return true on
  1.1383 + // success, or false if HEADER's machine architecture is not
  1.1384 + // supported.
  1.1385 + template<typename ElfClass>
  1.1386 + bool DwarfCFIRegisterNames(const typename ElfClass::Ehdr* elf_header,
  1.1387 +-                           std::vector<string>* register_names) {
  1.1388 ++                           std::vector<const UniqueString*>* register_names) {
  1.1389 +   switch (elf_header->e_machine) {
  1.1390 +     case EM_386:
  1.1391 +       *register_names = DwarfCFIToModule::RegisterNames::I386();
  1.1392 +       return true;
  1.1393 +     case EM_ARM:
  1.1394 +       *register_names = DwarfCFIToModule::RegisterNames::ARM();
  1.1395 +       return true;
  1.1396 +     case EM_X86_64:
  1.1397 +@@ -306,17 +307,17 @@
  1.1398 +                   const typename ElfClass::Shdr* section,
  1.1399 +                   const bool eh_frame,
  1.1400 +                   const typename ElfClass::Shdr* got_section,
  1.1401 +                   const typename ElfClass::Shdr* text_section,
  1.1402 +                   const bool big_endian,
  1.1403 +                   Module* module) {
  1.1404 +   // Find the appropriate set of register names for this file's
  1.1405 +   // architecture.
  1.1406 +-  std::vector<string> register_names;
  1.1407 ++  std::vector<const UniqueString*> register_names;
  1.1408 +   if (!DwarfCFIRegisterNames<ElfClass>(elf_header, &register_names)) {
  1.1409 +     fprintf(stderr, "%s: unrecognized ELF machine architecture '%d';"
  1.1410 +             " cannot convert DWARF call frame information\n",
  1.1411 +             dwarf_filename.c_str(), elf_header->e_machine);
  1.1412 +     return false;
  1.1413 +   }
  1.1414 + 
  1.1415 +   const dwarf2reader::Endianness endianness = big_endian ?
  1.1416 +diff --git a/src/common/mac/dump_syms.mm b/src/common/mac/dump_syms.mm
  1.1417 +--- a/src/common/mac/dump_syms.mm
  1.1418 ++++ b/src/common/mac/dump_syms.mm
  1.1419 +@@ -313,17 +313,17 @@
  1.1420 + }
  1.1421 + 
  1.1422 + bool DumpSymbols::ReadCFI(google_breakpad::Module *module,
  1.1423 +                           const mach_o::Reader &macho_reader,
  1.1424 +                           const mach_o::Section &section,
  1.1425 +                           bool eh_frame) const {
  1.1426 +   // Find the appropriate set of register names for this file's
  1.1427 +   // architecture.
  1.1428 +-  vector<string> register_names;
  1.1429 ++  vector<const UniqueString*> register_names;
  1.1430 +   switch (macho_reader.cpu_type()) {
  1.1431 +     case CPU_TYPE_X86:
  1.1432 +       register_names = DwarfCFIToModule::RegisterNames::I386();
  1.1433 +       break;
  1.1434 +     case CPU_TYPE_X86_64:
  1.1435 +       register_names = DwarfCFIToModule::RegisterNames::X86_64();
  1.1436 +       break;
  1.1437 +     case CPU_TYPE_ARM:
  1.1438 +diff --git a/src/common/module.cc b/src/common/module.cc
  1.1439 +--- a/src/common/module.cc
  1.1440 ++++ b/src/common/module.cc
  1.1441 +@@ -33,16 +33,17 @@
  1.1442 + 
  1.1443 + #include "common/module.h"
  1.1444 + 
  1.1445 + #include <assert.h>
  1.1446 + #include <errno.h>
  1.1447 + #include <stdio.h>
  1.1448 + #include <string.h>
  1.1449 + 
  1.1450 ++#include <algorithm>
  1.1451 + #include <iostream>
  1.1452 + #include <utility>
  1.1453 + 
  1.1454 + namespace google_breakpad {
  1.1455 + 
  1.1456 + using std::dec;
  1.1457 + using std::endl;
  1.1458 + using std::hex;
  1.1459 +@@ -255,36 +256,50 @@
  1.1460 +           strerror(errno));
  1.1461 +   return false;
  1.1462 + }
  1.1463 + 
  1.1464 + std::ostream& operator<<(std::ostream& stream, const Module::Expr& expr) {
  1.1465 +   assert(!expr.invalid());
  1.1466 +   switch (expr.how_) {
  1.1467 +     case Module::kExprSimple:
  1.1468 +-      stream << expr.ident_ << " " << expr.offset_ << " +";
  1.1469 ++      stream << FromUniqueString(expr.ident_) << " " << expr.offset_ << " +";
  1.1470 +       break;
  1.1471 +     case Module::kExprSimpleMem:
  1.1472 +-      stream << expr.ident_ << " " << expr.offset_ << " + ^";
  1.1473 ++      stream << FromUniqueString(expr.ident_) << " " << expr.offset_ << " + ^";
  1.1474 +       break;
  1.1475 +     case Module::kExprPostfix:
  1.1476 +       stream << expr.postfix_; break;
  1.1477 +     case Module::kExprInvalid:
  1.1478 +     default:
  1.1479 +       break;
  1.1480 +   }
  1.1481 +   return stream;
  1.1482 + }
  1.1483 + 
  1.1484 + bool Module::WriteRuleMap(const RuleMap &rule_map, std::ostream &stream) {
  1.1485 ++  // Visit the register rules in alphabetical order.  Because
  1.1486 ++  // rule_map has the elements in some arbitrary order,
  1.1487 ++  // get the names out into a vector, sort them, and visit in
  1.1488 ++  // sorted order.
  1.1489 ++  std::vector<const UniqueString*> rr_names;
  1.1490 +   for (RuleMap::const_iterator it = rule_map.begin();
  1.1491 +        it != rule_map.end(); ++it) {
  1.1492 +-    if (it != rule_map.begin())
  1.1493 +-      stream << ' ';
  1.1494 +-    stream << it->first << ": " << it->second;
  1.1495 ++    rr_names.push_back(it->first);
  1.1496 ++  }
  1.1497 ++
  1.1498 ++  std::sort(rr_names.begin(), rr_names.end(), LessThan_UniqueString);
  1.1499 ++
  1.1500 ++  // Now visit the register rules in alphabetical order.
  1.1501 ++  for (std::vector<const UniqueString*>::const_iterator name = rr_names.begin();
  1.1502 ++       name != rr_names.end();
  1.1503 ++       ++name) {
  1.1504 ++    if (name != rr_names.begin())
  1.1505 ++      stream << " ";
  1.1506 ++    stream << FromUniqueString(*name) << ": " << rule_map.find(*name)->second;
  1.1507 +   }
  1.1508 +   return stream.good();
  1.1509 + }
  1.1510 + 
  1.1511 + bool Module::Write(std::ostream &stream, SymbolData symbol_data) {
  1.1512 +   stream << "MODULE " << os_ << " " << architecture_ << " "
  1.1513 +          << id_ << " " << name_ << endl;
  1.1514 +   if (!stream.good())
  1.1515 +diff --git a/src/common/module.h b/src/common/module.h
  1.1516 +--- a/src/common/module.h
  1.1517 ++++ b/src/common/module.h
  1.1518 +@@ -41,16 +41,17 @@
  1.1519 + #include <iostream>
  1.1520 + #include <map>
  1.1521 + #include <set>
  1.1522 + #include <string>
  1.1523 + #include <vector>
  1.1524 + 
  1.1525 + #include "common/symbol_data.h"
  1.1526 + #include "common/using_std_string.h"
  1.1527 ++#include "common/unique_string.h"
  1.1528 + #include "google_breakpad/common/breakpad_types.h"
  1.1529 + 
  1.1530 + namespace google_breakpad {
  1.1531 + 
  1.1532 + using std::set;
  1.1533 + using std::vector;
  1.1534 + using std::map;
  1.1535 + 
  1.1536 +@@ -131,69 +132,69 @@
  1.1537 +   enum ExprHow {
  1.1538 +     kExprInvalid = 1,
  1.1539 +     kExprPostfix,
  1.1540 +     kExprSimple,
  1.1541 +     kExprSimpleMem
  1.1542 +   };
  1.1543 +   struct Expr {
  1.1544 +     // Construct a simple-form expression
  1.1545 +-    Expr(string ident, long offset, bool deref) {
  1.1546 +-      if (ident.empty()) {
  1.1547 ++    Expr(const UniqueString* ident, long offset, bool deref) {
  1.1548 ++      if (ident == ustr__empty()) {
  1.1549 +         Expr();
  1.1550 +       } else {
  1.1551 +         postfix_ = "";
  1.1552 +         ident_ = ident;
  1.1553 +         offset_ = offset;
  1.1554 +         how_ = deref ? kExprSimpleMem : kExprSimple;
  1.1555 +       }
  1.1556 +     }
  1.1557 +     // Construct an expression from a postfix string
  1.1558 +     Expr(string postfix) {
  1.1559 +       if (postfix.empty()) {
  1.1560 +         Expr();
  1.1561 +       } else {
  1.1562 +         postfix_ = postfix;
  1.1563 +-        ident_ = "";
  1.1564 ++        ident_ = NULL;
  1.1565 +         offset_ = 0;
  1.1566 +         how_ = kExprPostfix;
  1.1567 +       }
  1.1568 +     }
  1.1569 +     // Construct an invalid expression
  1.1570 +     Expr() {
  1.1571 +       postfix_ = "";
  1.1572 +-      ident_ = "";
  1.1573 ++      ident_ = NULL;
  1.1574 +       offset_ = 0;
  1.1575 +       how_ = kExprInvalid;
  1.1576 +     }
  1.1577 +     bool invalid() const { return how_ == kExprInvalid; }
  1.1578 +     bool operator==(const Expr& other) const {
  1.1579 +       return how_ == other.how_ &&
  1.1580 +           ident_ == other.ident_ &&
  1.1581 +           offset_ == other.offset_ &&
  1.1582 +           postfix_ == other.postfix_;
  1.1583 +     }
  1.1584 + 
  1.1585 +     // The identifier that gives the starting value for simple expressions.
  1.1586 +-    string  ident_;
  1.1587 ++    const UniqueString* ident_;
  1.1588 +     // The offset to add for simple expressions.
  1.1589 +     long    offset_;
  1.1590 +     // The Postfix expression string to evaluate for non-simple expressions.
  1.1591 +     string  postfix_;
  1.1592 +     // The operation expressed by this expression.
  1.1593 +     ExprHow how_;
  1.1594 + 
  1.1595 +     friend std::ostream& operator<<(std::ostream& stream, const Expr& expr);
  1.1596 +   };
  1.1597 + 
  1.1598 +   // A map from register names to expressions that recover
  1.1599 +   // their values. This can represent a complete set of rules to
  1.1600 +   // follow at some address, or a set of changes to be applied to an
  1.1601 +   // extant set of rules.
  1.1602 +-  typedef map<string, Expr> RuleMap;
  1.1603 ++  typedef map<const UniqueString*, Expr> RuleMap;
  1.1604 + 
  1.1605 +   // A map from addresses to RuleMaps, representing changes that take
  1.1606 +   // effect at given addresses.
  1.1607 +   typedef map<Address, RuleMap> RuleChangeMap;
  1.1608 + 
  1.1609 +   // A range of 'STACK CFI' stack walking information. An instance of
  1.1610 +   // this structure corresponds to a 'STACK CFI INIT' record and the
  1.1611 +   // subsequent 'STACK CFI' records that fall within its range.
  1.1612 +diff --git a/src/common/module_unittest.cc b/src/common/module_unittest.cc
  1.1613 +--- a/src/common/module_unittest.cc
  1.1614 ++++ b/src/common/module_unittest.cc
  1.1615 +@@ -40,16 +40,18 @@
  1.1616 + #include <sstream>
  1.1617 + #include <string>
  1.1618 + 
  1.1619 + #include "breakpad_googletest_includes.h"
  1.1620 + #include "common/module.h"
  1.1621 + #include "common/using_std_string.h"
  1.1622 + 
  1.1623 + using google_breakpad::Module;
  1.1624 ++using google_breakpad::ToUniqueString;
  1.1625 ++using google_breakpad::ustr__ZDcfa;
  1.1626 + using std::stringstream;
  1.1627 + using std::vector;
  1.1628 + using testing::ContainerEq;
  1.1629 + 
  1.1630 + static Module::Function *generate_duplicate_function(const string &name) {
  1.1631 +   const Module::Address DUP_ADDRESS = 0xd35402aac7a7ad5cLL;
  1.1632 +   const Module::Address DUP_SIZE = 0x200b26e605f99071LL;
  1.1633 +   const Module::Address DUP_PARAMETER_SIZE = 0xf14ac4fed48c4a99LL;
  1.1634 +@@ -125,21 +127,27 @@
  1.1635 +   function->lines.push_back(line1);
  1.1636 + 
  1.1637 +   m.AddFunction(function);
  1.1638 + 
  1.1639 +   // Some stack information.
  1.1640 +   Module::StackFrameEntry *entry = new Module::StackFrameEntry();
  1.1641 +   entry->address = 0x30f9e5c83323973dULL;
  1.1642 +   entry->size = 0x49fc9ca7c7c13dc2ULL;
  1.1643 +-  entry->initial_rules[".cfa"] = Module::Expr("he was a handsome man");
  1.1644 +-  entry->initial_rules["and"] = Module::Expr("what i want to know is");
  1.1645 +-  entry->rule_changes[0x30f9e5c83323973eULL]["how"] =
  1.1646 +-    Module::Expr("do you like your blueeyed boy");
  1.1647 +-  entry->rule_changes[0x30f9e5c83323973eULL]["Mister"] = Module::Expr("Death");
  1.1648 ++  entry->initial_rules[ustr__ZDcfa()] = Module::Expr("he was a handsome man");
  1.1649 ++  entry->initial_rules[ToUniqueString("and")] =
  1.1650 ++      Module::Expr("what i want to know is");
  1.1651 ++  entry->initial_rules[ToUniqueString("stallion")] =
  1.1652 ++      Module::Expr(ToUniqueString("and break"), 8, false);
  1.1653 ++  entry->initial_rules[ToUniqueString("onetwothreefourfive")] =
  1.1654 ++      Module::Expr(ToUniqueString("pigeonsjustlikethat"), 42, true);
  1.1655 ++  entry->rule_changes[0x30f9e5c83323973eULL][ToUniqueString("how")] =
  1.1656 ++      Module::Expr("do you like your blueeyed boy");
  1.1657 ++  entry->rule_changes[0x30f9e5c83323973eULL][ToUniqueString("Mister")] =
  1.1658 ++      Module::Expr("Death");
  1.1659 +   m.AddStackFrameEntry(entry);
  1.1660 + 
  1.1661 +   // Set the load address.  Doing this after adding all the data to
  1.1662 +   // the module must work fine.
  1.1663 +   m.SetLoadAddress(0x2ab698b0b6407073LL);
  1.1664 + 
  1.1665 +   m.Write(s, ALL_SYMBOL_DATA);
  1.1666 +   string contents = s.str();
  1.1667 +@@ -147,17 +155,19 @@
  1.1668 +                "FILE 0 filename-a.cc\n"
  1.1669 +                "FILE 1 filename-b.cc\n"
  1.1670 +                "FUNC 9410dc39a798c580 2922088f98d3f6fc e5e9aa008bd5f0d0"
  1.1671 +                " A_FLIBBERTIJIBBET::a_will_o_the_wisp(a clown)\n"
  1.1672 +                "b03cc3106d47eb91 cf621b8d324d0eb 67519080 0\n"
  1.1673 +                "9410dc39a798c580 1c2be6d6c5af2611 41676901 1\n"
  1.1674 +                "STACK CFI INIT 6434d177ce326ca 49fc9ca7c7c13dc2"
  1.1675 +                " .cfa: he was a handsome man"
  1.1676 +-               " and: what i want to know is\n"
  1.1677 ++               " and: what i want to know is"
  1.1678 ++               " onetwothreefourfive: pigeonsjustlikethat 42 + ^"
  1.1679 ++               " stallion: and break 8 +\n"
  1.1680 +                "STACK CFI 6434d177ce326cb"
  1.1681 +                " Mister: Death"
  1.1682 +                " how: do you like your blueeyed boy\n",
  1.1683 +                contents.c_str());
  1.1684 + }
  1.1685 + 
  1.1686 + TEST(Write, OmitUnusedFiles) {
  1.1687 +   Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID);
  1.1688 +@@ -229,21 +239,23 @@
  1.1689 +   function->lines.push_back(line1);
  1.1690 + 
  1.1691 +   m.AddFunction(function);
  1.1692 + 
  1.1693 +   // Some stack information.
  1.1694 +   Module::StackFrameEntry *entry = new Module::StackFrameEntry();
  1.1695 +   entry->address = 0x30f9e5c83323973dULL;
  1.1696 +   entry->size = 0x49fc9ca7c7c13dc2ULL;
  1.1697 +-  entry->initial_rules[".cfa"] = Module::Expr("he was a handsome man");
  1.1698 +-  entry->initial_rules["and"] = Module::Expr("what i want to know is");
  1.1699 +-  entry->rule_changes[0x30f9e5c83323973eULL]["how"] =
  1.1700 +-    Module::Expr("do you like your blueeyed boy");
  1.1701 +-  entry->rule_changes[0x30f9e5c83323973eULL]["Mister"] = Module::Expr("Death");
  1.1702 ++  entry->initial_rules[ustr__ZDcfa()] = Module::Expr("he was a handsome man");
  1.1703 ++  entry->initial_rules[ToUniqueString("and")] =
  1.1704 ++      Module::Expr("what i want to know is");
  1.1705 ++  entry->rule_changes[0x30f9e5c83323973eULL][ToUniqueString("how")] =
  1.1706 ++      Module::Expr("do you like your blueeyed boy");
  1.1707 ++  entry->rule_changes[0x30f9e5c83323973eULL][ToUniqueString("Mister")] =
  1.1708 ++      Module::Expr("Death");
  1.1709 +   m.AddStackFrameEntry(entry);
  1.1710 + 
  1.1711 +   // Set the load address.  Doing this after adding all the data to
  1.1712 +   // the module must work fine.
  1.1713 +   m.SetLoadAddress(0x2ab698b0b6407073LL);
  1.1714 + 
  1.1715 +   m.Write(s, NO_CFI);
  1.1716 +   string contents = s.str();
  1.1717 +@@ -305,33 +317,36 @@
  1.1718 +   entry1->address = 0xddb5f41285aa7757ULL;
  1.1719 +   entry1->size = 0x1486493370dc5073ULL;
  1.1720 +   m.AddStackFrameEntry(entry1);
  1.1721 + 
  1.1722 +   // Second STACK CFI entry, with initial rules but no deltas.
  1.1723 +   Module::StackFrameEntry *entry2 = new Module::StackFrameEntry();
  1.1724 +   entry2->address = 0x8064f3af5e067e38ULL;
  1.1725 +   entry2->size = 0x0de2a5ee55509407ULL;
  1.1726 +-  entry2->initial_rules[".cfa"] = Module::Expr("I think that I shall never see");
  1.1727 +-  entry2->initial_rules["stromboli"] = Module::Expr("a poem lovely as a tree");
  1.1728 +-  entry2->initial_rules["cannoli"] = Module::Expr("a tree whose hungry mouth is prest");
  1.1729 ++  entry2->initial_rules[ustr__ZDcfa()] =
  1.1730 ++      Module::Expr("I think that I shall never see");
  1.1731 ++  entry2->initial_rules[ToUniqueString("stromboli")] =
  1.1732 ++      Module::Expr("a poem lovely as a tree");
  1.1733 ++  entry2->initial_rules[ToUniqueString("cannoli")] =
  1.1734 ++      Module::Expr("a tree whose hungry mouth is prest");
  1.1735 +   m.AddStackFrameEntry(entry2);
  1.1736 + 
  1.1737 +   // Third STACK CFI entry, with initial rules and deltas.
  1.1738 +   Module::StackFrameEntry *entry3 = new Module::StackFrameEntry();
  1.1739 +   entry3->address = 0x5e8d0db0a7075c6cULL;
  1.1740 +   entry3->size = 0x1c7edb12a7aea229ULL;
  1.1741 +-  entry3->initial_rules[".cfa"] = Module::Expr("Whose woods are these");
  1.1742 +-  entry3->rule_changes[0x47ceb0f63c269d7fULL]["calzone"] =
  1.1743 ++  entry3->initial_rules[ustr__ZDcfa()] = Module::Expr("Whose woods are these");
  1.1744 ++  entry3->rule_changes[0x47ceb0f63c269d7fULL][ToUniqueString("calzone")] =
  1.1745 +     Module::Expr("the village though");
  1.1746 +-  entry3->rule_changes[0x47ceb0f63c269d7fULL]["cannoli"] =
  1.1747 ++  entry3->rule_changes[0x47ceb0f63c269d7fULL][ToUniqueString("cannoli")] =
  1.1748 +     Module::Expr("he will not see me stopping here");
  1.1749 +-  entry3->rule_changes[0x36682fad3763ffffULL]["stromboli"] =
  1.1750 ++  entry3->rule_changes[0x36682fad3763ffffULL][ToUniqueString("stromboli")] =
  1.1751 +     Module::Expr("his house is in");
  1.1752 +-  entry3->rule_changes[0x36682fad3763ffffULL][".cfa"] =
  1.1753 ++  entry3->rule_changes[0x36682fad3763ffffULL][ustr__ZDcfa()] =
  1.1754 +     Module::Expr("I think I know");
  1.1755 +   m.AddStackFrameEntry(entry3);
  1.1756 + 
  1.1757 +   // Check that Write writes STACK CFI records properly.
  1.1758 +   m.Write(s, ALL_SYMBOL_DATA);
  1.1759 +   string contents = s.str();
  1.1760 +   EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n"
  1.1761 +                "STACK CFI INIT 5e8d0db0a7075c6c 1c7edb12a7aea229"
  1.1762 +@@ -352,33 +367,39 @@
  1.1763 +   // Check that GetStackFrameEntries works.
  1.1764 +   vector<Module::StackFrameEntry *> entries;
  1.1765 +   m.GetStackFrameEntries(&entries);
  1.1766 +   ASSERT_EQ(3U, entries.size());
  1.1767 +   // Check first entry.
  1.1768 +   EXPECT_EQ(0x5e8d0db0a7075c6cULL, entries[0]->address);
  1.1769 +   EXPECT_EQ(0x1c7edb12a7aea229ULL, entries[0]->size);
  1.1770 +   Module::RuleMap entry1_initial;
  1.1771 +-  entry1_initial[".cfa"] = Module::Expr("Whose woods are these");
  1.1772 ++  entry1_initial[ustr__ZDcfa()] = Module::Expr("Whose woods are these");
  1.1773 +   EXPECT_THAT(entries[0]->initial_rules, ContainerEq(entry1_initial));
  1.1774 +   Module::RuleChangeMap entry1_changes;
  1.1775 +-  entry1_changes[0x36682fad3763ffffULL][".cfa"] = Module::Expr("I think I know");
  1.1776 +-  entry1_changes[0x36682fad3763ffffULL]["stromboli"] = Module::Expr("his house is in");
  1.1777 +-  entry1_changes[0x47ceb0f63c269d7fULL]["calzone"] = Module::Expr("the village though");
  1.1778 +-  entry1_changes[0x47ceb0f63c269d7fULL]["cannoli"] =
  1.1779 +-    Module::Expr("he will not see me stopping here");
  1.1780 ++  entry1_changes[0x36682fad3763ffffULL][ustr__ZDcfa()] =
  1.1781 ++      Module::Expr("I think I know");
  1.1782 ++  entry1_changes[0x36682fad3763ffffULL][ToUniqueString("stromboli")] =
  1.1783 ++      Module::Expr("his house is in");
  1.1784 ++  entry1_changes[0x47ceb0f63c269d7fULL][ToUniqueString("calzone")] =
  1.1785 ++      Module::Expr("the village though");
  1.1786 ++  entry1_changes[0x47ceb0f63c269d7fULL][ToUniqueString("cannoli")] =
  1.1787 ++      Module::Expr("he will not see me stopping here");
  1.1788 +   EXPECT_THAT(entries[0]->rule_changes, ContainerEq(entry1_changes));
  1.1789 +   // Check second entry.
  1.1790 +   EXPECT_EQ(0x8064f3af5e067e38ULL, entries[1]->address);
  1.1791 +   EXPECT_EQ(0x0de2a5ee55509407ULL, entries[1]->size);
  1.1792 +   ASSERT_EQ(3U, entries[1]->initial_rules.size());
  1.1793 +   Module::RuleMap entry2_initial;
  1.1794 +-  entry2_initial[".cfa"] = Module::Expr("I think that I shall never see");
  1.1795 +-  entry2_initial["stromboli"] = Module::Expr("a poem lovely as a tree");
  1.1796 +-  entry2_initial["cannoli"] = Module::Expr("a tree whose hungry mouth is prest");
  1.1797 ++  entry2_initial[ustr__ZDcfa()] =
  1.1798 ++      Module::Expr("I think that I shall never see");
  1.1799 ++  entry2_initial[ToUniqueString("stromboli")] =
  1.1800 ++      Module::Expr("a poem lovely as a tree");
  1.1801 ++  entry2_initial[ToUniqueString("cannoli")] =
  1.1802 ++      Module::Expr("a tree whose hungry mouth is prest");
  1.1803 +   EXPECT_THAT(entries[1]->initial_rules, ContainerEq(entry2_initial));
  1.1804 +   ASSERT_EQ(0U, entries[1]->rule_changes.size());
  1.1805 +   // Check third entry.
  1.1806 +   EXPECT_EQ(0xddb5f41285aa7757ULL, entries[2]->address);
  1.1807 +   EXPECT_EQ(0x1486493370dc5073ULL, entries[2]->size);
  1.1808 +   ASSERT_EQ(0U, entries[2]->initial_rules.size());
  1.1809 +   ASSERT_EQ(0U, entries[2]->rule_changes.size());
  1.1810 + }
  1.1811 +@@ -585,33 +606,36 @@
  1.1812 +   entry1->address = 0x2000;
  1.1813 +   entry1->size = 0x900;
  1.1814 +   m.AddStackFrameEntry(entry1);
  1.1815 + 
  1.1816 +   // Second STACK CFI entry, with initial rules but no deltas.
  1.1817 +   Module::StackFrameEntry *entry2 = new Module::StackFrameEntry();
  1.1818 +   entry2->address = 0x3000;
  1.1819 +   entry2->size = 0x900;
  1.1820 +-  entry2->initial_rules[".cfa"] = Module::Expr("I think that I shall never see");
  1.1821 +-  entry2->initial_rules["stromboli"] = Module::Expr("a poem lovely as a tree");
  1.1822 +-  entry2->initial_rules["cannoli"] = Module::Expr("a tree whose hungry mouth is prest");
  1.1823 ++  entry2->initial_rules[ustr__ZDcfa()] =
  1.1824 ++      Module::Expr("I think that I shall never see");
  1.1825 ++  entry2->initial_rules[ToUniqueString("stromboli")] =
  1.1826 ++      Module::Expr("a poem lovely as a tree");
  1.1827 ++  entry2->initial_rules[ToUniqueString("cannoli")] =
  1.1828 ++      Module::Expr("a tree whose hungry mouth is prest");
  1.1829 +   m.AddStackFrameEntry(entry2);
  1.1830 + 
  1.1831 +   // Third STACK CFI entry, with initial rules and deltas.
  1.1832 +   Module::StackFrameEntry *entry3 = new Module::StackFrameEntry();
  1.1833 +   entry3->address = 0x1000;
  1.1834 +   entry3->size = 0x900;
  1.1835 +-  entry3->initial_rules[".cfa"] = Module::Expr("Whose woods are these");
  1.1836 +-  entry3->rule_changes[0x47ceb0f63c269d7fULL]["calzone"] =
  1.1837 ++  entry3->initial_rules[ustr__ZDcfa()] = Module::Expr("Whose woods are these");
  1.1838 ++  entry3->rule_changes[0x47ceb0f63c269d7fULL][ToUniqueString("calzone")] =
  1.1839 +     Module::Expr("the village though");
  1.1840 +-  entry3->rule_changes[0x47ceb0f63c269d7fULL]["cannoli"] =
  1.1841 ++  entry3->rule_changes[0x47ceb0f63c269d7fULL][ToUniqueString("cannoli")] =
  1.1842 +     Module::Expr("he will not see me stopping here");
  1.1843 +-  entry3->rule_changes[0x36682fad3763ffffULL]["stromboli"] =
  1.1844 ++  entry3->rule_changes[0x36682fad3763ffffULL][ToUniqueString("stromboli")] =
  1.1845 +     Module::Expr("his house is in");
  1.1846 +-  entry3->rule_changes[0x36682fad3763ffffULL][".cfa"] =
  1.1847 ++  entry3->rule_changes[0x36682fad3763ffffULL][ustr__ZDcfa()] =
  1.1848 +     Module::Expr("I think I know");
  1.1849 +   m.AddStackFrameEntry(entry3);
  1.1850 + 
  1.1851 +   Module::StackFrameEntry* s = m.FindStackFrameEntryByAddress(0x1000);
  1.1852 +   EXPECT_EQ(entry3, s);
  1.1853 +   s = m.FindStackFrameEntryByAddress(0x18FF);
  1.1854 +   EXPECT_EQ(entry3, s);
  1.1855 + 
  1.1856 +diff --git a/src/common/unique_string.cc b/src/common/unique_string.cc
  1.1857 +new file mode 100644
  1.1858 +--- /dev/null
  1.1859 ++++ b/src/common/unique_string.cc
  1.1860 +@@ -0,0 +1,110 @@
  1.1861 ++// Copyright (c) 2013 Google Inc.
  1.1862 ++// All rights reserved.
  1.1863 ++//
  1.1864 ++// Redistribution and use in source and binary forms, with or without
  1.1865 ++// modification, are permitted provided that the following conditions are
  1.1866 ++// met:
  1.1867 ++//
  1.1868 ++//     * Redistributions of source code must retain the above copyright
  1.1869 ++// notice, this list of conditions and the following disclaimer.
  1.1870 ++//     * Redistributions in binary form must reproduce the above
  1.1871 ++// copyright notice, this list of conditions and the following disclaimer
  1.1872 ++// in the documentation and/or other materials provided with the
  1.1873 ++// distribution.
  1.1874 ++//     * Neither the name of Google Inc. nor the names of its
  1.1875 ++// contributors may be used to endorse or promote products derived from
  1.1876 ++// this software without specific prior written permission.
  1.1877 ++//
  1.1878 ++// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  1.1879 ++// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  1.1880 ++// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  1.1881 ++// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  1.1882 ++// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  1.1883 ++// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  1.1884 ++// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  1.1885 ++// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  1.1886 ++// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  1.1887 ++// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  1.1888 ++// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  1.1889 ++
  1.1890 ++#include <string>
  1.1891 ++#include <map>
  1.1892 ++
  1.1893 ++#include <stdlib.h>
  1.1894 ++#include <string.h>
  1.1895 ++
  1.1896 ++#include "common/unique_string.h"
  1.1897 ++
  1.1898 ++namespace google_breakpad {
  1.1899 ++
  1.1900 ++///////////////////////////////////////////////////////////////////
  1.1901 ++// UniqueString
  1.1902 ++//
  1.1903 ++class UniqueString {
  1.1904 ++ public:
  1.1905 ++  UniqueString(string str) { str_ = strdup(str.c_str()); }
  1.1906 ++  ~UniqueString() { free(reinterpret_cast<void*>(const_cast<char*>(str_))); }
  1.1907 ++  const char* str_;
  1.1908 ++};
  1.1909 ++
  1.1910 ++class UniqueStringUniverse {
  1.1911 ++ public:
  1.1912 ++  UniqueStringUniverse() {};
  1.1913 ++  const UniqueString* FindOrCopy(string str) {
  1.1914 ++    std::map<string, UniqueString*>::iterator it = map_.find(str);
  1.1915 ++    if (it == map_.end()) {
  1.1916 ++      UniqueString* ustr = new UniqueString(str);
  1.1917 ++      map_[str] = ustr;
  1.1918 ++      return ustr;
  1.1919 ++    } else {
  1.1920 ++      return it->second;
  1.1921 ++    }
  1.1922 ++  }
  1.1923 ++ private:
  1.1924 ++  std::map<string, UniqueString*> map_;
  1.1925 ++};
  1.1926 ++
  1.1927 ++//
  1.1928 ++///////////////////////////////////////////////////////////////////
  1.1929 ++
  1.1930 ++
  1.1931 ++static UniqueStringUniverse* sUSU = NULL;
  1.1932 ++
  1.1933 ++
  1.1934 ++// This isn't threadsafe.
  1.1935 ++const UniqueString* ToUniqueString(string str) {
  1.1936 ++  if (!sUSU) {
  1.1937 ++    sUSU = new UniqueStringUniverse();
  1.1938 ++  }
  1.1939 ++  return sUSU->FindOrCopy(str);
  1.1940 ++}
  1.1941 ++
  1.1942 ++// This isn't threadsafe.
  1.1943 ++const UniqueString* ToUniqueString_n(const char* str, size_t n) {
  1.1944 ++  if (!sUSU) {
  1.1945 ++    sUSU = new UniqueStringUniverse();
  1.1946 ++  }
  1.1947 ++  string key(str, n);
  1.1948 ++  return sUSU->FindOrCopy(key);
  1.1949 ++}
  1.1950 ++
  1.1951 ++const char Index(const UniqueString* us, int ix)
  1.1952 ++{
  1.1953 ++  return us->str_[ix];
  1.1954 ++}
  1.1955 ++
  1.1956 ++const char* const FromUniqueString(const UniqueString* ustr)
  1.1957 ++{
  1.1958 ++  return ustr->str_;
  1.1959 ++}
  1.1960 ++
  1.1961 ++int StrcmpUniqueString(const UniqueString* us1, const UniqueString* us2) {
  1.1962 ++  return strcmp(us1->str_, us2->str_);
  1.1963 ++}
  1.1964 ++
  1.1965 ++bool LessThan_UniqueString(const UniqueString* us1, const UniqueString* us2) {
  1.1966 ++  int r = StrcmpUniqueString(us1, us2);
  1.1967 ++  return r < 0;
  1.1968 ++}
  1.1969 ++
  1.1970 ++}  // namespace google_breakpad
  1.1971 +diff --git a/src/common/unique_string.h b/src/common/unique_string.h
  1.1972 +new file mode 100644
  1.1973 +--- /dev/null
  1.1974 ++++ b/src/common/unique_string.h
  1.1975 +@@ -0,0 +1,239 @@
  1.1976 ++// Copyright (c) 2013 Google Inc.
  1.1977 ++// All rights reserved.
  1.1978 ++//
  1.1979 ++// Redistribution and use in source and binary forms, with or without
  1.1980 ++// modification, are permitted provided that the following conditions are
  1.1981 ++// met:
  1.1982 ++//
  1.1983 ++//     * Redistributions of source code must retain the above copyright
  1.1984 ++// notice, this list of conditions and the following disclaimer.
  1.1985 ++//     * Redistributions in binary form must reproduce the above
  1.1986 ++// copyright notice, this list of conditions and the following disclaimer
  1.1987 ++// in the documentation and/or other materials provided with the
  1.1988 ++// distribution.
  1.1989 ++//     * Neither the name of Google Inc. nor the names of its
  1.1990 ++// contributors may be used to endorse or promote products derived from
  1.1991 ++// this software without specific prior written permission.
  1.1992 ++//
  1.1993 ++// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  1.1994 ++// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  1.1995 ++// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  1.1996 ++// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  1.1997 ++// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  1.1998 ++// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  1.1999 ++// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  1.2000 ++// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  1.2001 ++// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  1.2002 ++// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  1.2003 ++// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  1.2004 ++
  1.2005 ++#ifndef COMMON_UNIQUE_STRING_H_
  1.2006 ++#define COMMON_UNIQUE_STRING_H_
  1.2007 ++
  1.2008 ++#include <string>
  1.2009 ++#include "common/using_std_string.h"
  1.2010 ++
  1.2011 ++namespace google_breakpad {
  1.2012 ++
  1.2013 ++// Abstract type
  1.2014 ++class UniqueString;
  1.2015 ++
  1.2016 ++// Unique-ify a string.  |ToUniqueString| can never return NULL.
  1.2017 ++const UniqueString* ToUniqueString(string);
  1.2018 ++
  1.2019 ++// ditto, starting instead from the first n characters of a C string
  1.2020 ++const UniqueString* ToUniqueString_n(const char* str, size_t n);
  1.2021 ++
  1.2022 ++// Pull chars out of the string.  No range checking.
  1.2023 ++const char Index(const UniqueString*, int);
  1.2024 ++
  1.2025 ++// Get the contained C string (debugging only)
  1.2026 ++const char* const FromUniqueString(const UniqueString*);
  1.2027 ++
  1.2028 ++// Do a strcmp-style comparison on the contained C string
  1.2029 ++int StrcmpUniqueString(const UniqueString*, const UniqueString*);
  1.2030 ++
  1.2031 ++// Less-than comparison of two UniqueStrings, usable for std::sort.
  1.2032 ++bool LessThan_UniqueString(const UniqueString*, const UniqueString*);
  1.2033 ++
  1.2034 ++// Some handy pre-uniqified strings.  Z is an escape character:
  1.2035 ++//   ZS        '$'
  1.2036 ++//   ZD        '.'
  1.2037 ++//   Zeq       '='
  1.2038 ++//   Zplus     '+'
  1.2039 ++//   Zstar     '*'
  1.2040 ++//   Zslash    '/'
  1.2041 ++//   Zpercent  '%'
  1.2042 ++//   Zat       '@'
  1.2043 ++//   Zcaret    '^'
  1.2044 ++
  1.2045 ++// Note that ustr__empty and (UniqueString*)NULL are considered
  1.2046 ++// to be different.
  1.2047 ++//
  1.2048 ++// Unfortunately these have to be written as functions so as to
  1.2049 ++// make them safe to use in static initialisers.
  1.2050 ++
  1.2051 ++// ""
  1.2052 ++inline static const UniqueString* ustr__empty() {
  1.2053 ++  static const UniqueString* us = NULL;
  1.2054 ++  if (!us) us = ToUniqueString("");
  1.2055 ++  return us;
  1.2056 ++}
  1.2057 ++
  1.2058 ++// "$eip"
  1.2059 ++inline static const UniqueString* ustr__ZSeip() {
  1.2060 ++  static const UniqueString* us = NULL;
  1.2061 ++  if (!us) us = ToUniqueString("$eip");
  1.2062 ++  return us;
  1.2063 ++}
  1.2064 ++
  1.2065 ++// "$ebp"
  1.2066 ++inline static const UniqueString* ustr__ZSebp() {
  1.2067 ++  static const UniqueString* us = NULL;
  1.2068 ++  if (!us) us = ToUniqueString("$ebp");
  1.2069 ++  return us;
  1.2070 ++}
  1.2071 ++
  1.2072 ++// "$esp"
  1.2073 ++inline static const UniqueString* ustr__ZSesp() {
  1.2074 ++  static const UniqueString* us = NULL;
  1.2075 ++  if (!us) us = ToUniqueString("$esp");
  1.2076 ++  return us;
  1.2077 ++}
  1.2078 ++
  1.2079 ++// "$ebx"
  1.2080 ++inline static const UniqueString* ustr__ZSebx() {
  1.2081 ++  static const UniqueString* us = NULL;
  1.2082 ++  if (!us) us = ToUniqueString("$ebx");
  1.2083 ++  return us;
  1.2084 ++}
  1.2085 ++
  1.2086 ++// "$esi"
  1.2087 ++inline static const UniqueString* ustr__ZSesi() {
  1.2088 ++  static const UniqueString* us = NULL;
  1.2089 ++  if (!us) us = ToUniqueString("$esi");
  1.2090 ++  return us;
  1.2091 ++}
  1.2092 ++
  1.2093 ++// "$edi"
  1.2094 ++inline static const UniqueString* ustr__ZSedi() {
  1.2095 ++  static const UniqueString* us = NULL;
  1.2096 ++  if (!us) us = ToUniqueString("$edi");
  1.2097 ++  return us;
  1.2098 ++}
  1.2099 ++
  1.2100 ++// ".cbCalleeParams"
  1.2101 ++inline static const UniqueString* ustr__ZDcbCalleeParams() {
  1.2102 ++  static const UniqueString* us = NULL;
  1.2103 ++  if (!us) us = ToUniqueString(".cbCalleeParams");
  1.2104 ++  return us;
  1.2105 ++}
  1.2106 ++
  1.2107 ++// ".cbSavedRegs"
  1.2108 ++inline static const UniqueString* ustr__ZDcbSavedRegs() {
  1.2109 ++  static const UniqueString* us = NULL;
  1.2110 ++  if (!us) us = ToUniqueString(".cbSavedRegs");
  1.2111 ++  return us;
  1.2112 ++}
  1.2113 ++
  1.2114 ++// ".cbLocals"
  1.2115 ++inline static const UniqueString* ustr__ZDcbLocals() {
  1.2116 ++  static const UniqueString* us = NULL;
  1.2117 ++  if (!us) us = ToUniqueString(".cbLocals");
  1.2118 ++  return us;
  1.2119 ++}
  1.2120 ++
  1.2121 ++// ".raSearchStart"
  1.2122 ++inline static const UniqueString* ustr__ZDraSearchStart() {
  1.2123 ++  static const UniqueString* us = NULL;
  1.2124 ++  if (!us) us = ToUniqueString(".raSearchStart");
  1.2125 ++  return us;
  1.2126 ++}
  1.2127 ++
  1.2128 ++// ".raSearch"
  1.2129 ++inline static const UniqueString* ustr__ZDraSearch() {
  1.2130 ++  static const UniqueString* us = NULL;
  1.2131 ++  if (!us) us = ToUniqueString(".raSearch");
  1.2132 ++  return us;
  1.2133 ++}
  1.2134 ++
  1.2135 ++// ".cbParams"
  1.2136 ++inline static const UniqueString* ustr__ZDcbParams() {
  1.2137 ++  static const UniqueString* us = NULL;
  1.2138 ++  if (!us) us = ToUniqueString(".cbParams");
  1.2139 ++  return us;
  1.2140 ++}
  1.2141 ++
  1.2142 ++// "+"
  1.2143 ++inline static const UniqueString* ustr__Zplus() {
  1.2144 ++  static const UniqueString* us = NULL;
  1.2145 ++  if (!us) us = ToUniqueString("+");
  1.2146 ++  return us;
  1.2147 ++}
  1.2148 ++
  1.2149 ++// "-"
  1.2150 ++inline static const UniqueString* ustr__Zminus() {
  1.2151 ++  static const UniqueString* us = NULL;
  1.2152 ++  if (!us) us = ToUniqueString("-");
  1.2153 ++  return us;
  1.2154 ++}
  1.2155 ++
  1.2156 ++// "*"
  1.2157 ++inline static const UniqueString* ustr__Zstar() {
  1.2158 ++  static const UniqueString* us = NULL;
  1.2159 ++  if (!us) us = ToUniqueString("*");
  1.2160 ++  return us;
  1.2161 ++}
  1.2162 ++
  1.2163 ++// "/"
  1.2164 ++inline static const UniqueString* ustr__Zslash() {
  1.2165 ++  static const UniqueString* us = NULL;
  1.2166 ++  if (!us) us = ToUniqueString("/");
  1.2167 ++  return us;
  1.2168 ++}
  1.2169 ++
  1.2170 ++// "%"
  1.2171 ++inline static const UniqueString* ustr__Zpercent() {
  1.2172 ++  static const UniqueString* us = NULL;
  1.2173 ++  if (!us) us = ToUniqueString("%");
  1.2174 ++  return us;
  1.2175 ++}
  1.2176 ++
  1.2177 ++// "@"
  1.2178 ++inline static const UniqueString* ustr__Zat() {
  1.2179 ++  static const UniqueString* us = NULL;
  1.2180 ++  if (!us) us = ToUniqueString("@");
  1.2181 ++  return us;
  1.2182 ++}
  1.2183 ++
  1.2184 ++// "^"
  1.2185 ++inline static const UniqueString* ustr__Zcaret() {
  1.2186 ++  static const UniqueString* us = NULL;
  1.2187 ++  if (!us) us = ToUniqueString("^");
  1.2188 ++  return us;
  1.2189 ++}
  1.2190 ++
  1.2191 ++// "="
  1.2192 ++inline static const UniqueString* ustr__Zeq() {
  1.2193 ++  static const UniqueString* us = NULL;
  1.2194 ++  if (!us) us = ToUniqueString("=");
  1.2195 ++  return us;
  1.2196 ++}
  1.2197 ++
  1.2198 ++// ".cfa"
  1.2199 ++inline static const UniqueString* ustr__ZDcfa() {
  1.2200 ++  static const UniqueString* us = NULL;
  1.2201 ++  if (!us) us = ToUniqueString(".cfa");
  1.2202 ++  return us;
  1.2203 ++}
  1.2204 ++
  1.2205 ++// ".ra"
  1.2206 ++inline static const UniqueString* ustr__ZDra() {
  1.2207 ++  static const UniqueString* us = NULL;
  1.2208 ++  if (!us) us = ToUniqueString(".ra");
  1.2209 ++  return us;
  1.2210 ++}
  1.2211 ++
  1.2212 ++}  // namespace google_breakpad
  1.2213 ++
  1.2214 ++#endif  // COMMON_UNIQUE_STRING_H_
  1.2215 +diff --git a/src/processor/basic_source_line_resolver_unittest.cc b/src/processor/basic_source_line_resolver_unittest.cc
  1.2216 +--- a/src/processor/basic_source_line_resolver_unittest.cc
  1.2217 ++++ b/src/processor/basic_source_line_resolver_unittest.cc
  1.2218 +@@ -43,21 +43,30 @@
  1.2219 + #include "processor/windows_frame_info.h"
  1.2220 + #include "processor/cfi_frame_info.h"
  1.2221 + 
  1.2222 + namespace {
  1.2223 + 
  1.2224 + using google_breakpad::BasicSourceLineResolver;
  1.2225 + using google_breakpad::CFIFrameInfo;
  1.2226 + using google_breakpad::CodeModule;
  1.2227 ++using google_breakpad::FromUniqueString;
  1.2228 + using google_breakpad::MemoryRegion;
  1.2229 + using google_breakpad::StackFrame;
  1.2230 ++using google_breakpad::ToUniqueString;
  1.2231 + using google_breakpad::WindowsFrameInfo;
  1.2232 + using google_breakpad::linked_ptr;
  1.2233 + using google_breakpad::scoped_ptr;
  1.2234 ++using google_breakpad::ustr__ZDcfa;
  1.2235 ++using google_breakpad::ustr__ZDra;
  1.2236 ++using google_breakpad::ustr__ZSebx;
  1.2237 ++using google_breakpad::ustr__ZSebp;
  1.2238 ++using google_breakpad::ustr__ZSedi;
  1.2239 ++using google_breakpad::ustr__ZSesi;
  1.2240 ++using google_breakpad::ustr__ZSesp;
  1.2241 + 
  1.2242 + class TestCodeModule : public CodeModule {
  1.2243 +  public:
  1.2244 +   TestCodeModule(string code_file) : code_file_(code_file) {}
  1.2245 +   virtual ~TestCodeModule() {}
  1.2246 + 
  1.2247 +   virtual uint64_t base_address() const { return 0; }
  1.2248 +   virtual uint64_t size() const { return 0xb000; }
  1.2249 +@@ -107,34 +116,34 @@
  1.2250 + // association. (That is, ACTUAL's associations should be a subset of
  1.2251 + // EXPECTED's.) Also verify that ACTUAL has associations for ".ra" and
  1.2252 + // ".cfa".
  1.2253 + static bool VerifyRegisters(
  1.2254 +     const char *file, int line,
  1.2255 +     const CFIFrameInfo::RegisterValueMap<uint32_t> &expected,
  1.2256 +     const CFIFrameInfo::RegisterValueMap<uint32_t> &actual) {
  1.2257 +   CFIFrameInfo::RegisterValueMap<uint32_t>::const_iterator a;
  1.2258 +-  a = actual.find(".cfa");
  1.2259 ++  a = actual.find(ustr__ZDcfa());
  1.2260 +   if (a == actual.end())
  1.2261 +     return false;
  1.2262 +-  a = actual.find(".ra");
  1.2263 ++  a = actual.find(ustr__ZDra());
  1.2264 +   if (a == actual.end())
  1.2265 +     return false;
  1.2266 +   for (a = actual.begin(); a != actual.end(); a++) {
  1.2267 +     CFIFrameInfo::RegisterValueMap<uint32_t>::const_iterator e =
  1.2268 +       expected.find(a->first);
  1.2269 +     if (e == expected.end()) {
  1.2270 +       fprintf(stderr, "%s:%d: unexpected register '%s' recovered, value 0x%x\n",
  1.2271 +-              file, line, a->first.c_str(), a->second);
  1.2272 ++              file, line, FromUniqueString(a->first), a->second);
  1.2273 +       return false;
  1.2274 +     }
  1.2275 +     if (e->second != a->second) {
  1.2276 +       fprintf(stderr,
  1.2277 +               "%s:%d: register '%s' recovered value was 0x%x, expected 0x%x\n",
  1.2278 +-              file, line, a->first.c_str(), a->second, e->second);
  1.2279 ++              file, line, FromUniqueString(a->first), a->second, e->second);
  1.2280 +       return false;
  1.2281 +     }
  1.2282 +     // Don't complain if this doesn't recover all registers. Although
  1.2283 +     // the DWARF spec says that unmentioned registers are undefined,
  1.2284 +     // GCC uses omission to mean that they are unchanged.
  1.2285 +   }
  1.2286 +   return true;
  1.2287 + }
  1.2288 +@@ -254,81 +263,81 @@
  1.2289 + 
  1.2290 +   CFIFrameInfo::RegisterValueMap<uint32_t> current_registers;
  1.2291 +   CFIFrameInfo::RegisterValueMap<uint32_t> caller_registers;
  1.2292 +   CFIFrameInfo::RegisterValueMap<uint32_t> expected_caller_registers;
  1.2293 +   MockMemoryRegion memory;
  1.2294 + 
  1.2295 +   // Regardless of which instruction evaluation takes place at, it
  1.2296 +   // should produce the same values for the caller's registers.
  1.2297 +-  expected_caller_registers[".cfa"] = 0x1001c;
  1.2298 +-  expected_caller_registers[".ra"]  = 0xf6438648;
  1.2299 +-  expected_caller_registers["$ebp"] = 0x10038;
  1.2300 +-  expected_caller_registers["$ebx"] = 0x98ecadc3;
  1.2301 +-  expected_caller_registers["$esi"] = 0x878f7524;
  1.2302 +-  expected_caller_registers["$edi"] = 0x6312f9a5;
  1.2303 ++  expected_caller_registers[ustr__ZDcfa()] = 0x1001c;
  1.2304 ++  expected_caller_registers[ustr__ZDra()]  = 0xf6438648;
  1.2305 ++  expected_caller_registers[ustr__ZSebp()] = 0x10038;
  1.2306 ++  expected_caller_registers[ustr__ZSebx()] = 0x98ecadc3;
  1.2307 ++  expected_caller_registers[ustr__ZSesi()] = 0x878f7524;
  1.2308 ++  expected_caller_registers[ustr__ZSedi()] = 0x6312f9a5;
  1.2309 + 
  1.2310 +   frame.instruction = 0x3d40;
  1.2311 +   frame.module = &module1;
  1.2312 +   current_registers.clear();
  1.2313 +-  current_registers["$esp"] = 0x10018;
  1.2314 +-  current_registers["$ebp"] = 0x10038;
  1.2315 +-  current_registers["$ebx"] = 0x98ecadc3;
  1.2316 +-  current_registers["$esi"] = 0x878f7524;
  1.2317 +-  current_registers["$edi"] = 0x6312f9a5;
  1.2318 ++  current_registers[ustr__ZSesp()] = 0x10018;
  1.2319 ++  current_registers[ustr__ZSebp()] = 0x10038;
  1.2320 ++  current_registers[ustr__ZSebx()] = 0x98ecadc3;
  1.2321 ++  current_registers[ustr__ZSesi()] = 0x878f7524;
  1.2322 ++  current_registers[ustr__ZSedi()] = 0x6312f9a5;
  1.2323 +   cfi_frame_info.reset(resolver.FindCFIFrameInfo(&frame));
  1.2324 +   ASSERT_TRUE(cfi_frame_info.get());
  1.2325 +   ASSERT_TRUE(cfi_frame_info.get()
  1.2326 +               ->FindCallerRegs<uint32_t>(current_registers, memory,
  1.2327 +                                           &caller_registers));
  1.2328 +   ASSERT_TRUE(VerifyRegisters(__FILE__, __LINE__,
  1.2329 +                               expected_caller_registers, caller_registers));
  1.2330 + 
  1.2331 +   frame.instruction = 0x3d41;
  1.2332 +-  current_registers["$esp"] = 0x10014;
  1.2333 ++  current_registers[ustr__ZSesp()] = 0x10014;
  1.2334 +   cfi_frame_info.reset(resolver.FindCFIFrameInfo(&frame));
  1.2335 +   ASSERT_TRUE(cfi_frame_info.get());
  1.2336 +   ASSERT_TRUE(cfi_frame_info.get()
  1.2337 +               ->FindCallerRegs<uint32_t>(current_registers, memory,
  1.2338 +                                           &caller_registers));
  1.2339 +   ASSERT_TRUE(VerifyRegisters(__FILE__, __LINE__,
  1.2340 +                               expected_caller_registers, caller_registers));
  1.2341 + 
  1.2342 +   frame.instruction = 0x3d43;
  1.2343 +-  current_registers["$ebp"] = 0x10014;
  1.2344 ++  current_registers[ustr__ZSebp()] = 0x10014;
  1.2345 +   cfi_frame_info.reset(resolver.FindCFIFrameInfo(&frame));
  1.2346 +   ASSERT_TRUE(cfi_frame_info.get());
  1.2347 +   ASSERT_TRUE(cfi_frame_info.get()
  1.2348 +               ->FindCallerRegs<uint32_t>(current_registers, memory,
  1.2349 +                                           &caller_registers));
  1.2350 +   VerifyRegisters(__FILE__, __LINE__,
  1.2351 +                   expected_caller_registers, caller_registers);
  1.2352 + 
  1.2353 +   frame.instruction = 0x3d54;
  1.2354 +-  current_registers["$ebx"] = 0x6864f054U;
  1.2355 ++  current_registers[ustr__ZSebx()] = 0x6864f054U;
  1.2356 +   cfi_frame_info.reset(resolver.FindCFIFrameInfo(&frame));
  1.2357 +   ASSERT_TRUE(cfi_frame_info.get());
  1.2358 +   ASSERT_TRUE(cfi_frame_info.get()
  1.2359 +               ->FindCallerRegs<uint32_t>(current_registers, memory,
  1.2360 +                                           &caller_registers));
  1.2361 +   VerifyRegisters(__FILE__, __LINE__,
  1.2362 +                   expected_caller_registers, caller_registers);
  1.2363 + 
  1.2364 +   frame.instruction = 0x3d5a;
  1.2365 +-  current_registers["$esi"] = 0x6285f79aU;
  1.2366 ++  current_registers[ustr__ZSesi()] = 0x6285f79aU;
  1.2367 +   cfi_frame_info.reset(resolver.FindCFIFrameInfo(&frame));
  1.2368 +   ASSERT_TRUE(cfi_frame_info.get());
  1.2369 +   ASSERT_TRUE(cfi_frame_info.get()
  1.2370 +               ->FindCallerRegs<uint32_t>(current_registers, memory,
  1.2371 +                                           &caller_registers));
  1.2372 +   VerifyRegisters(__FILE__, __LINE__,
  1.2373 +                   expected_caller_registers, caller_registers);
  1.2374 + 
  1.2375 +   frame.instruction = 0x3d84;
  1.2376 +-  current_registers["$edi"] = 0x64061449U;
  1.2377 ++  current_registers[ustr__ZSedi()] = 0x64061449U;
  1.2378 +   cfi_frame_info.reset(resolver.FindCFIFrameInfo(&frame));
  1.2379 +   ASSERT_TRUE(cfi_frame_info.get());
  1.2380 +   ASSERT_TRUE(cfi_frame_info.get()
  1.2381 +               ->FindCallerRegs<uint32_t>(current_registers, memory,
  1.2382 +                                           &caller_registers));
  1.2383 +   VerifyRegisters(__FILE__, __LINE__,
  1.2384 +                   expected_caller_registers, caller_registers);
  1.2385 + 
  1.2386 +diff --git a/src/processor/cfi_frame_info.cc b/src/processor/cfi_frame_info.cc
  1.2387 +--- a/src/processor/cfi_frame_info.cc
  1.2388 ++++ b/src/processor/cfi_frame_info.cc
  1.2389 +@@ -31,16 +31,17 @@
  1.2390 + 
  1.2391 + // cfi_frame_info.cc: Implementation of CFIFrameInfo class.
  1.2392 + // See cfi_frame_info.h for details.
  1.2393 + 
  1.2394 + #include "processor/cfi_frame_info.h"
  1.2395 + 
  1.2396 + #include <string.h>
  1.2397 + 
  1.2398 ++#include <algorithm>
  1.2399 + #include <sstream>
  1.2400 + 
  1.2401 + #include "common/scoped_ptr.h"
  1.2402 + #include "processor/postfix_evaluator-inl.h"
  1.2403 + 
  1.2404 + namespace google_breakpad {
  1.2405 + 
  1.2406 + #ifdef _WIN32
  1.2407 +@@ -65,33 +66,33 @@
  1.2408 +   V cfa;
  1.2409 +   working = registers;
  1.2410 +   if (!evaluator.EvaluateForValue(cfa_rule_, &cfa))
  1.2411 +     return false;
  1.2412 + 
  1.2413 +   // Then, compute the return address.
  1.2414 +   V ra;
  1.2415 +   working = registers;
  1.2416 +-  working[".cfa"] = cfa;
  1.2417 ++  working[ustr__ZDcfa()] = cfa;
  1.2418 +   if (!evaluator.EvaluateForValue(ra_rule_, &ra))
  1.2419 +     return false;
  1.2420 + 
  1.2421 +   // Now, compute values for all the registers register_rules_ mentions.
  1.2422 +   for (RuleMap::const_iterator it = register_rules_.begin();
  1.2423 +        it != register_rules_.end(); it++) {
  1.2424 +     V value;
  1.2425 +     working = registers;
  1.2426 +-    working[".cfa"] = cfa;
  1.2427 ++    working[ustr__ZDcfa()] = cfa;
  1.2428 +     if (!evaluator.EvaluateForValue(it->second, &value))
  1.2429 +       return false;
  1.2430 +     (*caller_registers)[it->first] = value;
  1.2431 +   }
  1.2432 + 
  1.2433 +-  (*caller_registers)[".ra"] = ra;
  1.2434 +-  (*caller_registers)[".cfa"] = cfa;
  1.2435 ++  (*caller_registers)[ustr__ZDra()] = ra;
  1.2436 ++  (*caller_registers)[ustr__ZDcfa()] = cfa;
  1.2437 + 
  1.2438 +   return true;
  1.2439 + }
  1.2440 + 
  1.2441 + // Explicit instantiations for 32-bit and 64-bit architectures.
  1.2442 + template bool CFIFrameInfo::FindCallerRegs<uint32_t>(
  1.2443 +     const RegisterValueMap<uint32_t> &registers,
  1.2444 +     const MemoryRegion &memory,
  1.2445 +@@ -107,81 +108,98 @@
  1.2446 +   if (!cfa_rule_.invalid()) {
  1.2447 +     stream << ".cfa: " << cfa_rule_;
  1.2448 +   }
  1.2449 +   if (!ra_rule_.invalid()) {
  1.2450 +     if (static_cast<std::streamoff>(stream.tellp()) != 0)
  1.2451 +       stream << " ";
  1.2452 +     stream << ".ra: " << ra_rule_;
  1.2453 +   }
  1.2454 ++
  1.2455 ++  // Visit the register rules in alphabetical order.  Because
  1.2456 ++  // register_rules_ has the elements in some arbitrary order,
  1.2457 ++  // get the names out into a vector, sort them, and visit in
  1.2458 ++  // sorted order.
  1.2459 ++  std::vector<const UniqueString*> rr_names;
  1.2460 +   for (RuleMap::const_iterator iter = register_rules_.begin();
  1.2461 +        iter != register_rules_.end();
  1.2462 +        ++iter) {
  1.2463 ++    rr_names.push_back(iter->first);
  1.2464 ++  }
  1.2465 ++
  1.2466 ++  std::sort(rr_names.begin(), rr_names.end(), LessThan_UniqueString);
  1.2467 ++
  1.2468 ++  // Now visit the register rules in alphabetical order.
  1.2469 ++  for (std::vector<const UniqueString*>::const_iterator name = rr_names.begin();
  1.2470 ++       name != rr_names.end();
  1.2471 ++       ++name) {
  1.2472 ++    const UniqueString* nm = *name;
  1.2473 ++    Module::Expr rule = register_rules_.find(nm)->second;
  1.2474 +     if (static_cast<std::streamoff>(stream.tellp()) != 0)
  1.2475 +       stream << " ";
  1.2476 +-    stream << iter->first << ": " << iter->second;
  1.2477 ++    stream << FromUniqueString(nm) << ": " << rule;
  1.2478 +   }
  1.2479 + 
  1.2480 +   return stream.str();
  1.2481 + }
  1.2482 + 
  1.2483 + bool CFIRuleParser::Parse(const string &rule_set) {
  1.2484 +   size_t rule_set_len = rule_set.size();
  1.2485 +   scoped_array<char> working_copy(new char[rule_set_len + 1]);
  1.2486 +   memcpy(working_copy.get(), rule_set.data(), rule_set_len);
  1.2487 +   working_copy[rule_set_len] = '\0';
  1.2488 + 
  1.2489 +-  name_.clear();
  1.2490 ++  name_ = ustr__empty();
  1.2491 +   expression_.clear();
  1.2492 + 
  1.2493 +   char *cursor;
  1.2494 +   static const char token_breaks[] = " \t\r\n";
  1.2495 +   char *token = strtok_r(working_copy.get(), token_breaks, &cursor);
  1.2496 + 
  1.2497 +   for (;;) {
  1.2498 +     // End of rule set?
  1.2499 +     if (!token) return Report();
  1.2500 + 
  1.2501 +     // Register/pseudoregister name?
  1.2502 +     size_t token_len = strlen(token);
  1.2503 +     if (token_len >= 1 && token[token_len - 1] == ':') {
  1.2504 +       // Names can't be empty.
  1.2505 +       if (token_len < 2) return false;
  1.2506 +       // If there is any pending content, report it.
  1.2507 +-      if (!name_.empty() || !expression_.empty()) {
  1.2508 ++      if (name_ != ustr__empty() || !expression_.empty()) {
  1.2509 +         if (!Report()) return false;
  1.2510 +       }
  1.2511 +-      name_.assign(token, token_len - 1);
  1.2512 ++      name_ = ToUniqueString_n(token, token_len - 1);
  1.2513 +       expression_.clear();
  1.2514 +     } else {
  1.2515 +       // Another expression component.
  1.2516 +       assert(token_len > 0); // strtok_r guarantees this, I think.
  1.2517 +       if (!expression_.empty())
  1.2518 +         expression_ += ' ';
  1.2519 +       expression_ += token;
  1.2520 +     }
  1.2521 +     token = strtok_r(NULL, token_breaks, &cursor);
  1.2522 +   }
  1.2523 + }
  1.2524 + 
  1.2525 + bool CFIRuleParser::Report() {
  1.2526 +-  if (name_.empty() || expression_.empty()) return false;
  1.2527 +-  if (name_ == ".cfa") handler_->CFARule(expression_);
  1.2528 +-  else if (name_ == ".ra") handler_->RARule(expression_);
  1.2529 ++  if (name_ == ustr__empty() || expression_.empty()) return false;
  1.2530 ++  if (name_ == ustr__ZDcfa()) handler_->CFARule(expression_);
  1.2531 ++  else if (name_ == ustr__ZDra()) handler_->RARule(expression_);
  1.2532 +   else handler_->RegisterRule(name_, expression_);
  1.2533 +   return true;
  1.2534 + }
  1.2535 + 
  1.2536 + void CFIFrameInfoParseHandler::CFARule(const string &expression) {
  1.2537 +   // 'expression' is a postfix expression string.
  1.2538 +   frame_info_->SetCFARule(Module::Expr(expression));
  1.2539 + }
  1.2540 + 
  1.2541 + void CFIFrameInfoParseHandler::RARule(const string &expression) {
  1.2542 +   frame_info_->SetRARule(Module::Expr(expression));
  1.2543 + }
  1.2544 + 
  1.2545 +-void CFIFrameInfoParseHandler::RegisterRule(const string &name,
  1.2546 ++void CFIFrameInfoParseHandler::RegisterRule(const UniqueString* name,
  1.2547 +                                             const string &expression) {
  1.2548 +   frame_info_->SetRegisterRule(name, Module::Expr(expression));
  1.2549 + }
  1.2550 + 
  1.2551 + } // namespace google_breakpad
  1.2552 +diff --git a/src/processor/cfi_frame_info.h b/src/processor/cfi_frame_info.h
  1.2553 +--- a/src/processor/cfi_frame_info.h
  1.2554 ++++ b/src/processor/cfi_frame_info.h
  1.2555 +@@ -37,16 +37,17 @@
  1.2556 + 
  1.2557 + #ifndef PROCESSOR_CFI_FRAME_INFO_H_
  1.2558 + #define PROCESSOR_CFI_FRAME_INFO_H_
  1.2559 + 
  1.2560 + #include <map>
  1.2561 + #include <string>
  1.2562 + 
  1.2563 + #include "common/using_std_string.h"
  1.2564 ++#include "common/unique_string.h"
  1.2565 + #include "google_breakpad/common/breakpad_types.h"
  1.2566 + #include "common/module.h"
  1.2567 + 
  1.2568 + namespace google_breakpad {
  1.2569 + 
  1.2570 + using std::map;
  1.2571 + 
  1.2572 + class MemoryRegion;
  1.2573 +@@ -63,24 +64,24 @@
  1.2574 + // changes given by the 'STACK CFI' records up to our instruction's
  1.2575 + // address. Then, use the FindCallerRegs member function to apply the
  1.2576 + // rules to the callee frame's register values, yielding the caller
  1.2577 + // frame's register values.
  1.2578 + class CFIFrameInfo {
  1.2579 +  public:
  1.2580 +   // A map from register names onto values.
  1.2581 +   template<typename ValueType> class RegisterValueMap:
  1.2582 +-    public map<string, ValueType> { };
  1.2583 ++    public map<const UniqueString*, ValueType> { };
  1.2584 + 
  1.2585 +   // Set the expression for computing a call frame address, return
  1.2586 +   // address, or register's value. At least the CFA rule and the RA
  1.2587 +   // rule must be set before calling FindCallerRegs.
  1.2588 +   void SetCFARule(const Module::Expr& rule) { cfa_rule_ = rule; }
  1.2589 +   void SetRARule(const Module::Expr& rule)  { ra_rule_ = rule; }
  1.2590 +-  void SetRegisterRule(const string& register_name,
  1.2591 ++  void SetRegisterRule(const UniqueString* register_name,
  1.2592 +                        const Module::Expr& rule) {
  1.2593 +     register_rules_[register_name] = rule;
  1.2594 +   }
  1.2595 + 
  1.2596 +   // Compute the values of the calling frame's registers, according to
  1.2597 +   // this rule set. Use ValueType in expression evaluation; this
  1.2598 +   // should be uint32_t on machines with 32-bit addresses, or
  1.2599 +   // uint64_t on machines with 64-bit addresses.
  1.2600 +@@ -104,17 +105,17 @@
  1.2601 + 
  1.2602 +   // Serialize the rules in this object into a string in the format
  1.2603 +   // of STACK CFI records.
  1.2604 +   string Serialize() const;
  1.2605 + 
  1.2606 +  private:
  1.2607 + 
  1.2608 +   // A map from register names onto evaluation rules.
  1.2609 +-  typedef map<string, Module::Expr> RuleMap;
  1.2610 ++  typedef map<const UniqueString*, Module::Expr> RuleMap;
  1.2611 + 
  1.2612 +   // An expression for computing the current frame's CFA (call
  1.2613 +   // frame address). The CFA is a reference address for the frame that
  1.2614 +   // remains unchanged throughout the frame's lifetime. You should
  1.2615 +   // evaluate this expression with a dictionary initially populated
  1.2616 +   // with the values of the current frame's known registers.
  1.2617 +   Module::Expr cfa_rule_;
  1.2618 + 
  1.2619 +@@ -145,17 +146,18 @@
  1.2620 +     Handler() { }
  1.2621 +     virtual ~Handler() { }
  1.2622 + 
  1.2623 +     // The input specifies EXPRESSION as the CFA/RA computation rule.
  1.2624 +     virtual void CFARule(const string &expression) = 0;
  1.2625 +     virtual void RARule(const string &expression) = 0;
  1.2626 + 
  1.2627 +     // The input specifies EXPRESSION as the recovery rule for register NAME.
  1.2628 +-    virtual void RegisterRule(const string &name, const string &expression) = 0;
  1.2629 ++    virtual void RegisterRule(const UniqueString* name,
  1.2630 ++                              const string &expression) = 0;
  1.2631 +   };
  1.2632 +     
  1.2633 +   // Construct a parser which feeds its results to HANDLER.
  1.2634 +   CFIRuleParser(Handler *handler) : handler_(handler) { }
  1.2635 + 
  1.2636 +   // Parse RULE_SET as a set of CFA computation and RA/register
  1.2637 +   // recovery rules, as appearing in STACK CFI records. Report the
  1.2638 +   // results of parsing by making the appropriate calls to handler_.
  1.2639 +@@ -165,30 +167,31 @@
  1.2640 +  private:
  1.2641 +   // Report any accumulated rule to handler_
  1.2642 +   bool Report();
  1.2643 + 
  1.2644 +   // The handler to which the parser reports its findings.
  1.2645 +   Handler *handler_;
  1.2646 + 
  1.2647 +   // Working data.
  1.2648 +-  string name_, expression_;
  1.2649 ++  const UniqueString* name_;
  1.2650 ++  string expression_;
  1.2651 + };
  1.2652 + 
  1.2653 + // A handler for rule set parsing that populates a CFIFrameInfo with
  1.2654 + // the results.
  1.2655 + class CFIFrameInfoParseHandler: public CFIRuleParser::Handler {
  1.2656 +  public:
  1.2657 +   // Populate FRAME_INFO with the results of parsing.
  1.2658 +   CFIFrameInfoParseHandler(CFIFrameInfo *frame_info)
  1.2659 +       : frame_info_(frame_info) { }
  1.2660 + 
  1.2661 +   void CFARule(const string &expression);
  1.2662 +   void RARule(const string &expression);
  1.2663 +-  void RegisterRule(const string &name, const string &expression);
  1.2664 ++  void RegisterRule(const UniqueString* name, const string &expression);
  1.2665 + 
  1.2666 +  private:
  1.2667 +   CFIFrameInfo *frame_info_;
  1.2668 + };
  1.2669 + 
  1.2670 + // A utility class template for simple 'STACK CFI'-driven stack walkers.
  1.2671 + // Given a CFIFrameInfo instance, a table describing the architecture's
  1.2672 + // register set, and a context holding the last frame's registers, an
  1.2673 +@@ -205,24 +208,24 @@
  1.2674 + // uint32_t or uint64_t. RawContextType should be the raw context
  1.2675 + // structure type for this architecture.
  1.2676 + template <typename RegisterType, class RawContextType>
  1.2677 + class SimpleCFIWalker {
  1.2678 +  public:
  1.2679 +   // A structure describing one architecture register.
  1.2680 +   struct RegisterSet {
  1.2681 +     // The register name, as it appears in STACK CFI rules.
  1.2682 +-    const char *name;
  1.2683 ++    const UniqueString* name;
  1.2684 + 
  1.2685 +     // An alternate name that the register's value might be found
  1.2686 +     // under in a register value dictionary, or NULL. When generating
  1.2687 +     // names, prefer NAME to this value. It's common to list ".cfa" as
  1.2688 +     // an alternative name for the stack pointer, and ".ra" as an
  1.2689 +     // alternative name for the instruction pointer.
  1.2690 +-    const char *alternate_name;
  1.2691 ++    const UniqueString* alternate_name;
  1.2692 + 
  1.2693 +     // True if the callee is expected to preserve the value of this
  1.2694 +     // register. If this flag is true for some register R, and the STACK
  1.2695 +     // CFI records provide no rule to recover R, then SimpleCFIWalker
  1.2696 +     // assumes that the callee has not changed R's value, and the caller's
  1.2697 +     // value for R is that currently in the callee's context.
  1.2698 +     bool callee_saves;
  1.2699 + 
  1.2700 +diff --git a/src/processor/cfi_frame_info_unittest.cc b/src/processor/cfi_frame_info_unittest.cc
  1.2701 +--- a/src/processor/cfi_frame_info_unittest.cc
  1.2702 ++++ b/src/processor/cfi_frame_info_unittest.cc
  1.2703 +@@ -38,19 +38,24 @@
  1.2704 + #include "common/module.h"
  1.2705 + #include "common/using_std_string.h"
  1.2706 + #include "processor/cfi_frame_info.h"
  1.2707 + #include "google_breakpad/processor/memory_region.h"
  1.2708 + 
  1.2709 + using google_breakpad::CFIFrameInfo;
  1.2710 + using google_breakpad::CFIFrameInfoParseHandler;
  1.2711 + using google_breakpad::CFIRuleParser;
  1.2712 ++using google_breakpad::FromUniqueString;
  1.2713 + using google_breakpad::MemoryRegion;
  1.2714 + using google_breakpad::Module;
  1.2715 + using google_breakpad::SimpleCFIWalker;
  1.2716 ++using google_breakpad::ToUniqueString;
  1.2717 ++using google_breakpad::UniqueString;
  1.2718 ++using google_breakpad::ustr__ZDcfa;
  1.2719 ++using google_breakpad::ustr__ZDra;
  1.2720 + using testing::_;
  1.2721 + using testing::A;
  1.2722 + using testing::AtMost;
  1.2723 + using testing::DoAll;
  1.2724 + using testing::Return;
  1.2725 + using testing::SetArgumentPointee;
  1.2726 + using testing::Test;
  1.2727 + 
  1.2728 +@@ -107,41 +112,47 @@
  1.2729 + TEST_F(Simple, SetCFAAndRARule) {
  1.2730 +   ExpectNoMemoryReferences();
  1.2731 + 
  1.2732 +   cfi.SetCFARule(Module::Expr("330903416631436410"));
  1.2733 +   cfi.SetRARule(Module::Expr("5870666104170902211"));
  1.2734 +   ASSERT_TRUE(cfi.FindCallerRegs<uint64_t>(registers, memory,
  1.2735 +                                             &caller_registers));
  1.2736 +   ASSERT_EQ(2U, caller_registers.size());
  1.2737 +-  ASSERT_EQ(330903416631436410ULL, caller_registers[".cfa"]);
  1.2738 +-  ASSERT_EQ(5870666104170902211ULL, caller_registers[".ra"]);
  1.2739 ++  ASSERT_EQ(330903416631436410ULL, caller_registers[ustr__ZDcfa()]);
  1.2740 ++  ASSERT_EQ(5870666104170902211ULL, caller_registers[ustr__ZDra()]);
  1.2741 + 
  1.2742 +   ASSERT_EQ(".cfa: 330903416631436410 .ra: 5870666104170902211",
  1.2743 +             cfi.Serialize());
  1.2744 + }
  1.2745 + 
  1.2746 + TEST_F(Simple, SetManyRules) {
  1.2747 +   ExpectNoMemoryReferences();
  1.2748 + 
  1.2749 +   cfi.SetCFARule(Module::Expr("$temp1 68737028 = $temp2 61072337 = $temp1 $temp2 -"));
  1.2750 +   cfi.SetRARule(Module::Expr(".cfa 99804755 +"));
  1.2751 +-  cfi.SetRegisterRule("register1", Module::Expr(".cfa 54370437 *"));
  1.2752 +-  cfi.SetRegisterRule("vodkathumbscrewingly", Module::Expr("24076308 .cfa +"));
  1.2753 +-  cfi.SetRegisterRule("pubvexingfjordschmaltzy", Module::Expr(".cfa 29801007 -"));
  1.2754 +-  cfi.SetRegisterRule("uncopyrightables", Module::Expr("92642917 .cfa /"));
  1.2755 ++
  1.2756 ++  const UniqueString* reg1 = ToUniqueString("register1");
  1.2757 ++  const UniqueString* reg2 = ToUniqueString("vodkathumbscrewingly");
  1.2758 ++  const UniqueString* reg3 = ToUniqueString("pubvexingfjordschmaltzy");
  1.2759 ++  const UniqueString* reg4 = ToUniqueString("uncopyrightables");
  1.2760 ++
  1.2761 ++  cfi.SetRegisterRule(reg1, Module::Expr(".cfa 54370437 *"));
  1.2762 ++  cfi.SetRegisterRule(reg2, Module::Expr("24076308 .cfa +"));
  1.2763 ++  cfi.SetRegisterRule(reg3, Module::Expr(".cfa 29801007 -"));
  1.2764 ++  cfi.SetRegisterRule(reg4, Module::Expr("92642917 .cfa /"));
  1.2765 +   ASSERT_TRUE(cfi.FindCallerRegs<uint64_t>(registers, memory,
  1.2766 +                                             &caller_registers));
  1.2767 +   ASSERT_EQ(6U, caller_registers.size());
  1.2768 +-  ASSERT_EQ(7664691U,           caller_registers[".cfa"]);
  1.2769 +-  ASSERT_EQ(107469446U,         caller_registers[".ra"]);
  1.2770 +-  ASSERT_EQ(416732599139967ULL, caller_registers["register1"]);
  1.2771 +-  ASSERT_EQ(31740999U,          caller_registers["vodkathumbscrewingly"]);
  1.2772 +-  ASSERT_EQ(-22136316ULL,       caller_registers["pubvexingfjordschmaltzy"]);
  1.2773 +-  ASSERT_EQ(12U,                caller_registers["uncopyrightables"]);
  1.2774 ++  ASSERT_EQ(7664691U,           caller_registers[ustr__ZDcfa()]);
  1.2775 ++  ASSERT_EQ(107469446U,         caller_registers[ustr__ZDra()]);
  1.2776 ++  ASSERT_EQ(416732599139967ULL, caller_registers[reg1]);
  1.2777 ++  ASSERT_EQ(31740999U,          caller_registers[reg2]);
  1.2778 ++  ASSERT_EQ(-22136316ULL,       caller_registers[reg3]);
  1.2779 ++  ASSERT_EQ(12U,                caller_registers[reg4]);
  1.2780 +   ASSERT_EQ(".cfa: $temp1 68737028 = $temp2 61072337 = $temp1 $temp2 - "
  1.2781 +             ".ra: .cfa 99804755 + "
  1.2782 +             "pubvexingfjordschmaltzy: .cfa 29801007 - "
  1.2783 +             "register1: .cfa 54370437 * "
  1.2784 +             "uncopyrightables: 92642917 .cfa / "
  1.2785 +             "vodkathumbscrewingly: 24076308 .cfa +",
  1.2786 +             cfi.Serialize());
  1.2787 + }
  1.2788 +@@ -150,18 +161,18 @@
  1.2789 +   ExpectNoMemoryReferences();
  1.2790 + 
  1.2791 +   cfi.SetCFARule(Module::Expr("330903416631436410"));
  1.2792 +   cfi.SetRARule(Module::Expr("5870666104170902211"));
  1.2793 +   cfi.SetCFARule(Module::Expr("2828089117179001"));
  1.2794 +   ASSERT_TRUE(cfi.FindCallerRegs<uint64_t>(registers, memory,
  1.2795 +                                             &caller_registers));
  1.2796 +   ASSERT_EQ(2U, caller_registers.size());
  1.2797 +-  ASSERT_EQ(2828089117179001ULL, caller_registers[".cfa"]);
  1.2798 +-  ASSERT_EQ(5870666104170902211ULL, caller_registers[".ra"]);
  1.2799 ++  ASSERT_EQ(2828089117179001ULL, caller_registers[ustr__ZDcfa()]);
  1.2800 ++  ASSERT_EQ(5870666104170902211ULL, caller_registers[ustr__ZDra()]);
  1.2801 +   ASSERT_EQ(".cfa: 2828089117179001 .ra: 5870666104170902211",
  1.2802 +             cfi.Serialize());
  1.2803 + }
  1.2804 + 
  1.2805 + class Scope: public CFIFixture, public Test { };
  1.2806 + 
  1.2807 + // There should be no value for .cfa in scope when evaluating the CFA rule.
  1.2808 + TEST_F(Scope, CFALacksCFA) {
  1.2809 +@@ -183,37 +194,39 @@
  1.2810 +                                              &caller_registers));
  1.2811 + }
  1.2812 + 
  1.2813 + // The current frame's registers should be in scope when evaluating
  1.2814 + // the CFA rule.
  1.2815 + TEST_F(Scope, CFASeesCurrentRegs) {
  1.2816 +   ExpectNoMemoryReferences();
  1.2817 + 
  1.2818 +-  registers[".baraminology"] = 0x06a7bc63e4f13893ULL;
  1.2819 +-  registers[".ornithorhynchus"] = 0x5e0bf850bafce9d2ULL;
  1.2820 ++  const UniqueString* reg1 = ToUniqueString(".baraminology");
  1.2821 ++  const UniqueString* reg2 = ToUniqueString(".ornithorhynchus");
  1.2822 ++  registers[reg1] = 0x06a7bc63e4f13893ULL;
  1.2823 ++  registers[reg2] = 0x5e0bf850bafce9d2ULL;
  1.2824 +   cfi.SetCFARule(Module::Expr(".baraminology .ornithorhynchus +"));
  1.2825 +   cfi.SetRARule(Module::Expr("0"));
  1.2826 +   ASSERT_TRUE(cfi.FindCallerRegs<uint64_t>(registers, memory,
  1.2827 +                                             &caller_registers));
  1.2828 +   ASSERT_EQ(2U, caller_registers.size());
  1.2829 +   ASSERT_EQ(0x06a7bc63e4f13893ULL + 0x5e0bf850bafce9d2ULL,
  1.2830 +-            caller_registers[".cfa"]);
  1.2831 ++            caller_registers[ustr__ZDcfa()]);
  1.2832 + }
  1.2833 + 
  1.2834 + // .cfa should be in scope in the return address expression.
  1.2835 + TEST_F(Scope, RASeesCFA) {
  1.2836 +   ExpectNoMemoryReferences();
  1.2837 + 
  1.2838 +   cfi.SetCFARule(Module::Expr("48364076"));
  1.2839 +   cfi.SetRARule(Module::Expr(".cfa"));
  1.2840 +   ASSERT_TRUE(cfi.FindCallerRegs<uint64_t>(registers, memory,
  1.2841 +                                             &caller_registers));
  1.2842 +   ASSERT_EQ(2U, caller_registers.size());
  1.2843 +-  ASSERT_EQ(48364076U, caller_registers[".ra"]);
  1.2844 ++  ASSERT_EQ(48364076U, caller_registers[ustr__ZDra()]);
  1.2845 + }
  1.2846 + 
  1.2847 + // There should be no value for .ra in scope when evaluating the CFA rule.
  1.2848 + TEST_F(Scope, RALacksRA) {
  1.2849 +   ExpectNoMemoryReferences();
  1.2850 + 
  1.2851 +   cfi.SetCFARule(Module::Expr("0"));
  1.2852 +   cfi.SetRARule(Module::Expr(".ra"));
  1.2853 +@@ -221,64 +234,69 @@
  1.2854 +                                              &caller_registers));
  1.2855 + }
  1.2856 + 
  1.2857 + // The current frame's registers should be in scope in the return
  1.2858 + // address expression.
  1.2859 + TEST_F(Scope, RASeesCurrentRegs) {
  1.2860 +   ExpectNoMemoryReferences();
  1.2861 + 
  1.2862 +-  registers["noachian"] = 0x54dc4a5d8e5eb503ULL;
  1.2863 +   cfi.SetCFARule(Module::Expr("10359370"));
  1.2864 +-  cfi.SetRARule(Module::Expr("noachian"));
  1.2865 ++  const UniqueString* reg1 = ToUniqueString("noachian");
  1.2866 ++  registers[reg1] = 0x54dc4a5d8e5eb503ULL;
  1.2867 ++  cfi.SetRARule(Module::Expr(reg1, 0, false));
  1.2868 +   ASSERT_TRUE(cfi.FindCallerRegs<uint64_t>(registers, memory,
  1.2869 +                                             &caller_registers));
  1.2870 +   ASSERT_EQ(2U, caller_registers.size());
  1.2871 +-  ASSERT_EQ(0x54dc4a5d8e5eb503ULL, caller_registers[".ra"]);
  1.2872 ++  ASSERT_EQ(0x54dc4a5d8e5eb503ULL, caller_registers[ustr__ZDra()]);
  1.2873 + }
  1.2874 + 
  1.2875 + // .cfa should be in scope for register rules.
  1.2876 + TEST_F(Scope, RegistersSeeCFA) {
  1.2877 +   ExpectNoMemoryReferences();
  1.2878 + 
  1.2879 +   cfi.SetCFARule(Module::Expr("6515179"));
  1.2880 +   cfi.SetRARule(Module::Expr(".cfa"));
  1.2881 +-  cfi.SetRegisterRule("rogerian", Module::Expr(".cfa"));
  1.2882 ++  const UniqueString* reg1 = ToUniqueString("rogerian");
  1.2883 ++  cfi.SetRegisterRule(reg1, Module::Expr(".cfa"));
  1.2884 +   ASSERT_TRUE(cfi.FindCallerRegs<uint64_t>(registers, memory,
  1.2885 +                                             &caller_registers));
  1.2886 +   ASSERT_EQ(3U, caller_registers.size());
  1.2887 +-  ASSERT_EQ(6515179U, caller_registers["rogerian"]);
  1.2888 ++  ASSERT_EQ(6515179U, caller_registers[reg1]);
  1.2889 + }
  1.2890 + 
  1.2891 + // The return address should not be in scope for register rules.
  1.2892 + TEST_F(Scope, RegsLackRA) {
  1.2893 +   ExpectNoMemoryReferences();
  1.2894 + 
  1.2895 +   cfi.SetCFARule(Module::Expr("42740329"));
  1.2896 +   cfi.SetRARule(Module::Expr("27045204"));
  1.2897 +-  cfi.SetRegisterRule("$r1", Module::Expr(".ra"));
  1.2898 ++  const UniqueString* reg1 = ToUniqueString("$r1");
  1.2899 ++  cfi.SetRegisterRule(reg1, Module::Expr(".ra"));
  1.2900 +   ASSERT_FALSE(cfi.FindCallerRegs<uint64_t>(registers, memory,
  1.2901 +                                              &caller_registers));
  1.2902 + }
  1.2903 + 
  1.2904 + // Register rules can see the current frame's register values.
  1.2905 + TEST_F(Scope, RegsSeeRegs) {
  1.2906 +   ExpectNoMemoryReferences();
  1.2907 + 
  1.2908 +-  registers["$r1"] = 0x6ed3582c4bedb9adULL;
  1.2909 +-  registers["$r2"] = 0xd27d9e742b8df6d0ULL;
  1.2910 ++  const UniqueString* reg1 = ToUniqueString("$r1");
  1.2911 ++  const UniqueString* reg2 = ToUniqueString("$r2");
  1.2912 ++  registers[reg1] = 0x6ed3582c4bedb9adULL;
  1.2913 ++  registers[reg2] = 0xd27d9e742b8df6d0ULL;
  1.2914 +   cfi.SetCFARule(Module::Expr("88239303"));
  1.2915 +   cfi.SetRARule(Module::Expr("30503835"));
  1.2916 +-  cfi.SetRegisterRule("$r1", Module::Expr("$r1 42175211 = $r2"));
  1.2917 +-  cfi.SetRegisterRule("$r2", Module::Expr("$r2 21357221 = $r1"));
  1.2918 ++  cfi.SetRegisterRule(reg1, Module::Expr("$r1 42175211 = $r2"));
  1.2919 ++  cfi.SetRegisterRule(reg2, Module::Expr("$r2 21357221 = $r1"));
  1.2920 +   ASSERT_TRUE(cfi.FindCallerRegs<uint64_t>(registers, memory,
  1.2921 +                                             &caller_registers));
  1.2922 +   ASSERT_EQ(4U, caller_registers.size());
  1.2923 +-  ASSERT_EQ(0xd27d9e742b8df6d0ULL, caller_registers["$r1"]);
  1.2924 +-  ASSERT_EQ(0x6ed3582c4bedb9adULL, caller_registers["$r2"]);
  1.2925 ++  ASSERT_EQ(0xd27d9e742b8df6d0ULL, caller_registers[reg1]);
  1.2926 ++  ASSERT_EQ(0x6ed3582c4bedb9adULL, caller_registers[reg2]);
  1.2927 + }
  1.2928 + 
  1.2929 + // Each rule's temporaries are separate.
  1.2930 + TEST_F(Scope, SeparateTempsRA) {
  1.2931 +   ExpectNoMemoryReferences();
  1.2932 + 
  1.2933 +   cfi.SetCFARule(Module::Expr("$temp1 76569129 = $temp1"));
  1.2934 +   cfi.SetRARule(Module::Expr("0"));
  1.2935 +@@ -290,17 +308,17 @@
  1.2936 +   ASSERT_FALSE(cfi.FindCallerRegs<uint64_t>(registers, memory,
  1.2937 +                                              &caller_registers));
  1.2938 + }
  1.2939 + 
  1.2940 + class MockCFIRuleParserHandler: public CFIRuleParser::Handler {
  1.2941 +  public:
  1.2942 +   MOCK_METHOD1(CFARule, void(const string &));
  1.2943 +   MOCK_METHOD1(RARule,  void(const string &));
  1.2944 +-  MOCK_METHOD2(RegisterRule, void(const string &, const string &));
  1.2945 ++  MOCK_METHOD2(RegisterRule, void(const UniqueString*, const string &));
  1.2946 + };
  1.2947 + 
  1.2948 + // A fixture class for testing CFIRuleParser.
  1.2949 + class CFIParserFixture {
  1.2950 +  public:
  1.2951 +   CFIParserFixture() : parser(&mock_handler) {
  1.2952 +     // Expect no parsing results to be reported to mock_handler. Individual
  1.2953 +     // tests can override this.
  1.2954 +@@ -361,100 +379,100 @@
  1.2955 + }
  1.2956 + 
  1.2957 + TEST_F(Parser, RA) {
  1.2958 +   EXPECT_CALL(mock_handler, RARule("notoriety")).WillOnce(Return());
  1.2959 +   EXPECT_TRUE(parser.Parse(".ra: notoriety"));
  1.2960 + }
  1.2961 + 
  1.2962 + TEST_F(Parser, Reg) {
  1.2963 +-  EXPECT_CALL(mock_handler, RegisterRule("nemo", "mellifluous"))
  1.2964 ++  EXPECT_CALL(mock_handler, RegisterRule(ToUniqueString("nemo"), "mellifluous"))
  1.2965 +       .WillOnce(Return());
  1.2966 +   EXPECT_TRUE(parser.Parse("nemo: mellifluous"));
  1.2967 + }
  1.2968 + 
  1.2969 + TEST_F(Parser, CFARARegs) {
  1.2970 +   EXPECT_CALL(mock_handler, CFARule("cfa expression")).WillOnce(Return());
  1.2971 +   EXPECT_CALL(mock_handler, RARule("ra expression")).WillOnce(Return());
  1.2972 +-  EXPECT_CALL(mock_handler, RegisterRule("galba", "praetorian"))
  1.2973 ++  EXPECT_CALL(mock_handler, RegisterRule(ToUniqueString("galba"), "praetorian"))
  1.2974 +       .WillOnce(Return());
  1.2975 +-  EXPECT_CALL(mock_handler, RegisterRule("otho", "vitellius"))
  1.2976 ++  EXPECT_CALL(mock_handler, RegisterRule(ToUniqueString("otho"), "vitellius"))
  1.2977 +       .WillOnce(Return());
  1.2978 +   EXPECT_TRUE(parser.Parse(".cfa: cfa expression .ra: ra expression "
  1.2979 +                     "galba: praetorian otho: vitellius"));
  1.2980 + }
  1.2981 + 
  1.2982 + TEST_F(Parser, Whitespace) {
  1.2983 +-  EXPECT_CALL(mock_handler, RegisterRule("r1", "r1 expression"))
  1.2984 ++  EXPECT_CALL(mock_handler, RegisterRule(ToUniqueString("r1"), "r1 expression"))
  1.2985 +       .WillOnce(Return());
  1.2986 +-  EXPECT_CALL(mock_handler, RegisterRule("r2", "r2 expression"))
  1.2987 ++  EXPECT_CALL(mock_handler, RegisterRule(ToUniqueString("r2"), "r2 expression"))
  1.2988 +       .WillOnce(Return());
  1.2989 +   EXPECT_TRUE(parser.Parse(" r1:\tr1\nexpression \tr2:\t\rr2\r\n "
  1.2990 +                            "expression  \n"));
  1.2991 + }
  1.2992 + 
  1.2993 + TEST_F(Parser, WhitespaceLoneColon) {
  1.2994 +   EXPECT_FALSE(parser.Parse("  \n:\t  "));
  1.2995 + }
  1.2996 + 
  1.2997 + TEST_F(Parser, EmptyName) {
  1.2998 +-  EXPECT_CALL(mock_handler, RegisterRule("reg", _))
  1.2999 ++  EXPECT_CALL(mock_handler, RegisterRule(ToUniqueString("reg"), _))
  1.3000 +       .Times(AtMost(1))
  1.3001 +       .WillRepeatedly(Return());
  1.3002 +   EXPECT_FALSE(parser.Parse("reg: expr1 : expr2"));
  1.3003 + }
  1.3004 + 
  1.3005 + TEST_F(Parser, RuleLoneColon) {
  1.3006 +-  EXPECT_CALL(mock_handler, RegisterRule("r1", "expr"))
  1.3007 ++  EXPECT_CALL(mock_handler, RegisterRule(ToUniqueString("r1"), "expr"))
  1.3008 +       .Times(AtMost(1))
  1.3009 +       .WillRepeatedly(Return());
  1.3010 +   EXPECT_FALSE(parser.Parse(" r1:   expr   :"));
  1.3011 + }
  1.3012 + 
  1.3013 + TEST_F(Parser, RegNoExprRule) {
  1.3014 +-  EXPECT_CALL(mock_handler, RegisterRule("r1", "expr"))
  1.3015 ++  EXPECT_CALL(mock_handler, RegisterRule(ToUniqueString("r1"), "expr"))
  1.3016 +       .Times(AtMost(1))
  1.3017 +       .WillRepeatedly(Return());
  1.3018 +   EXPECT_FALSE(parser.Parse("r0: r1:   expr"));
  1.3019 + }
  1.3020 + 
  1.3021 + class ParseHandlerFixture: public CFIFixture {
  1.3022 +  public:
  1.3023 +   ParseHandlerFixture() : CFIFixture(), handler(&cfi) { }
  1.3024 +   CFIFrameInfoParseHandler handler;
  1.3025 + };
  1.3026 + 
  1.3027 + class ParseHandler: public ParseHandlerFixture, public Test { };
  1.3028 + 
  1.3029 + TEST_F(ParseHandler, CFARARule) {
  1.3030 +   handler.CFARule("reg-for-cfa");
  1.3031 +   handler.RARule("reg-for-ra");
  1.3032 +-  registers["reg-for-cfa"] = 0x268a9a4a3821a797ULL;
  1.3033 +-  registers["reg-for-ra"] = 0x6301b475b8b91c02ULL;
  1.3034 ++  registers[ToUniqueString("reg-for-cfa")] = 0x268a9a4a3821a797ULL;
  1.3035 ++  registers[ToUniqueString("reg-for-ra")] = 0x6301b475b8b91c02ULL;
  1.3036 +   ASSERT_TRUE(cfi.FindCallerRegs<uint64_t>(registers, memory,
  1.3037 +                                             &caller_registers));
  1.3038 +-  ASSERT_EQ(0x268a9a4a3821a797ULL, caller_registers[".cfa"]);
  1.3039 +-  ASSERT_EQ(0x6301b475b8b91c02ULL, caller_registers[".ra"]);
  1.3040 ++  ASSERT_EQ(0x268a9a4a3821a797ULL, caller_registers[ustr__ZDcfa()]);
  1.3041 ++  ASSERT_EQ(0x6301b475b8b91c02ULL, caller_registers[ustr__ZDra()]);
  1.3042 + }
  1.3043 + 
  1.3044 + TEST_F(ParseHandler, RegisterRules) {
  1.3045 +   handler.CFARule("reg-for-cfa");
  1.3046 +   handler.RARule("reg-for-ra");
  1.3047 +-  handler.RegisterRule("reg1", "reg-for-reg1");
  1.3048 +-  handler.RegisterRule("reg2", "reg-for-reg2");
  1.3049 +-  registers["reg-for-cfa"] = 0x268a9a4a3821a797ULL;
  1.3050 +-  registers["reg-for-ra"] = 0x6301b475b8b91c02ULL;
  1.3051 +-  registers["reg-for-reg1"] = 0x06cde8e2ff062481ULL;
  1.3052 +-  registers["reg-for-reg2"] = 0xff0c4f76403173e2ULL;
  1.3053 ++  handler.RegisterRule(ToUniqueString("reg1"), "reg-for-reg1");
  1.3054 ++  handler.RegisterRule(ToUniqueString("reg2"), "reg-for-reg2");
  1.3055 ++  registers[ToUniqueString("reg-for-cfa")] = 0x268a9a4a3821a797ULL;
  1.3056 ++  registers[ToUniqueString("reg-for-ra")] = 0x6301b475b8b91c02ULL;
  1.3057 ++  registers[ToUniqueString("reg-for-reg1")] = 0x06cde8e2ff062481ULL;
  1.3058 ++  registers[ToUniqueString("reg-for-reg2")] = 0xff0c4f76403173e2ULL;
  1.3059 +   ASSERT_TRUE(cfi.FindCallerRegs<uint64_t>(registers, memory,
  1.3060 +                                             &caller_registers));
  1.3061 +-  ASSERT_EQ(0x268a9a4a3821a797ULL, caller_registers[".cfa"]);
  1.3062 +-  ASSERT_EQ(0x6301b475b8b91c02ULL, caller_registers[".ra"]);
  1.3063 +-  ASSERT_EQ(0x06cde8e2ff062481ULL, caller_registers["reg1"]);
  1.3064 +-  ASSERT_EQ(0xff0c4f76403173e2ULL, caller_registers["reg2"]);
  1.3065 ++  ASSERT_EQ(0x268a9a4a3821a797ULL, caller_registers[ustr__ZDcfa()]);
  1.3066 ++  ASSERT_EQ(0x6301b475b8b91c02ULL, caller_registers[ustr__ZDra()]);
  1.3067 ++  ASSERT_EQ(0x06cde8e2ff062481ULL, caller_registers[ToUniqueString("reg1")]);
  1.3068 ++  ASSERT_EQ(0xff0c4f76403173e2ULL, caller_registers[ToUniqueString("reg2")]);
  1.3069 + }
  1.3070 + 
  1.3071 + struct SimpleCFIWalkerFixture {
  1.3072 +   struct RawContext {
  1.3073 +     uint64_t r0, r1, r2, r3, r4, sp, pc;
  1.3074 +   };
  1.3075 +   enum Validity {
  1.3076 +     R0_VALID = 0x01,
  1.3077 +@@ -475,23 +493,23 @@
  1.3078 +   CFIFrameInfo call_frame_info;
  1.3079 +   CFIWalker walker;
  1.3080 +   MockMemoryRegion memory;
  1.3081 +   RawContext callee_context, caller_context;
  1.3082 + };
  1.3083 + 
  1.3084 + SimpleCFIWalkerFixture::CFIWalker::RegisterSet
  1.3085 + SimpleCFIWalkerFixture::register_map[7] = {
  1.3086 +-  { "r0", NULL,   true,  R0_VALID, &RawContext::r0 },
  1.3087 +-  { "r1", NULL,   true,  R1_VALID, &RawContext::r1 },
  1.3088 +-  { "r2", NULL,   false, R2_VALID, &RawContext::r2 },
  1.3089 +-  { "r3", NULL,   false, R3_VALID, &RawContext::r3 },
  1.3090 +-  { "r4", NULL,   true,  R4_VALID, &RawContext::r4 },
  1.3091 +-  { "sp", ".cfa", true,  SP_VALID, &RawContext::sp },
  1.3092 +-  { "pc", ".ra",  true,  PC_VALID, &RawContext::pc },
  1.3093 ++  { ToUniqueString("r0"), NULL,   true,  R0_VALID, &RawContext::r0 },
  1.3094 ++  { ToUniqueString("r1"), NULL,   true,  R1_VALID, &RawContext::r1 },
  1.3095 ++  { ToUniqueString("r2"), NULL,   false, R2_VALID, &RawContext::r2 },
  1.3096 ++  { ToUniqueString("r3"), NULL,   false, R3_VALID, &RawContext::r3 },
  1.3097 ++  { ToUniqueString("r4"), NULL,   true,  R4_VALID, &RawContext::r4 },
  1.3098 ++  { ToUniqueString("sp"), ustr__ZDcfa(), true,  SP_VALID, &RawContext::sp },
  1.3099 ++  { ToUniqueString("pc"), ustr__ZDra(),  true,  PC_VALID, &RawContext::pc },
  1.3100 + };
  1.3101 + 
  1.3102 + class SimpleWalker: public SimpleCFIWalkerFixture, public Test { };
  1.3103 + 
  1.3104 + TEST_F(SimpleWalker, Walk) {
  1.3105 +   // Stack_top is the current stack pointer, pointing to the lowest
  1.3106 +   // address of a frame that looks like this (all 64-bit words):
  1.3107 +   //
  1.3108 +@@ -516,18 +534,20 @@
  1.3109 +   // Saved return address.
  1.3110 +   EXPECT_CALL(memory,
  1.3111 +               GetMemoryAtAddress(stack_top + 16, A<uint64_t *>()))
  1.3112 +       .WillRepeatedly(DoAll(SetArgumentPointee<1>(0xba5ad6d9acce28deULL),
  1.3113 +                             Return(true)));
  1.3114 + 
  1.3115 +   call_frame_info.SetCFARule(Module::Expr("sp 24 +"));
  1.3116 +   call_frame_info.SetRARule(Module::Expr(".cfa 8 - ^"));
  1.3117 +-  call_frame_info.SetRegisterRule("r0", Module::Expr(".cfa 24 - ^"));
  1.3118 +-  call_frame_info.SetRegisterRule("r1", Module::Expr("r2"));
  1.3119 ++  call_frame_info.SetRegisterRule(ToUniqueString("r0"),
  1.3120 ++                                  Module::Expr(".cfa 24 - ^"));
  1.3121 ++  call_frame_info.SetRegisterRule(ToUniqueString("r1"),
  1.3122 ++                                  Module::Expr("r2"));
  1.3123 + 
  1.3124 +   callee_context.r0 = 0x94e030ca79edd119ULL;
  1.3125 +   callee_context.r1 = 0x937b4d7e95ce52d9ULL;
  1.3126 +   callee_context.r2 = 0x5fe0027416b8b62aULL; // caller's r1
  1.3127 +   // callee_context.r3 is not valid in callee.
  1.3128 +   // callee_context.r4 is not valid in callee.
  1.3129 +   callee_context.sp = stack_top;
  1.3130 +   callee_context.pc = 0x25b21b224311d280ULL;
  1.3131 +diff --git a/src/processor/fast_source_line_resolver_unittest.cc b/src/processor/fast_source_line_resolver_unittest.cc
  1.3132 +--- a/src/processor/fast_source_line_resolver_unittest.cc
  1.3133 ++++ b/src/processor/fast_source_line_resolver_unittest.cc
  1.3134 +@@ -51,25 +51,34 @@
  1.3135 + #include "processor/module_serializer.h"
  1.3136 + #include "processor/module_comparer.h"
  1.3137 + 
  1.3138 + namespace {
  1.3139 + 
  1.3140 + using google_breakpad::SourceLineResolverBase;
  1.3141 + using google_breakpad::BasicSourceLineResolver;
  1.3142 + using google_breakpad::FastSourceLineResolver;
  1.3143 ++using google_breakpad::FromUniqueString;
  1.3144 + using google_breakpad::ModuleSerializer;
  1.3145 + using google_breakpad::ModuleComparer;
  1.3146 + using google_breakpad::CFIFrameInfo;
  1.3147 + using google_breakpad::CodeModule;
  1.3148 + using google_breakpad::MemoryRegion;
  1.3149 + using google_breakpad::StackFrame;
  1.3150 ++using google_breakpad::ToUniqueString;
  1.3151 + using google_breakpad::WindowsFrameInfo;
  1.3152 + using google_breakpad::linked_ptr;
  1.3153 + using google_breakpad::scoped_ptr;
  1.3154 ++using google_breakpad::ustr__ZDcfa;
  1.3155 ++using google_breakpad::ustr__ZDra;
  1.3156 ++using google_breakpad::ustr__ZSebx;
  1.3157 ++using google_breakpad::ustr__ZSebp;
  1.3158 ++using google_breakpad::ustr__ZSedi;
  1.3159 ++using google_breakpad::ustr__ZSesi;
  1.3160 ++using google_breakpad::ustr__ZSesp;
  1.3161 + 
  1.3162 + class TestCodeModule : public CodeModule {
  1.3163 +  public:
  1.3164 +   explicit TestCodeModule(string code_file) : code_file_(code_file) {}
  1.3165 +   virtual ~TestCodeModule() {}
  1.3166 + 
  1.3167 +   virtual uint64_t base_address() const { return 0; }
  1.3168 +   virtual uint64_t size() const { return 0xb000; }
  1.3169 +@@ -119,34 +128,34 @@
  1.3170 + // association. (That is, ACTUAL's associations should be a subset of
  1.3171 + // EXPECTED's.) Also verify that ACTUAL has associations for ".ra" and
  1.3172 + // ".cfa".
  1.3173 + static bool VerifyRegisters(
  1.3174 +     const char *file, int line,
  1.3175 +     const CFIFrameInfo::RegisterValueMap<uint32_t> &expected,
  1.3176 +     const CFIFrameInfo::RegisterValueMap<uint32_t> &actual) {
  1.3177 +   CFIFrameInfo::RegisterValueMap<uint32_t>::const_iterator a;
  1.3178 +-  a = actual.find(".cfa");
  1.3179 ++  a = actual.find(ustr__ZDcfa());
  1.3180 +   if (a == actual.end())
  1.3181 +     return false;
  1.3182 +-  a = actual.find(".ra");
  1.3183 ++  a = actual.find(ustr__ZDra());
  1.3184 +   if (a == actual.end())
  1.3185 +     return false;
  1.3186 +   for (a = actual.begin(); a != actual.end(); a++) {
  1.3187 +     CFIFrameInfo::RegisterValueMap<uint32_t>::const_iterator e =
  1.3188 +       expected.find(a->first);
  1.3189 +     if (e == expected.end()) {
  1.3190 +       fprintf(stderr, "%s:%d: unexpected register '%s' recovered, value 0x%x\n",
  1.3191 +-              file, line, a->first.c_str(), a->second);
  1.3192 ++              file, line, FromUniqueString(a->first), a->second);
  1.3193 +       return false;
  1.3194 +     }
  1.3195 +     if (e->second != a->second) {
  1.3196 +       fprintf(stderr,
  1.3197 +               "%s:%d: register '%s' recovered value was 0x%x, expected 0x%x\n",
  1.3198 +-              file, line, a->first.c_str(), a->second, e->second);
  1.3199 ++              file, line, FromUniqueString(a->first), a->second, e->second);
  1.3200 +       return false;
  1.3201 +     }
  1.3202 +     // Don't complain if this doesn't recover all registers. Although
  1.3203 +     // the DWARF spec says that unmentioned registers are undefined,
  1.3204 +     // GCC uses omission to mean that they are unchanged.
  1.3205 +   }
  1.3206 +   return true;
  1.3207 + }
  1.3208 +@@ -282,81 +291,81 @@
  1.3209 + 
  1.3210 +   CFIFrameInfo::RegisterValueMap<uint32_t> current_registers;
  1.3211 +   CFIFrameInfo::RegisterValueMap<uint32_t> caller_registers;
  1.3212 +   CFIFrameInfo::RegisterValueMap<uint32_t> expected_caller_registers;
  1.3213 +   MockMemoryRegion memory;
  1.3214 + 
  1.3215 +   // Regardless of which instruction evaluation takes place at, it
  1.3216 +   // should produce the same values for the caller's registers.
  1.3217 +-  expected_caller_registers[".cfa"] = 0x1001c;
  1.3218 +-  expected_caller_registers[".ra"]  = 0xf6438648;
  1.3219 +-  expected_caller_registers["$ebp"] = 0x10038;
  1.3220 +-  expected_caller_registers["$ebx"] = 0x98ecadc3;
  1.3221 +-  expected_caller_registers["$esi"] = 0x878f7524;
  1.3222 +-  expected_caller_registers["$edi"] = 0x6312f9a5;
  1.3223 ++  expected_caller_registers[ustr__ZDcfa()] = 0x1001c;
  1.3224 ++  expected_caller_registers[ustr__ZDra()]  = 0xf6438648;
  1.3225 ++  expected_caller_registers[ustr__ZSebp()] = 0x10038;
  1.3226 ++  expected_caller_registers[ustr__ZSebx()] = 0x98ecadc3;
  1.3227 ++  expected_caller_registers[ustr__ZSesi()] = 0x878f7524;
  1.3228 ++  expected_caller_registers[ustr__ZSedi()] = 0x6312f9a5;
  1.3229 + 
  1.3230 +   frame.instruction = 0x3d40;
  1.3231 +   frame.module = &module1;
  1.3232 +   current_registers.clear();
  1.3233 +-  current_registers["$esp"] = 0x10018;
  1.3234 +-  current_registers["$ebp"] = 0x10038;
  1.3235 +-  current_registers["$ebx"] = 0x98ecadc3;
  1.3236 +-  current_registers["$esi"] = 0x878f7524;
  1.3237 +-  current_registers["$edi"] = 0x6312f9a5;
  1.3238 ++  current_registers[ustr__ZSesp()] = 0x10018;
  1.3239 ++  current_registers[ustr__ZSebp()] = 0x10038;
  1.3240 ++  current_registers[ustr__ZSebx()] = 0x98ecadc3;
  1.3241 ++  current_registers[ustr__ZSesi()] = 0x878f7524;
  1.3242 ++  current_registers[ustr__ZSedi()] = 0x6312f9a5;
  1.3243 +   cfi_frame_info.reset(fast_resolver.FindCFIFrameInfo(&frame));
  1.3244 +   ASSERT_TRUE(cfi_frame_info.get());
  1.3245 +   ASSERT_TRUE(cfi_frame_info.get()
  1.3246 +               ->FindCallerRegs<uint32_t>(current_registers, memory,
  1.3247 +                                           &caller_registers));
  1.3248 +   ASSERT_TRUE(VerifyRegisters(__FILE__, __LINE__,
  1.3249 +                               expected_caller_registers, caller_registers));
  1.3250 + 
  1.3251 +   frame.instruction = 0x3d41;
  1.3252 +-  current_registers["$esp"] = 0x10014;
  1.3253 ++  current_registers[ustr__ZSesp()] = 0x10014;
  1.3254 +   cfi_frame_info.reset(fast_resolver.FindCFIFrameInfo(&frame));
  1.3255 +   ASSERT_TRUE(cfi_frame_info.get());
  1.3256 +   ASSERT_TRUE(cfi_frame_info.get()
  1.3257 +               ->FindCallerRegs<uint32_t>(current_registers, memory,
  1.3258 +                                           &caller_registers));
  1.3259 +   ASSERT_TRUE(VerifyRegisters(__FILE__, __LINE__,
  1.3260 +                               expected_caller_registers, caller_registers));
  1.3261 + 
  1.3262 +   frame.instruction = 0x3d43;
  1.3263 +-  current_registers["$ebp"] = 0x10014;
  1.3264 ++  current_registers[ustr__ZSebp()] = 0x10014;
  1.3265 +   cfi_frame_info.reset(fast_resolver.FindCFIFrameInfo(&frame));
  1.3266 +   ASSERT_TRUE(cfi_frame_info.get());
  1.3267 +   ASSERT_TRUE(cfi_frame_info.get()
  1.3268 +               ->FindCallerRegs<uint32_t>(current_registers, memory,
  1.3269 +                                           &caller_registers));
  1.3270 +   VerifyRegisters(__FILE__, __LINE__,
  1.3271 +                   expected_caller_registers, caller_registers);
  1.3272 + 
  1.3273 +   frame.instruction = 0x3d54;
  1.3274 +-  current_registers["$ebx"] = 0x6864f054U;
  1.3275 ++  current_registers[ustr__ZSebx()] = 0x6864f054U;
  1.3276 +   cfi_frame_info.reset(fast_resolver.FindCFIFrameInfo(&frame));
  1.3277 +   ASSERT_TRUE(cfi_frame_info.get());
  1.3278 +   ASSERT_TRUE(cfi_frame_info.get()
  1.3279 +               ->FindCallerRegs<uint32_t>(current_registers, memory,
  1.3280 +                                           &caller_registers));
  1.3281 +   VerifyRegisters(__FILE__, __LINE__,
  1.3282 +                   expected_caller_registers, caller_registers);
  1.3283 + 
  1.3284 +   frame.instruction = 0x3d5a;
  1.3285 +-  current_registers["$esi"] = 0x6285f79aU;
  1.3286 ++  current_registers[ustr__ZSesi()] = 0x6285f79aU;
  1.3287 +   cfi_frame_info.reset(fast_resolver.FindCFIFrameInfo(&frame));
  1.3288 +   ASSERT_TRUE(cfi_frame_info.get());
  1.3289 +   ASSERT_TRUE(cfi_frame_info.get()
  1.3290 +               ->FindCallerRegs<uint32_t>(current_registers, memory,
  1.3291 +                                           &caller_registers));
  1.3292 +   VerifyRegisters(__FILE__, __LINE__,
  1.3293 +                   expected_caller_registers, caller_registers);
  1.3294 + 
  1.3295 +   frame.instruction = 0x3d84;
  1.3296 +-  current_registers["$edi"] = 0x64061449U;
  1.3297 ++  current_registers[ustr__ZSedi()] = 0x64061449U;
  1.3298 +   cfi_frame_info.reset(fast_resolver.FindCFIFrameInfo(&frame));
  1.3299 +   ASSERT_TRUE(cfi_frame_info.get());
  1.3300 +   ASSERT_TRUE(cfi_frame_info.get()
  1.3301 +               ->FindCallerRegs<uint32_t>(current_registers, memory,
  1.3302 +                                           &caller_registers));
  1.3303 +   VerifyRegisters(__FILE__, __LINE__,
  1.3304 +                   expected_caller_registers, caller_registers);
  1.3305 + 
  1.3306 +diff --git a/src/processor/postfix_evaluator-inl.h b/src/processor/postfix_evaluator-inl.h
  1.3307 +--- a/src/processor/postfix_evaluator-inl.h
  1.3308 ++++ b/src/processor/postfix_evaluator-inl.h
  1.3309 +@@ -51,23 +51,25 @@
  1.3310 + namespace google_breakpad {
  1.3311 + 
  1.3312 + using std::istringstream;
  1.3313 + using std::ostringstream;
  1.3314 + 
  1.3315 + 
  1.3316 + // A small class used in Evaluate to make sure to clean up the stack
  1.3317 + // before returning failure.
  1.3318 ++template<typename ValueType>
  1.3319 + class AutoStackClearer {
  1.3320 +  public:
  1.3321 +-  explicit AutoStackClearer(vector<string> *stack) : stack_(stack) {}
  1.3322 ++  explicit AutoStackClearer(vector<StackElem<ValueType> > *stack)
  1.3323 ++    : stack_(stack) {}
  1.3324 +   ~AutoStackClearer() { stack_->clear(); }
  1.3325 + 
  1.3326 +  private:
  1.3327 +-  vector<string> *stack_;
  1.3328 ++  vector<StackElem<ValueType> > *stack_;
  1.3329 + };
  1.3330 + 
  1.3331 + 
  1.3332 + template<typename ValueType>
  1.3333 + bool PostfixEvaluator<ValueType>::EvaluateToken(
  1.3334 +     const string &token,
  1.3335 +     const string &expression,
  1.3336 +     DictionaryValidityType *assigned) {
  1.3337 +@@ -170,38 +172,57 @@
  1.3338 +       BPLOG(INFO) << "Could not PopValue to get value to assign: " <<
  1.3339 +                      expression;
  1.3340 +       return false;
  1.3341 +     }
  1.3342 + 
  1.3343 +     // Assignment is only meaningful when assigning into an identifier.
  1.3344 +     // The identifier must name a variable, not a constant.  Variables
  1.3345 +     // begin with '$'.
  1.3346 +-    string identifier;
  1.3347 ++    const UniqueString* identifier;
  1.3348 +     if (PopValueOrIdentifier(NULL, &identifier) != POP_RESULT_IDENTIFIER) {
  1.3349 +       BPLOG(ERROR) << "PopValueOrIdentifier returned a value, but an "
  1.3350 +                       "identifier is needed to assign " <<
  1.3351 +                       HexString(value) << ": " << expression;
  1.3352 +       return false;
  1.3353 +     }
  1.3354 +-    if (identifier.empty() || identifier[0] != '$') {
  1.3355 ++    if (identifier == ustr__empty() || Index(identifier,0) != '$') {
  1.3356 +       BPLOG(ERROR) << "Can't assign " << HexString(value) << " to " <<
  1.3357 +                       identifier << ": " << expression;
  1.3358 +       return false;
  1.3359 +     }
  1.3360 + 
  1.3361 +     (*dictionary_)[identifier] = value;
  1.3362 +     if (assigned)
  1.3363 +       (*assigned)[identifier] = true;
  1.3364 +   } else {
  1.3365 +-    // The token is not an operator, it's a literal value or an identifier.
  1.3366 +-    // Push it onto the stack as-is.  Use push_back instead of PushValue
  1.3367 +-    // because PushValue pushes ValueType as a string, but token is already
  1.3368 +-    // a string.
  1.3369 +-    stack_.push_back(token);
  1.3370 ++    // Push it onto the stack as-is, but first convert it either to a
  1.3371 ++    // ValueType (if a literal) or to a UniqueString* (if an identifier).
  1.3372 ++    //
  1.3373 ++    // First, try to treat the value as a literal. Literals may have leading
  1.3374 ++    // '-' sign, and the entire remaining string must be parseable as
  1.3375 ++    // ValueType. If this isn't possible, it can't be a literal, so treat it
  1.3376 ++    // as an identifier instead.
  1.3377 ++    //
  1.3378 ++    // Some versions of the libstdc++, the GNU standard C++ library, have
  1.3379 ++    // stream extractors for unsigned integer values that permit a leading
  1.3380 ++    // '-' sign (6.0.13); others do not (6.0.9). Since we require it, we
  1.3381 ++    // handle it explicitly here.
  1.3382 ++    istringstream token_stream(token);
  1.3383 ++    ValueType literal = ValueType();
  1.3384 ++    bool negative = false;
  1.3385 ++    if (token_stream.peek() == '-') {
  1.3386 ++      negative = true;
  1.3387 ++      token_stream.get();
  1.3388 ++    }
  1.3389 ++    if (token_stream >> literal && token_stream.peek() == EOF) {
  1.3390 ++      PushValue(negative ? (-literal) : literal);
  1.3391 ++    } else {
  1.3392 ++      PushIdentifier(ToUniqueString(token));
  1.3393 ++    }
  1.3394 +   }
  1.3395 +   return true;
  1.3396 + }
  1.3397 + 
  1.3398 + template<typename ValueType>
  1.3399 + bool PostfixEvaluator<ValueType>::EvaluateInternal(
  1.3400 +     const string &expression,
  1.3401 +     DictionaryValidityType *assigned) {
  1.3402 +@@ -236,17 +257,17 @@
  1.3403 +   // The expression is being exevaluated only for its side effects.  Skip
  1.3404 +   // expressions that denote values only.
  1.3405 +   if (expr.how_ != Module::kExprPostfix) {
  1.3406 +     BPLOG(ERROR) << "Can't evaluate for side-effects: " << expr;
  1.3407 +     return false;
  1.3408 +   }
  1.3409 + 
  1.3410 +   // Ensure that the stack is cleared before returning.
  1.3411 +-  AutoStackClearer clearer(&stack_);
  1.3412 ++  AutoStackClearer<ValueType> clearer(&stack_);
  1.3413 + 
  1.3414 +   if (!EvaluateInternal(expr.postfix_, assigned))
  1.3415 +     return false;
  1.3416 + 
  1.3417 +   // If there's anything left on the stack, it indicates incomplete execution.
  1.3418 +   // This is a failure case.  If the stack is empty, evalution was complete
  1.3419 +   // and successful.
  1.3420 +   if (stack_.empty())
  1.3421 +@@ -260,17 +281,17 @@
  1.3422 + bool PostfixEvaluator<ValueType>::EvaluateForValue(const Module::Expr& expr,
  1.3423 +                                                    ValueType* result) {
  1.3424 +   switch (expr.how_) {
  1.3425 + 
  1.3426 +     // Postfix expression.  Give to the evaluator and return the
  1.3427 +     // one-and-only stack element that should be left over.
  1.3428 +     case Module::kExprPostfix: {
  1.3429 +       // Ensure that the stack is cleared before returning.
  1.3430 +-      AutoStackClearer clearer(&stack_);
  1.3431 ++      AutoStackClearer<ValueType> clearer(&stack_);
  1.3432 + 
  1.3433 +       if (!EvaluateInternal(expr.postfix_, NULL))
  1.3434 +         return false;
  1.3435 + 
  1.3436 +       // A successful execution should leave exactly one value on the stack.
  1.3437 +       if (stack_.size() != 1) {
  1.3438 +         BPLOG(ERROR) << "Expression yielded bad number of results: "
  1.3439 +                      << "'" << expr << "'";
  1.3440 +@@ -314,77 +335,56 @@
  1.3441 +       return false;
  1.3442 +   }
  1.3443 + }
  1.3444 + 
  1.3445 + 
  1.3446 + template<typename ValueType>
  1.3447 + typename PostfixEvaluator<ValueType>::PopResult
  1.3448 + PostfixEvaluator<ValueType>::PopValueOrIdentifier(
  1.3449 +-    ValueType *value, string *identifier) {
  1.3450 ++    ValueType *value, const UniqueString** identifier) {
  1.3451 +   // There needs to be at least one element on the stack to pop.
  1.3452 +   if (!stack_.size())
  1.3453 +     return POP_RESULT_FAIL;
  1.3454 + 
  1.3455 +-  string token = stack_.back();
  1.3456 ++  StackElem<ValueType> el = stack_.back();
  1.3457 +   stack_.pop_back();
  1.3458 + 
  1.3459 +-  // First, try to treat the value as a literal. Literals may have leading
  1.3460 +-  // '-' sign, and the entire remaining string must be parseable as
  1.3461 +-  // ValueType. If this isn't possible, it can't be a literal, so treat it
  1.3462 +-  // as an identifier instead.
  1.3463 +-  //
  1.3464 +-  // Some versions of the libstdc++, the GNU standard C++ library, have
  1.3465 +-  // stream extractors for unsigned integer values that permit a leading
  1.3466 +-  // '-' sign (6.0.13); others do not (6.0.9). Since we require it, we
  1.3467 +-  // handle it explicitly here.
  1.3468 +-  istringstream token_stream(token);
  1.3469 +-  ValueType literal = ValueType();
  1.3470 +-  bool negative;
  1.3471 +-  if (token_stream.peek() == '-') {
  1.3472 +-    negative = true;
  1.3473 +-    token_stream.get();
  1.3474 +-  } else {
  1.3475 +-    negative = false;
  1.3476 +-  }
  1.3477 +-  if (token_stream >> literal && token_stream.peek() == EOF) {
  1.3478 +-    if (value) {
  1.3479 +-      *value = literal;
  1.3480 +-    }
  1.3481 +-    if (negative)
  1.3482 +-      *value = -*value;
  1.3483 ++  if (el.isValue) {
  1.3484 ++    if (value)
  1.3485 ++      *value = el.u.val;
  1.3486 +     return POP_RESULT_VALUE;
  1.3487 +   } else {
  1.3488 +-    if (identifier) {
  1.3489 +-      *identifier = token;
  1.3490 +-    }
  1.3491 ++    if (identifier)
  1.3492 ++      *identifier = el.u.ustr;
  1.3493 +     return POP_RESULT_IDENTIFIER;
  1.3494 +   }
  1.3495 + }
  1.3496 + 
  1.3497 + 
  1.3498 + template<typename ValueType>
  1.3499 + bool PostfixEvaluator<ValueType>::PopValue(ValueType *value) {
  1.3500 +   ValueType literal = ValueType();
  1.3501 +-  string token;
  1.3502 ++  const UniqueString* token;
  1.3503 +   PopResult result;
  1.3504 +   if ((result = PopValueOrIdentifier(&literal, &token)) == POP_RESULT_FAIL) {
  1.3505 +     return false;
  1.3506 +   } else if (result == POP_RESULT_VALUE) {
  1.3507 +     // This is the easy case.
  1.3508 +     *value = literal;
  1.3509 +   } else {  // result == POP_RESULT_IDENTIFIER
  1.3510 +     // There was an identifier at the top of the stack.  Resolve it to a
  1.3511 +     // value by looking it up in the dictionary.
  1.3512 +     typename DictionaryType::const_iterator iterator =
  1.3513 +         dictionary_->find(token);
  1.3514 +     if (iterator == dictionary_->end()) {
  1.3515 +       // The identifier wasn't found in the dictionary.  Don't imply any
  1.3516 +       // default value, just fail.
  1.3517 +-      BPLOG(INFO) << "Identifier " << token << " not in dictionary";
  1.3518 ++      BPLOG(INFO) << "Identifier " << FromUniqueString(token)
  1.3519 ++                  << " not in dictionary";
  1.3520 +       return false;
  1.3521 +     }
  1.3522 + 
  1.3523 +     *value = iterator->second;
  1.3524 +   }
  1.3525 + 
  1.3526 +   return true;
  1.3527 + }
  1.3528 +@@ -394,18 +394,23 @@
  1.3529 + bool PostfixEvaluator<ValueType>::PopValues(ValueType *value1,
  1.3530 +                                             ValueType *value2) {
  1.3531 +   return PopValue(value2) && PopValue(value1);
  1.3532 + }
  1.3533 + 
  1.3534 + 
  1.3535 + template<typename ValueType>
  1.3536 + void PostfixEvaluator<ValueType>::PushValue(const ValueType &value) {
  1.3537 +-  ostringstream token_stream;
  1.3538 +-  token_stream << value;
  1.3539 +-  stack_.push_back(token_stream.str());
  1.3540 ++  StackElem<ValueType> el(value);
  1.3541 ++  stack_.push_back(el);
  1.3542 ++}
  1.3543 ++
  1.3544 ++template<typename ValueType>
  1.3545 ++void PostfixEvaluator<ValueType>::PushIdentifier(const UniqueString* str) {
  1.3546 ++  StackElem<ValueType> el(str);
  1.3547 ++  stack_.push_back(el);
  1.3548 + }
  1.3549 + 
  1.3550 + 
  1.3551 + }  // namespace google_breakpad
  1.3552 + 
  1.3553 + 
  1.3554 + #endif  // PROCESSOR_POSTFIX_EVALUATOR_INL_H__
  1.3555 +diff --git a/src/processor/postfix_evaluator.h b/src/processor/postfix_evaluator.h
  1.3556 +--- a/src/processor/postfix_evaluator.h
  1.3557 ++++ b/src/processor/postfix_evaluator.h
  1.3558 +@@ -70,30 +70,41 @@
  1.3559 + #define PROCESSOR_POSTFIX_EVALUATOR_H__
  1.3560 + 
  1.3561 + 
  1.3562 + #include <map>
  1.3563 + #include <string>
  1.3564 + #include <vector>
  1.3565 + 
  1.3566 + #include "common/using_std_string.h"
  1.3567 ++#include "common/unique_string.h"
  1.3568 + #include "common/module.h"
  1.3569 + 
  1.3570 + namespace google_breakpad {
  1.3571 + 
  1.3572 + using std::map;
  1.3573 + using std::vector;
  1.3574 + 
  1.3575 + class MemoryRegion;
  1.3576 + 
  1.3577 ++// A union type for elements in the postfix evaluator's stack.
  1.3578 ++template<typename ValueType>
  1.3579 ++class StackElem {
  1.3580 ++ public:
  1.3581 ++  StackElem(ValueType val) { isValue = true; u.val = val; }
  1.3582 ++  StackElem(const UniqueString* ustr) { isValue = false; u.ustr = ustr; }
  1.3583 ++  bool isValue;
  1.3584 ++  union { ValueType val; const UniqueString* ustr; } u;
  1.3585 ++};
  1.3586 ++
  1.3587 + template<typename ValueType>
  1.3588 + class PostfixEvaluator {
  1.3589 +  public:
  1.3590 +-  typedef map<string, ValueType> DictionaryType;
  1.3591 +-  typedef map<string, bool> DictionaryValidityType;
  1.3592 ++  typedef map<const UniqueString*, ValueType> DictionaryType;
  1.3593 ++  typedef map<const UniqueString*, bool> DictionaryValidityType;
  1.3594 + 
  1.3595 +   // Create a PostfixEvaluator object that may be used (with Evaluate) on
  1.3596 +   // one or more expressions.  PostfixEvaluator does not take ownership of
  1.3597 +   // either argument.  |memory| may be NULL, in which case dereferencing
  1.3598 +   // (^) will not be supported.  |dictionary| may be NULL, but evaluation
  1.3599 +   // will fail in that case unless set_dictionary is used before calling
  1.3600 +   // Evaluate.
  1.3601 +   PostfixEvaluator(DictionaryType *dictionary, const MemoryRegion *memory)
  1.3602 +@@ -128,24 +139,28 @@
  1.3603 +   };
  1.3604 + 
  1.3605 +   // Retrieves the topmost literal value, constant, or variable from the
  1.3606 +   // stack.  Returns POP_RESULT_VALUE if the topmost entry is a literal
  1.3607 +   // value, and sets |value| accordingly.  Returns POP_RESULT_IDENTIFIER
  1.3608 +   // if the topmost entry is a constant or variable identifier, and sets
  1.3609 +   // |identifier| accordingly.  Returns POP_RESULT_FAIL on failure, such
  1.3610 +   // as when the stack is empty.
  1.3611 +-  PopResult PopValueOrIdentifier(ValueType *value, string *identifier);
  1.3612 ++  PopResult PopValueOrIdentifier(ValueType *value,
  1.3613 ++                                 const UniqueString** identifier);
  1.3614 + 
  1.3615 +   // Retrieves the topmost value on the stack.  If the topmost entry is
  1.3616 +   // an identifier, the dictionary is queried for the identifier's value.
  1.3617 +   // Returns false on failure, such as when the stack is empty or when
  1.3618 +   // a nonexistent identifier is named.
  1.3619 +   bool PopValue(ValueType *value);
  1.3620 + 
  1.3621 ++  // Pushes a UniqueString* on the stack.
  1.3622 ++  void PushIdentifier(const UniqueString* ustr);
  1.3623 ++
  1.3624 +   // Retrieves the top two values on the stack, in the style of PopValue.
  1.3625 +   // value2 is popped before value1, so that value1 corresponds to the
  1.3626 +   // entry that was pushed prior to value2.  Returns false on failure.
  1.3627 +   bool PopValues(ValueType *value1, ValueType *value2);
  1.3628 + 
  1.3629 +   // Pushes a new value onto the stack.
  1.3630 +   void PushValue(const ValueType &value);
  1.3631 + 
  1.3632 +@@ -166,15 +181,15 @@
  1.3633 + 
  1.3634 +   // If non-NULL, the MemoryRegion used for dereference (^) operations.
  1.3635 +   // If NULL, dereferencing is unsupported and will fail.  Weak pointer.
  1.3636 +   const MemoryRegion *memory_;
  1.3637 + 
  1.3638 +   // The stack contains state information as execution progresses.  Values
  1.3639 +   // are pushed on to it as the expression string is read and as operations
  1.3640 +   // yield values; values are popped when used as operands to operators.
  1.3641 +-  vector<string> stack_;
  1.3642 ++  vector<StackElem<ValueType> > stack_;
  1.3643 + };
  1.3644 + 
  1.3645 + }  // namespace google_breakpad
  1.3646 + 
  1.3647 + 
  1.3648 + #endif  // PROCESSOR_POSTFIX_EVALUATOR_H__
  1.3649 +diff --git a/src/processor/postfix_evaluator_unittest.cc b/src/processor/postfix_evaluator_unittest.cc
  1.3650 +--- a/src/processor/postfix_evaluator_unittest.cc
  1.3651 ++++ b/src/processor/postfix_evaluator_unittest.cc
  1.3652 +@@ -43,18 +43,32 @@
  1.3653 + #include "google_breakpad/processor/memory_region.h"
  1.3654 + #include "processor/logging.h"
  1.3655 + 
  1.3656 + 
  1.3657 + namespace {
  1.3658 + 
  1.3659 + 
  1.3660 + using std::map;
  1.3661 ++using google_breakpad::FromUniqueString;
  1.3662 + using google_breakpad::MemoryRegion;
  1.3663 + using google_breakpad::PostfixEvaluator;
  1.3664 ++using google_breakpad::ToUniqueString;
  1.3665 ++using google_breakpad::UniqueString;
  1.3666 ++using google_breakpad::ustr__ZDcbParams;
  1.3667 ++using google_breakpad::ustr__ZDcbSavedRegs;
  1.3668 ++using google_breakpad::ustr__ZDcfa;
  1.3669 ++using google_breakpad::ustr__ZDra;
  1.3670 ++using google_breakpad::ustr__ZDraSearchStart;
  1.3671 ++using google_breakpad::ustr__ZSebx;
  1.3672 ++using google_breakpad::ustr__ZSebp;
  1.3673 ++using google_breakpad::ustr__ZSedi;
  1.3674 ++using google_breakpad::ustr__ZSeip;
  1.3675 ++using google_breakpad::ustr__ZSesi;
  1.3676 ++using google_breakpad::ustr__ZSesp;
  1.3677 + 
  1.3678 + 
  1.3679 + // FakeMemoryRegion is used to test PostfixEvaluator's dereference (^)
  1.3680 + // operator.  The result of dereferencing a value is one greater than
  1.3681 + // the value.
  1.3682 + class FakeMemoryRegion : public MemoryRegion {
  1.3683 +  public:
  1.3684 +   virtual uint64_t GetBase() const { return 0; }
  1.3685 +@@ -95,17 +109,17 @@
  1.3686 +   // The list of tests.
  1.3687 +   const EvaluateTest *evaluate_tests;
  1.3688 + 
  1.3689 +   // The number of tests.
  1.3690 +   unsigned int evaluate_test_count;
  1.3691 + 
  1.3692 +   // Identifiers and their expected values upon completion of the Evaluate
  1.3693 +   // tests in the set.
  1.3694 +-  map<string, unsigned int> *validate_data;
  1.3695 ++  map<const UniqueString*, unsigned int> *validate_data;
  1.3696 + };
  1.3697 + 
  1.3698 + 
  1.3699 + struct EvaluateForValueTest {
  1.3700 +   // Expression passed to PostfixEvaluator::Evaluate.
  1.3701 +   const string expression;
  1.3702 +   
  1.3703 +   // True if the expression is expected to be evaluable, false if evaluation
  1.3704 +@@ -147,39 +161,39 @@
  1.3705 +     { "$rMul 9 6 * =",     true },   // $rMul = 9 * 6 = 54
  1.3706 +     { "$rSub 9 6 - =",     true },   // $rSub = 9 - 6 = 3
  1.3707 +     { "$rDivQ 9 6 / =",    true },   // $rDivQ = 9 / 6 = 1
  1.3708 +     { "$rDivM 9 6 % =",    true },   // $rDivM = 9 % 6 = 3
  1.3709 +     { "$rDeref 9 ^ =",     true },   // $rDeref = ^9 = 10 (FakeMemoryRegion)
  1.3710 +     { "$rAlign 36 8 @ =",  true },   // $rAlign = 36 @ 8
  1.3711 +     { "$rAdd3 2 2 + =$rMul2 9 6 * =", true } // smashed-equals tokenization
  1.3712 +   };
  1.3713 +-  map<string, unsigned int> validate_data_0;
  1.3714 +-  validate_data_0["$rAdd"]   = 8;
  1.3715 +-  validate_data_0["$rAdd2"]  = 4;
  1.3716 +-  validate_data_0["$rSub"]   = 3;
  1.3717 +-  validate_data_0["$rMul"]   = 54;
  1.3718 +-  validate_data_0["$rDivQ"]  = 1;
  1.3719 +-  validate_data_0["$rDivM"]  = 3;
  1.3720 +-  validate_data_0["$rDeref"] = 10;
  1.3721 +-  validate_data_0["$rAlign"] = 32;
  1.3722 +-  validate_data_0["$rAdd3"]  = 4;
  1.3723 +-  validate_data_0["$rMul2"]  = 54;
  1.3724 ++  map<const UniqueString*, unsigned int> validate_data_0;
  1.3725 ++  validate_data_0[ToUniqueString("$rAdd")]   = 8;
  1.3726 ++  validate_data_0[ToUniqueString("$rAdd2")]  = 4;
  1.3727 ++  validate_data_0[ToUniqueString("$rSub")]   = 3;
  1.3728 ++  validate_data_0[ToUniqueString("$rMul")]   = 54;
  1.3729 ++  validate_data_0[ToUniqueString("$rDivQ")]  = 1;
  1.3730 ++  validate_data_0[ToUniqueString("$rDivM")]  = 3;
  1.3731 ++  validate_data_0[ToUniqueString("$rDeref")] = 10;
  1.3732 ++  validate_data_0[ToUniqueString("$rAlign")] = 32;
  1.3733 ++  validate_data_0[ToUniqueString("$rAdd3")]  = 4;
  1.3734 ++  validate_data_0[ToUniqueString("$rMul2")]  = 54;
  1.3735 + 
  1.3736 +   // The second test set simulates a couple of MSVC program strings.
  1.3737 +   // The data is fudged a little bit because the tests use FakeMemoryRegion
  1.3738 +   // instead of a real stack snapshot, but the program strings are real and
  1.3739 +   // the implementation doesn't know or care that the data is not real.
  1.3740 +   PostfixEvaluator<unsigned int>::DictionaryType dictionary_1;
  1.3741 +-  dictionary_1["$ebp"] = 0xbfff0010;
  1.3742 +-  dictionary_1["$eip"] = 0x10000000;
  1.3743 +-  dictionary_1["$esp"] = 0xbfff0000;
  1.3744 +-  dictionary_1[".cbSavedRegs"] = 4;
  1.3745 +-  dictionary_1[".cbParams"] = 4;
  1.3746 +-  dictionary_1[".raSearchStart"] = 0xbfff0020;
  1.3747 ++  dictionary_1[ustr__ZSebp()] = 0xbfff0010;
  1.3748 ++  dictionary_1[ustr__ZSeip()] = 0x10000000;
  1.3749 ++  dictionary_1[ustr__ZSesp()] = 0xbfff0000;
  1.3750 ++  dictionary_1[ustr__ZDcbSavedRegs()] = 4;
  1.3751 ++  dictionary_1[ustr__ZDcbParams()] = 4;
  1.3752 ++  dictionary_1[ustr__ZDraSearchStart()] = 0xbfff0020;
  1.3753 +   const EvaluateTest evaluate_tests_1[] = {
  1.3754 +     { "$T0 $ebp = $eip $T0 4 + ^ = $ebp $T0 ^ = $esp $T0 8 + = "
  1.3755 +       "$L $T0 .cbSavedRegs - = $P $T0 8 + .cbParams + =", true },
  1.3756 +     // Intermediate state: $T0  = 0xbfff0010, $eip = 0xbfff0015,
  1.3757 +     //                     $ebp = 0xbfff0011, $esp = 0xbfff0018,
  1.3758 +     //                     $L   = 0xbfff000c, $P   = 0xbfff001c
  1.3759 +     { "$T0 $ebp = $eip $T0 4 + ^ = $ebp $T0 ^ = $esp $T0 8 + = "
  1.3760 +       "$L $T0 .cbSavedRegs - = $P $T0 8 + .cbParams + = $ebx $T0 28 - ^ =",
  1.3761 +@@ -188,28 +202,28 @@
  1.3762 +     //                     $ebp = 0xbfff0012, $esp = 0xbfff0019,
  1.3763 +     //                     $L   = 0xbfff000d, $P   = 0xbfff001d,
  1.3764 +     //                     $ebx = 0xbffefff6
  1.3765 +     { "$T0 $ebp = $T2 $esp = $T1 .raSearchStart = $eip $T1 ^ = $ebp $T0 = "
  1.3766 +       "$esp $T1 4 + = $L $T0 .cbSavedRegs - = $P $T1 4 + .cbParams + = "
  1.3767 +       "$ebx $T0 28 - ^ =",
  1.3768 +       true }
  1.3769 +   };
  1.3770 +-  map<string, unsigned int> validate_data_1;
  1.3771 +-  validate_data_1["$T0"]  = 0xbfff0012;
  1.3772 +-  validate_data_1["$T1"]  = 0xbfff0020;
  1.3773 +-  validate_data_1["$T2"]  = 0xbfff0019;
  1.3774 +-  validate_data_1["$eip"] = 0xbfff0021;
  1.3775 +-  validate_data_1["$ebp"] = 0xbfff0012;
  1.3776 +-  validate_data_1["$esp"] = 0xbfff0024;
  1.3777 +-  validate_data_1["$L"]   = 0xbfff000e;
  1.3778 +-  validate_data_1["$P"]   = 0xbfff0028;
  1.3779 +-  validate_data_1["$ebx"] = 0xbffefff7;
  1.3780 +-  validate_data_1[".cbSavedRegs"] = 4;
  1.3781 +-  validate_data_1[".cbParams"] = 4;
  1.3782 ++  map<const UniqueString*, unsigned int> validate_data_1;
  1.3783 ++  validate_data_1[ToUniqueString("$T0")]  = 0xbfff0012;
  1.3784 ++  validate_data_1[ToUniqueString("$T1")]  = 0xbfff0020;
  1.3785 ++  validate_data_1[ToUniqueString("$T2")]  = 0xbfff0019;
  1.3786 ++  validate_data_1[ustr__ZSeip()] = 0xbfff0021;
  1.3787 ++  validate_data_1[ustr__ZSebp()] = 0xbfff0012;
  1.3788 ++  validate_data_1[ustr__ZSesp()] = 0xbfff0024;
  1.3789 ++  validate_data_1[ToUniqueString("$L")]   = 0xbfff000e;
  1.3790 ++  validate_data_1[ToUniqueString("$P")]   = 0xbfff0028;
  1.3791 ++  validate_data_1[ustr__ZSebx()] = 0xbffefff7;
  1.3792 ++  validate_data_1[ustr__ZDcbSavedRegs()] = 4;
  1.3793 ++  validate_data_1[ustr__ZDcbParams()] = 4;
  1.3794 + 
  1.3795 +   EvaluateTestSet evaluate_test_sets[] = {
  1.3796 +     { &dictionary_0, evaluate_tests_0,
  1.3797 +           sizeof(evaluate_tests_0) / sizeof(EvaluateTest), &validate_data_0 },
  1.3798 +     { &dictionary_1, evaluate_tests_1,
  1.3799 +           sizeof(evaluate_tests_1) / sizeof(EvaluateTest), &validate_data_1 },
  1.3800 +   };
  1.3801 + 
  1.3802 +@@ -251,97 +265,100 @@
  1.3803 +                 evaluate_test->expression.c_str(),
  1.3804 +                 evaluate_test->evaluable ? "evaluable" : "not evaluable",
  1.3805 +                 result ? "evaluted" : "not evaluated");
  1.3806 +         return false;
  1.3807 +       }
  1.3808 +     }
  1.3809 + 
  1.3810 +     // Validate the results.
  1.3811 +-    for (map<string, unsigned int>::const_iterator validate_iterator =
  1.3812 ++    for (map<const UniqueString*, unsigned int>::const_iterator
  1.3813 ++            validate_iterator =
  1.3814 +             evaluate_test_set->validate_data->begin();
  1.3815 +         validate_iterator != evaluate_test_set->validate_data->end();
  1.3816 +         ++validate_iterator) {
  1.3817 +-      const string identifier = validate_iterator->first;
  1.3818 ++      const UniqueString* identifier = validate_iterator->first;
  1.3819 +       unsigned int expected_value = validate_iterator->second;
  1.3820 + 
  1.3821 +-      map<string, unsigned int>::const_iterator dictionary_iterator =
  1.3822 ++      map<const UniqueString*, unsigned int>::const_iterator
  1.3823 ++          dictionary_iterator =
  1.3824 +           evaluate_test_set->dictionary->find(identifier);
  1.3825 + 
  1.3826 +       // The identifier must exist in the dictionary.
  1.3827 +       if (dictionary_iterator == evaluate_test_set->dictionary->end()) {
  1.3828 +         fprintf(stderr, "FAIL: evaluate test set %d/%d, "
  1.3829 +                         "validate identifier \"%s\", "
  1.3830 +                         "expected %d, observed not found\n",
  1.3831 +                 evaluate_test_set_index, evaluate_test_set_count,
  1.3832 +-                identifier.c_str(), expected_value);
  1.3833 ++                FromUniqueString(identifier), expected_value);
  1.3834 +         return false;
  1.3835 +       }
  1.3836 + 
  1.3837 +       // The value in the dictionary must be the same as the expected value.
  1.3838 +       unsigned int observed_value = dictionary_iterator->second;
  1.3839 +       if (expected_value != observed_value) {
  1.3840 +         fprintf(stderr, "FAIL: evaluate test set %d/%d, "
  1.3841 +                         "validate identifier \"%s\", "
  1.3842 +                         "expected %d, observed %d\n",
  1.3843 +                 evaluate_test_set_index, evaluate_test_set_count,
  1.3844 +-                identifier.c_str(), expected_value, observed_value);
  1.3845 ++                FromUniqueString(identifier), expected_value, observed_value);
  1.3846 +         return false;
  1.3847 +       }
  1.3848 + 
  1.3849 +       // The value must be set in the "assigned" dictionary if it was a
  1.3850 +       // variable.  It must not have been assigned if it was a constant.
  1.3851 +-      bool expected_assigned = identifier[0] == '$';
  1.3852 ++      bool expected_assigned = FromUniqueString(identifier)[0] == '$';
  1.3853 +       bool observed_assigned = false;
  1.3854 +       PostfixEvaluator<unsigned int>::DictionaryValidityType::const_iterator
  1.3855 +           iterator_assigned = assigned.find(identifier);
  1.3856 +       if (iterator_assigned != assigned.end()) {
  1.3857 +         observed_assigned = iterator_assigned->second;
  1.3858 +       }
  1.3859 +       if (expected_assigned != observed_assigned) {
  1.3860 +         fprintf(stderr, "FAIL: evaluate test set %d/%d, "
  1.3861 +                         "validate assignment of \"%s\", "
  1.3862 +                         "expected %d, observed %d\n",
  1.3863 +                 evaluate_test_set_index, evaluate_test_set_count,
  1.3864 +-                identifier.c_str(), expected_assigned, observed_assigned);
  1.3865 ++                FromUniqueString(identifier), expected_assigned,
  1.3866 ++                observed_assigned);
  1.3867 +         return false;
  1.3868 +       }
  1.3869 +     }
  1.3870 +   }
  1.3871 + 
  1.3872 +   // EvaluateForValue tests.
  1.3873 +   PostfixEvaluator<unsigned int>::DictionaryType dictionary_2;
  1.3874 +-  dictionary_2["$ebp"] = 0xbfff0010;
  1.3875 +-  dictionary_2["$eip"] = 0x10000000;
  1.3876 +-  dictionary_2["$esp"] = 0xbfff0000;
  1.3877 +-  dictionary_2[".cbSavedRegs"] = 4;
  1.3878 +-  dictionary_2[".cbParams"] = 4;
  1.3879 +-  dictionary_2[".raSearchStart"] = 0xbfff0020;
  1.3880 ++  dictionary_2[ustr__ZSebp()] = 0xbfff0010;
  1.3881 ++  dictionary_2[ustr__ZSeip()] = 0x10000000;
  1.3882 ++  dictionary_2[ustr__ZSesp()] = 0xbfff0000;
  1.3883 ++  dictionary_2[ustr__ZDcbSavedRegs()] = 4;
  1.3884 ++  dictionary_2[ustr__ZDcbParams()] = 4;
  1.3885 ++  dictionary_2[ustr__ZDraSearchStart()] = 0xbfff0020;
  1.3886 +   const EvaluateForValueTest evaluate_for_value_tests_2[] = {
  1.3887 +     { "28907223",               true,  28907223 },      // simple constant
  1.3888 +     { "89854293 40010015 +",    true,  89854293 + 40010015 }, // arithmetic
  1.3889 +     { "-870245 8769343 +",      true,  7899098 },       // negative constants
  1.3890 +     { "$ebp $esp - $eip +",     true,  0x10000010 },    // variable references
  1.3891 +     { "18929794 34015074",      false, 0 },             // too many values
  1.3892 +     { "$ebp $ebp 4 - =",        false, 0 },             // too few values
  1.3893 +     { "$new $eip = $new",       true,  0x10000000 },    // make new variable
  1.3894 +     { "$new 4 +",               true,  0x10000004 },    // see prior assignments
  1.3895 +     { ".cfa 42 = 10",           false, 0 }              // can't set constants
  1.3896 +   };
  1.3897 +   const int evaluate_for_value_tests_2_size
  1.3898 +       = (sizeof (evaluate_for_value_tests_2)
  1.3899 +          / sizeof (evaluate_for_value_tests_2[0]));
  1.3900 +-  map<string, unsigned int> validate_data_2;
  1.3901 +-  validate_data_2["$eip"] = 0x10000000;
  1.3902 +-  validate_data_2["$ebp"] = 0xbfff000c;
  1.3903 +-  validate_data_2["$esp"] = 0xbfff0000;
  1.3904 +-  validate_data_2["$new"] = 0x10000000;
  1.3905 +-  validate_data_2[".cbSavedRegs"] = 4;
  1.3906 +-  validate_data_2[".cbParams"] = 4;
  1.3907 +-  validate_data_2[".raSearchStart"] = 0xbfff0020;
  1.3908 ++  map<const UniqueString*, unsigned int> validate_data_2;
  1.3909 ++  validate_data_2[ustr__ZSeip()] = 0x10000000;
  1.3910 ++  validate_data_2[ustr__ZSebp()] = 0xbfff000c;
  1.3911 ++  validate_data_2[ustr__ZSesp()] = 0xbfff0000;
  1.3912 ++  validate_data_2[ToUniqueString("$new")] = 0x10000000;
  1.3913 ++  validate_data_2[ustr__ZDcbSavedRegs()] = 4;
  1.3914 ++  validate_data_2[ustr__ZDcbParams()] = 4;
  1.3915 ++  validate_data_2[ustr__ZDraSearchStart()] = 0xbfff0020;
  1.3916 + 
  1.3917 +   postfix_evaluator.set_dictionary(&dictionary_2);
  1.3918 +   for (int i = 0; i < evaluate_for_value_tests_2_size; i++) {
  1.3919 +     const EvaluateForValueTest *test = &evaluate_for_value_tests_2[i];
  1.3920 +     unsigned int result;
  1.3921 +     if (postfix_evaluator.EvaluateForValue(test->expression, &result)
  1.3922 +         != test->evaluable) {
  1.3923 +       fprintf(stderr, "FAIL: evaluate for value test %d, "
  1.3924 +@@ -353,40 +370,43 @@
  1.3925 +     if (test->evaluable && result != test->value) {
  1.3926 +       fprintf(stderr, "FAIL: evaluate for value test %d, "
  1.3927 +               "expected value to be 0x%x, but it was 0x%x\n",
  1.3928 +               i, test->value, result);
  1.3929 +       return false;
  1.3930 +     }
  1.3931 +   }
  1.3932 + 
  1.3933 +-  for (map<string, unsigned int>::iterator v = validate_data_2.begin();
  1.3934 ++  for (map<const UniqueString*, unsigned int>::iterator v =
  1.3935 ++         validate_data_2.begin();
  1.3936 +        v != validate_data_2.end(); v++) {
  1.3937 +-    map<string, unsigned int>::iterator a = dictionary_2.find(v->first);
  1.3938 ++    map<const UniqueString*, unsigned int>::iterator a =
  1.3939 ++        dictionary_2.find(v->first);
  1.3940 +     if (a == dictionary_2.end()) {
  1.3941 +       fprintf(stderr, "FAIL: evaluate for value dictionary check: "
  1.3942 +               "expected dict[\"%s\"] to be 0x%x, but it was unset\n",
  1.3943 +-              v->first.c_str(), v->second);
  1.3944 ++              FromUniqueString(v->first), v->second);
  1.3945 +       return false;
  1.3946 +     } else if (a->second != v->second) {
  1.3947 +       fprintf(stderr, "FAIL: evaluate for value dictionary check: "
  1.3948 +               "expected dict[\"%s\"] to be 0x%x, but it was 0x%x\n",
  1.3949 +-              v->first.c_str(), v->second, a->second);
  1.3950 ++              FromUniqueString(v->first), v->second, a->second);
  1.3951 +       return false;
  1.3952 +     } 
  1.3953 +     dictionary_2.erase(a);
  1.3954 +   }
  1.3955 +   
  1.3956 +-  map<string, unsigned int>::iterator remaining = dictionary_2.begin();
  1.3957 ++  map<const UniqueString*, unsigned int>::iterator remaining =
  1.3958 ++      dictionary_2.begin();
  1.3959 +   if (remaining != dictionary_2.end()) {
  1.3960 +     fprintf(stderr, "FAIL: evaluation of test expressions put unexpected "
  1.3961 +             "values in dictionary:\n");
  1.3962 +     for (; remaining != dictionary_2.end(); remaining++)
  1.3963 +       fprintf(stderr, "    dict[\"%s\"] == 0x%x\n",
  1.3964 +-              remaining->first.c_str(), remaining->second);
  1.3965 ++              FromUniqueString(remaining->first), remaining->second);
  1.3966 +     return false;
  1.3967 +   }
  1.3968 + 
  1.3969 +   return true;
  1.3970 + }
  1.3971 + 
  1.3972 + 
  1.3973 + }  // namespace
  1.3974 +diff --git a/src/processor/stackwalker_amd64.cc b/src/processor/stackwalker_amd64.cc
  1.3975 +--- a/src/processor/stackwalker_amd64.cc
  1.3976 ++++ b/src/processor/stackwalker_amd64.cc
  1.3977 +@@ -50,49 +50,49 @@
  1.3978 + 
  1.3979 + const StackwalkerAMD64::CFIWalker::RegisterSet
  1.3980 + StackwalkerAMD64::cfi_register_map_[] = {
  1.3981 +   // It may seem like $rip and $rsp are callee-saves, because the callee is
  1.3982 +   // responsible for having them restored upon return. But the callee_saves
  1.3983 +   // flags here really means that the walker should assume they're
  1.3984 +   // unchanged if the CFI doesn't mention them --- clearly wrong for $rip
  1.3985 +   // and $rsp.
  1.3986 +-  { "$rax", NULL, false,
  1.3987 ++  { ToUniqueString("$rax"), NULL, false,
  1.3988 +     StackFrameAMD64::CONTEXT_VALID_RAX, &MDRawContextAMD64::rax },
  1.3989 +-  { "$rdx", NULL, false,
  1.3990 ++  { ToUniqueString("$rdx"), NULL, false,
  1.3991 +     StackFrameAMD64::CONTEXT_VALID_RDX, &MDRawContextAMD64::rdx },
  1.3992 +-  { "$rcx", NULL, false,
  1.3993 ++  { ToUniqueString("$rcx"), NULL, false,
  1.3994 +     StackFrameAMD64::CONTEXT_VALID_RCX, &MDRawContextAMD64::rcx },
  1.3995 +-  { "$rbx", NULL, true,
  1.3996 ++  { ToUniqueString("$rbx"), NULL, true,
  1.3997 +     StackFrameAMD64::CONTEXT_VALID_RBX, &MDRawContextAMD64::rbx },
  1.3998 +-  { "$rsi", NULL, false,
  1.3999 ++  { ToUniqueString("$rsi"), NULL, false,
  1.4000 +     StackFrameAMD64::CONTEXT_VALID_RSI, &MDRawContextAMD64::rsi },
  1.4001 +-  { "$rdi", NULL, false,
  1.4002 ++  { ToUniqueString("$rdi"), NULL, false,
  1.4003 +     StackFrameAMD64::CONTEXT_VALID_RDI, &MDRawContextAMD64::rdi },
  1.4004 +-  { "$rbp", NULL, true,
  1.4005 ++  { ToUniqueString("$rbp"), NULL, true,
  1.4006 +     StackFrameAMD64::CONTEXT_VALID_RBP, &MDRawContextAMD64::rbp },
  1.4007 +-  { "$rsp", ".cfa", false,
  1.4008 ++  { ToUniqueString("$rsp"), ToUniqueString(".cfa"), false,
  1.4009 +     StackFrameAMD64::CONTEXT_VALID_RSP, &MDRawContextAMD64::rsp },
  1.4010 +-  { "$r8", NULL, false,
  1.4011 ++  { ToUniqueString("$r8"), NULL, false,
  1.4012 +     StackFrameAMD64::CONTEXT_VALID_R8,  &MDRawContextAMD64::r8 },
  1.4013 +-  { "$r9", NULL, false,
  1.4014 ++  { ToUniqueString("$r9"), NULL, false,
  1.4015 +     StackFrameAMD64::CONTEXT_VALID_R9,  &MDRawContextAMD64::r9 },
  1.4016 +-  { "$r10", NULL, false,
  1.4017 ++  { ToUniqueString("$r10"), NULL, false,
  1.4018 +     StackFrameAMD64::CONTEXT_VALID_R10, &MDRawContextAMD64::r10 },
  1.4019 +-  { "$r11", NULL, false,
  1.4020 ++  { ToUniqueString("$r11"), NULL, false,
  1.4021 +     StackFrameAMD64::CONTEXT_VALID_R11, &MDRawContextAMD64::r11 },
  1.4022 +-  { "$r12", NULL, true,
  1.4023 ++  { ToUniqueString("$r12"), NULL, true,
  1.4024 +     StackFrameAMD64::CONTEXT_VALID_R12, &MDRawContextAMD64::r12 },
  1.4025 +-  { "$r13", NULL, true,
  1.4026 ++  { ToUniqueString("$r13"), NULL, true,
  1.4027 +     StackFrameAMD64::CONTEXT_VALID_R13, &MDRawContextAMD64::r13 },
  1.4028 +-  { "$r14", NULL, true,
  1.4029 ++  { ToUniqueString("$r14"), NULL, true,
  1.4030 +     StackFrameAMD64::CONTEXT_VALID_R14, &MDRawContextAMD64::r14 },
  1.4031 +-  { "$r15", NULL, true,
  1.4032 ++  { ToUniqueString("$r15"), NULL, true,
  1.4033 +     StackFrameAMD64::CONTEXT_VALID_R15, &MDRawContextAMD64::r15 },
  1.4034 +-  { "$rip", ".ra", false,
  1.4035 ++  { ToUniqueString("$rip"), ToUniqueString(".ra"), false,
  1.4036 +     StackFrameAMD64::CONTEXT_VALID_RIP, &MDRawContextAMD64::rip },
  1.4037 + };
  1.4038 + 
  1.4039 + StackwalkerAMD64::StackwalkerAMD64(const SystemInfo* system_info,
  1.4040 +                                    const MDRawContextAMD64* context,
  1.4041 +                                    MemoryRegion* memory,
  1.4042 +                                    const CodeModules* modules,
  1.4043 +                                    StackFrameSymbolizer* resolver_helper)
  1.4044 +diff --git a/src/processor/stackwalker_arm.cc b/src/processor/stackwalker_arm.cc
  1.4045 +--- a/src/processor/stackwalker_arm.cc
  1.4046 ++++ b/src/processor/stackwalker_arm.cc
  1.4047 +@@ -76,21 +76,30 @@
  1.4048 +   return frame;
  1.4049 + }
  1.4050 + 
  1.4051 + StackFrameARM* StackwalkerARM::GetCallerByCFIFrameInfo(
  1.4052 +     const vector<StackFrame*> &frames,
  1.4053 +     CFIFrameInfo* cfi_frame_info) {
  1.4054 +   StackFrameARM* last_frame = static_cast<StackFrameARM*>(frames.back());
  1.4055 + 
  1.4056 +-  static const char* register_names[] = {
  1.4057 +-    "r0",  "r1",  "r2",  "r3",  "r4",  "r5",  "r6",  "r7",
  1.4058 +-    "r8",  "r9",  "r10", "r11", "r12", "sp",  "lr",  "pc",
  1.4059 +-    "f0",  "f1",  "f2",  "f3",  "f4",  "f5",  "f6",  "f7",
  1.4060 +-    "fps", "cpsr",
  1.4061 ++  static const UniqueString *register_names[] = {
  1.4062 ++    ToUniqueString("r0"),  ToUniqueString("r1"),
  1.4063 ++    ToUniqueString("r2"),  ToUniqueString("r3"),
  1.4064 ++    ToUniqueString("r4"),  ToUniqueString("r5"),
  1.4065 ++    ToUniqueString("r6"),  ToUniqueString("r7"),
  1.4066 ++    ToUniqueString("r8"),  ToUniqueString("r9"),
  1.4067 ++    ToUniqueString("r10"), ToUniqueString("r11"),
  1.4068 ++    ToUniqueString("r12"), ToUniqueString("sp"),
  1.4069 ++    ToUniqueString("lr"),  ToUniqueString("pc"),
  1.4070 ++    ToUniqueString("f0"),  ToUniqueString("f1"),
  1.4071 ++    ToUniqueString("f2"),  ToUniqueString("f3"),
  1.4072 ++    ToUniqueString("f4"),  ToUniqueString("f5"),
  1.4073 ++    ToUniqueString("f6"),  ToUniqueString("f7"),
  1.4074 ++    ToUniqueString("fps"), ToUniqueString("cpsr"),
  1.4075 +     NULL
  1.4076 +   };
  1.4077 + 
  1.4078 +   // Populate a dictionary with the valid register values in last_frame.
  1.4079 +   CFIFrameInfo::RegisterValueMap<uint32_t> callee_registers;
  1.4080 +   for (int i = 0; register_names[i]; i++)
  1.4081 +     if (last_frame->context_validity & StackFrameARM::RegisterValidFlag(i))
  1.4082 +       callee_registers[register_names[i]] = last_frame->context.iregs[i];
  1.4083 +@@ -119,17 +128,17 @@
  1.4084 +       // Call Standard for the ARM Architecture, which the Linux ABI follows.
  1.4085 +       frame->context_validity |= StackFrameARM::RegisterValidFlag(i);
  1.4086 +       frame->context.iregs[i] = last_frame->context.iregs[i];
  1.4087 +     }
  1.4088 +   }
  1.4089 +   // If the CFI doesn't recover the PC explicitly, then use .ra.
  1.4090 +   if (!(frame->context_validity & StackFrameARM::CONTEXT_VALID_PC)) {
  1.4091 +     CFIFrameInfo::RegisterValueMap<uint32_t>::iterator entry =
  1.4092 +-      caller_registers.find(".ra");
  1.4093 ++      caller_registers.find(ustr__ZDra());
  1.4094 +     if (entry != caller_registers.end()) {
  1.4095 +       if (fp_register_ == -1) {
  1.4096 +         frame->context_validity |= StackFrameARM::CONTEXT_VALID_PC;
  1.4097 +         frame->context.iregs[MD_CONTEXT_ARM_REG_PC] = entry->second;
  1.4098 +       } else {
  1.4099 +         // The CFI updated the link register and not the program counter.
  1.4100 +         // Handle getting the program counter from the link register.
  1.4101 +         frame->context_validity |= StackFrameARM::CONTEXT_VALID_PC;
  1.4102 +@@ -138,17 +147,17 @@
  1.4103 +         frame->context.iregs[MD_CONTEXT_ARM_REG_PC] =
  1.4104 +             last_frame->context.iregs[MD_CONTEXT_ARM_REG_LR];
  1.4105 +       }
  1.4106 +     }
  1.4107 +   }
  1.4108 +   // If the CFI doesn't recover the SP explicitly, then use .cfa.
  1.4109 +   if (!(frame->context_validity & StackFrameARM::CONTEXT_VALID_SP)) {
  1.4110 +     CFIFrameInfo::RegisterValueMap<uint32_t>::iterator entry =
  1.4111 +-      caller_registers.find(".cfa");
  1.4112 ++      caller_registers.find(ustr__ZDcfa());
  1.4113 +     if (entry != caller_registers.end()) {
  1.4114 +       frame->context_validity |= StackFrameARM::CONTEXT_VALID_SP;
  1.4115 +       frame->context.iregs[MD_CONTEXT_ARM_REG_SP] = entry->second;
  1.4116 +     }
  1.4117 +   }
  1.4118 + 
  1.4119 +   // If we didn't recover the PC and the SP, then the frame isn't very useful.
  1.4120 +   static const int essentials = (StackFrameARM::CONTEXT_VALID_SP
  1.4121 +diff --git a/src/processor/stackwalker_x86.cc b/src/processor/stackwalker_x86.cc
  1.4122 +--- a/src/processor/stackwalker_x86.cc
  1.4123 ++++ b/src/processor/stackwalker_x86.cc
  1.4124 +@@ -53,33 +53,33 @@
  1.4125 + 
  1.4126 + const StackwalkerX86::CFIWalker::RegisterSet
  1.4127 + StackwalkerX86::cfi_register_map_[] = {
  1.4128 +   // It may seem like $eip and $esp are callee-saves, because (with Unix or
  1.4129 +   // cdecl calling conventions) the callee is responsible for having them
  1.4130 +   // restored upon return. But the callee_saves flags here really means
  1.4131 +   // that the walker should assume they're unchanged if the CFI doesn't
  1.4132 +   // mention them, which is clearly wrong for $eip and $esp.
  1.4133 +-  { "$eip", ".ra",  false,
  1.4134 ++  { ToUniqueString("$eip"), ToUniqueString(".ra"),  false,
  1.4135 +     StackFrameX86::CONTEXT_VALID_EIP, &MDRawContextX86::eip },
  1.4136 +-  { "$esp", ".cfa", false,
  1.4137 ++  { ToUniqueString("$esp"), ToUniqueString(".cfa"), false,
  1.4138 +     StackFrameX86::CONTEXT_VALID_ESP, &MDRawContextX86::esp },
  1.4139 +-  { "$ebp", NULL,   true,
  1.4140 ++  { ToUniqueString("$ebp"), NULL,   true,
  1.4141 +     StackFrameX86::CONTEXT_VALID_EBP, &MDRawContextX86::ebp },
  1.4142 +-  { "$eax", NULL,   false,
  1.4143 ++  { ToUniqueString("$eax"), NULL,   false,
  1.4144 +     StackFrameX86::CONTEXT_VALID_EAX, &MDRawContextX86::eax },
  1.4145 +-  { "$ebx", NULL,   true,
  1.4146 ++  { ToUniqueString("$ebx"), NULL,   true,
  1.4147 +     StackFrameX86::CONTEXT_VALID_EBX, &MDRawContextX86::ebx },
  1.4148 +-  { "$ecx", NULL,   false,
  1.4149 ++  { ToUniqueString("$ecx"), NULL,   false,
  1.4150 +     StackFrameX86::CONTEXT_VALID_ECX, &MDRawContextX86::ecx },
  1.4151 +-  { "$edx", NULL,   false,
  1.4152 ++  { ToUniqueString("$edx"), NULL,   false,
  1.4153 +     StackFrameX86::CONTEXT_VALID_EDX, &MDRawContextX86::edx },
  1.4154 +-  { "$esi", NULL,   true,
  1.4155 ++  { ToUniqueString("$esi"), NULL,   true,
  1.4156 +     StackFrameX86::CONTEXT_VALID_ESI, &MDRawContextX86::esi },
  1.4157 +-  { "$edi", NULL,   true,
  1.4158 ++  { ToUniqueString("$edi"), NULL,   true,
  1.4159 +     StackFrameX86::CONTEXT_VALID_EDI, &MDRawContextX86::edi },
  1.4160 + };
  1.4161 + 
  1.4162 + StackwalkerX86::StackwalkerX86(const SystemInfo* system_info,
  1.4163 +                                const MDRawContextX86* context,
  1.4164 +                                MemoryRegion* memory,
  1.4165 +                                const CodeModules* modules,
  1.4166 +                                StackFrameSymbolizer* resolver_helper)
  1.4167 +@@ -194,26 +194,26 @@
  1.4168 +     }
  1.4169 +   }
  1.4170 + 
  1.4171 +   // Set up the dictionary for the PostfixEvaluator.  %ebp and %esp are used
  1.4172 +   // in each program string, and their previous values are known, so set them
  1.4173 +   // here.
  1.4174 +   PostfixEvaluator<uint32_t>::DictionaryType dictionary;
  1.4175 +   // Provide the current register values.
  1.4176 +-  dictionary["$ebp"] = last_frame->context.ebp;
  1.4177 +-  dictionary["$esp"] = last_frame->context.esp;
  1.4178 ++  dictionary[ustr__ZSebp()] = last_frame->context.ebp;
  1.4179 ++  dictionary[ustr__ZSesp()] = last_frame->context.esp;
  1.4180 +   // Provide constants from the debug info for last_frame and its callee.
  1.4181 +   // .cbCalleeParams is a Breakpad extension that allows us to use the
  1.4182 +   // PostfixEvaluator engine when certain types of debugging information
  1.4183 +   // are present without having to write the constants into the program
  1.4184 +   // string as literals.
  1.4185 +-  dictionary[".cbCalleeParams"] = last_frame_callee_parameter_size;
  1.4186 +-  dictionary[".cbSavedRegs"] = last_frame_info->saved_register_size;
  1.4187 +-  dictionary[".cbLocals"] = last_frame_info->local_size;
  1.4188 ++  dictionary[ustr__ZDcbCalleeParams()] = last_frame_callee_parameter_size;
  1.4189 ++  dictionary[ustr__ZDcbSavedRegs()] = last_frame_info->saved_register_size;
  1.4190 ++  dictionary[ustr__ZDcbLocals()] = last_frame_info->local_size;
  1.4191 + 
  1.4192 +   uint32_t raSearchStart = last_frame->context.esp +
  1.4193 +                             last_frame_callee_parameter_size +
  1.4194 +                             last_frame_info->local_size +
  1.4195 +                             last_frame_info->saved_register_size;
  1.4196 + 
  1.4197 +   uint32_t raSearchStartOld = raSearchStart;
  1.4198 +   uint32_t found = 0;  // dummy value
  1.4199 +@@ -232,20 +232,20 @@
  1.4200 +     // Skip one slot from the stack and do another scan in order to get the
  1.4201 +     // actual return address.
  1.4202 +     raSearchStart += 4;
  1.4203 +     ScanForReturnAddress(raSearchStart, &raSearchStart, &found, 3);
  1.4204 +   }
  1.4205 + 
  1.4206 +   // The difference between raSearch and raSearchStart is unknown,
  1.4207 +   // but making them the same seems to work well in practice.
  1.4208 +-  dictionary[".raSearchStart"] = raSearchStart;
  1.4209 +-  dictionary[".raSearch"] = raSearchStart;
  1.4210 ++  dictionary[ustr__ZDraSearchStart()] = raSearchStart;
  1.4211 ++  dictionary[ustr__ZDraSearch()] = raSearchStart;
  1.4212 + 
  1.4213 +-  dictionary[".cbParams"] = last_frame_info->parameter_size;
  1.4214 ++  dictionary[ustr__ZDcbParams()] = last_frame_info->parameter_size;
  1.4215 + 
  1.4216 +   // Decide what type of program string to use. The program string is in
  1.4217 +   // postfix notation and will be passed to PostfixEvaluator::Evaluate.
  1.4218 +   // Given the dictionary and the program string, it is possible to compute
  1.4219 +   // the return address and the values of other registers in the calling
  1.4220 +   // function. Because of bugs described below, the stack may need to be
  1.4221 +   // scanned for these values. The results of program string evaluation
  1.4222 +   // will be used to determine whether to scan for better values.
  1.4223 +@@ -325,18 +325,18 @@
  1.4224 +   }
  1.4225 + 
  1.4226 +   // Now crank it out, making sure that the program string set at least the
  1.4227 +   // two required variables.
  1.4228 +   PostfixEvaluator<uint32_t> evaluator =
  1.4229 +       PostfixEvaluator<uint32_t>(&dictionary, memory_);
  1.4230 +   PostfixEvaluator<uint32_t>::DictionaryValidityType dictionary_validity;
  1.4231 +   if (!evaluator.Evaluate(program_string, &dictionary_validity) ||
  1.4232 +-      dictionary_validity.find("$eip") == dictionary_validity.end() ||
  1.4233 +-      dictionary_validity.find("$esp") == dictionary_validity.end()) {
  1.4234 ++      dictionary_validity.find(ustr__ZSeip()) == dictionary_validity.end() ||
  1.4235 ++      dictionary_validity.find(ustr__ZSesp()) == dictionary_validity.end()) {
  1.4236 +     // Program string evaluation failed. It may be that %eip is not somewhere
  1.4237 +     // with stack frame info, and %ebp is pointing to non-stack memory, so
  1.4238 +     // our evaluation couldn't succeed. We'll scan the stack for a return
  1.4239 +     // address. This can happen if the stack is in a module for which
  1.4240 +     // we don't have symbols, and that module is compiled without a
  1.4241 +     // frame pointer.
  1.4242 +     uint32_t location_start = last_frame->context.esp;
  1.4243 +     uint32_t location, eip;
  1.4244 +@@ -344,69 +344,69 @@
  1.4245 +       // if we can't find an instruction pointer even with stack scanning,
  1.4246 +       // give up.
  1.4247 +       return NULL;
  1.4248 +     }
  1.4249 + 
  1.4250 +     // This seems like a reasonable return address. Since program string
  1.4251 +     // evaluation failed, use it and set %esp to the location above the
  1.4252 +     // one where the return address was found.
  1.4253 +-    dictionary["$eip"] = eip;
  1.4254 +-    dictionary["$esp"] = location + 4;
  1.4255 ++    dictionary[ustr__ZSeip()] = eip;
  1.4256 ++    dictionary[ustr__ZSesp()] = location + 4;
  1.4257 +     trust = StackFrame::FRAME_TRUST_SCAN;
  1.4258 +   }
  1.4259 + 
  1.4260 +   // Since this stack frame did not use %ebp in a traditional way,
  1.4261 +   // locating the return address isn't entirely deterministic. In that
  1.4262 +   // case, the stack can be scanned to locate the return address.
  1.4263 +   //
  1.4264 +   // However, if program string evaluation resulted in both %eip and
  1.4265 +   // %ebp values of 0, trust that the end of the stack has been
  1.4266 +   // reached and don't scan for anything else.
  1.4267 +-  if (dictionary["$eip"] != 0 || dictionary["$ebp"] != 0) {
  1.4268 ++  if (dictionary[ustr__ZSeip()] != 0 || dictionary[ustr__ZSebp()] != 0) {
  1.4269 +     int offset = 0;
  1.4270 + 
  1.4271 +     // This scan can only be done if a CodeModules object is available, to
  1.4272 +     // check that candidate return addresses are in fact inside a module.
  1.4273 +     //
  1.4274 +     // TODO(mmentovai): This ignores dynamically-generated code.  One possible
  1.4275 +     // solution is to check the minidump's memory map to see if the candidate
  1.4276 +     // %eip value comes from a mapped executable page, although this would
  1.4277 +     // require dumps that contain MINIDUMP_MEMORY_INFO, which the Breakpad
  1.4278 +     // client doesn't currently write (it would need to call MiniDumpWriteDump
  1.4279 +     // with the MiniDumpWithFullMemoryInfo type bit set).  Even given this
  1.4280 +     // ability, older OSes (pre-XP SP2) and CPUs (pre-P4) don't enforce
  1.4281 +     // an independent execute privilege on memory pages.
  1.4282 + 
  1.4283 +-    uint32_t eip = dictionary["$eip"];
  1.4284 ++    uint32_t eip = dictionary[ustr__ZSeip()];
  1.4285 +     if (modules_ && !modules_->GetModuleForAddress(eip)) {
  1.4286 +       // The instruction pointer at .raSearchStart was invalid, so start
  1.4287 +       // looking one 32-bit word above that location.
  1.4288 +-      uint32_t location_start = dictionary[".raSearchStart"] + 4;
  1.4289 ++      uint32_t location_start = dictionary[ustr__ZDraSearchStart()] + 4;
  1.4290 +       uint32_t location;
  1.4291 +       if (ScanForReturnAddress(location_start, &location, &eip)) {
  1.4292 +         // This is a better return address that what program string
  1.4293 +         // evaluation found.  Use it, and set %esp to the location above the
  1.4294 +         // one where the return address was found.
  1.4295 +-        dictionary["$eip"] = eip;
  1.4296 +-        dictionary["$esp"] = location + 4;
  1.4297 ++        dictionary[ustr__ZSeip()] = eip;
  1.4298 ++        dictionary[ustr__ZSesp()] = location + 4;
  1.4299 +         offset = location - location_start;
  1.4300 +         trust = StackFrame::FRAME_TRUST_CFI_SCAN;
  1.4301 +       }
  1.4302 +     }
  1.4303 + 
  1.4304 +     if (recover_ebp) {
  1.4305 +       // When trying to recover the previous value of the frame pointer (%ebp),
  1.4306 +       // start looking at the lowest possible address in the saved-register
  1.4307 +       // area, and look at the entire saved register area, increased by the
  1.4308 +       // size of |offset| to account for additional data that may be on the
  1.4309 +       // stack.  The scan is performed from the highest possible address to
  1.4310 +       // the lowest, because the expectation is that the function's prolog
  1.4311 +       // would have saved %ebp early.
  1.4312 +-      uint32_t ebp = dictionary["$ebp"];
  1.4313 ++      uint32_t ebp = dictionary[ustr__ZSebp()];
  1.4314 + 
  1.4315 +       // When a scan for return address is used, it is possible to skip one or
  1.4316 +       // more frames (when return address is not in a known module).  One
  1.4317 +       // indication for skipped frames is when the value of %ebp is lower than
  1.4318 +       // the location of the return address on the stack
  1.4319 +       bool has_skipped_frames =
  1.4320 +         (trust != StackFrame::FRAME_TRUST_CFI && ebp <= raSearchStart + offset);
  1.4321 + 
  1.4322 +@@ -420,49 +420,49 @@
  1.4323 +              location >= location_end;
  1.4324 +              location -= 4) {
  1.4325 +           if (!memory_->GetMemoryAtAddress(location, &ebp))
  1.4326 +             break;
  1.4327 + 
  1.4328 +           if (memory_->GetMemoryAtAddress(ebp, &value)) {
  1.4329 +             // The candidate value is a pointer to the same memory region
  1.4330 +             // (the stack).  Prefer it as a recovered %ebp result.
  1.4331 +-            dictionary["$ebp"] = ebp;
  1.4332 ++            dictionary[ustr__ZSebp()] = ebp;
  1.4333 +             break;
  1.4334 +           }
  1.4335 +         }
  1.4336 +       }
  1.4337 +     }
  1.4338 +   }
  1.4339 + 
  1.4340 +   // Create a new stack frame (ownership will be transferred to the caller)
  1.4341 +   // and fill it in.
  1.4342 +   StackFrameX86* frame = new StackFrameX86();
  1.4343 + 
  1.4344 +   frame->trust = trust;
  1.4345 +   frame->context = last_frame->context;
  1.4346 +-  frame->context.eip = dictionary["$eip"];
  1.4347 +-  frame->context.esp = dictionary["$esp"];
  1.4348 +-  frame->context.ebp = dictionary["$ebp"];
  1.4349 ++  frame->context.eip = dictionary[ustr__ZSeip()];
  1.4350 ++  frame->context.esp = dictionary[ustr__ZSesp()];
  1.4351 ++  frame->context.ebp = dictionary[ustr__ZSebp()];
  1.4352 +   frame->context_validity = StackFrameX86::CONTEXT_VALID_EIP |
  1.4353 +                                 StackFrameX86::CONTEXT_VALID_ESP |
  1.4354 +                                 StackFrameX86::CONTEXT_VALID_EBP;
  1.4355 + 
  1.4356 +   // These are nonvolatile (callee-save) registers, and the program string
  1.4357 +   // may have filled them in.
  1.4358 +-  if (dictionary_validity.find("$ebx") != dictionary_validity.end()) {
  1.4359 +-    frame->context.ebx = dictionary["$ebx"];
  1.4360 ++  if (dictionary_validity.find(ustr__ZSebx()) != dictionary_validity.end()) {
  1.4361 ++    frame->context.ebx = dictionary[ustr__ZSebx()];
  1.4362 +     frame->context_validity |= StackFrameX86::CONTEXT_VALID_EBX;
  1.4363 +   }
  1.4364 +-  if (dictionary_validity.find("$esi") != dictionary_validity.end()) {
  1.4365 +-    frame->context.esi = dictionary["$esi"];
  1.4366 ++  if (dictionary_validity.find(ustr__ZSesi()) != dictionary_validity.end()) {
  1.4367 ++    frame->context.esi = dictionary[ustr__ZSesi()];
  1.4368 +     frame->context_validity |= StackFrameX86::CONTEXT_VALID_ESI;
  1.4369 +   }
  1.4370 +-  if (dictionary_validity.find("$edi") != dictionary_validity.end()) {
  1.4371 +-    frame->context.edi = dictionary["$edi"];
  1.4372 ++  if (dictionary_validity.find(ustr__ZSedi()) != dictionary_validity.end()) {
  1.4373 ++    frame->context.edi = dictionary[ustr__ZSedi()];
  1.4374 +     frame->context_validity |= StackFrameX86::CONTEXT_VALID_EDI;
  1.4375 +   }
  1.4376 + 
  1.4377 +   return frame;
  1.4378 + }
  1.4379 + 
  1.4380 + StackFrameX86* StackwalkerX86::GetCallerByCFIFrameInfo(
  1.4381 +     const vector<StackFrame*> &frames,
  1.4382 +diff --git a/src/tools/mac/dump_syms/dump_syms.xcodeproj/project.pbxproj b/src/tools/mac/dump_syms/dump_syms.xcodeproj/project.pbxproj
  1.4383 +--- a/src/tools/mac/dump_syms/dump_syms.xcodeproj/project.pbxproj
  1.4384 ++++ b/src/tools/mac/dump_syms/dump_syms.xcodeproj/project.pbxproj
  1.4385 +@@ -98,16 +98,22 @@
  1.4386 + 		B8C5B51B1166534700D34F4E /* macho_id.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9BE650430B52F6D800611104 /* macho_id.cc */; };
  1.4387 + 		B8C5B51C1166534700D34F4E /* macho_walker.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9BE650450B52F6D800611104 /* macho_walker.cc */; };
  1.4388 + 		B8C5B51D1166534700D34F4E /* dump_syms.mm in Sources */ = {isa = PBXBuildFile; fileRef = 08FB7796FE84155DC02AAC07 /* dump_syms.mm */; };
  1.4389 + 		B8C5B51E1166534700D34F4E /* dump_syms_tool.mm in Sources */ = {isa = PBXBuildFile; fileRef = 9BDF186E0B1BB43700F8391B /* dump_syms_tool.mm */; };
  1.4390 + 		B8C5B523116653BA00D34F4E /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 08FB779EFE84155DC02AAC07 /* Foundation.framework */; };
  1.4391 + 		D21F97D711CBA12300239E38 /* test_assembler_unittest.cc in Sources */ = {isa = PBXBuildFile; fileRef = B88FB0D9116CEC0600407530 /* test_assembler_unittest.cc */; };
  1.4392 + 		D21F97D811CBA13D00239E38 /* libgtestmockall.a in Frameworks */ = {isa = PBXBuildFile; fileRef = B88FB024116BDFFF00407530 /* libgtestmockall.a */; };
  1.4393 + 		D21F97E911CBA1FF00239E38 /* test_assembler.cc in Sources */ = {isa = PBXBuildFile; fileRef = B88FAE0911665B5700407530 /* test_assembler.cc */; };
  1.4394 ++		D24997CC16B6C16800E588C5 /* unique_string.cc in Sources */ = {isa = PBXBuildFile; fileRef = D24997CA16B6C16800E588C5 /* unique_string.cc */; };
  1.4395 ++		D24997CD16B6C16800E588C5 /* unique_string.cc in Sources */ = {isa = PBXBuildFile; fileRef = D24997CA16B6C16800E588C5 /* unique_string.cc */; };
  1.4396 ++		D24997CE16B6C16800E588C5 /* unique_string.cc in Sources */ = {isa = PBXBuildFile; fileRef = D24997CA16B6C16800E588C5 /* unique_string.cc */; };
  1.4397 ++		D2499A0016B9BA6A00E588C5 /* unique_string.cc in Sources */ = {isa = PBXBuildFile; fileRef = D24997CA16B6C16800E588C5 /* unique_string.cc */; };
  1.4398 ++		D2499A0216B9BA9600E588C5 /* unique_string.cc in Sources */ = {isa = PBXBuildFile; fileRef = D24997CA16B6C16800E588C5 /* unique_string.cc */; };
  1.4399 ++		D2499A0316B9BA9D00E588C5 /* unique_string.cc in Sources */ = {isa = PBXBuildFile; fileRef = D24997CA16B6C16800E588C5 /* unique_string.cc */; };
  1.4400 + /* End PBXBuildFile section */
  1.4401 + 
  1.4402 + /* Begin PBXContainerItemProxy section */
  1.4403 + 		8B31051411F100CF00FCF3E4 /* PBXContainerItemProxy */ = {
  1.4404 + 			isa = PBXContainerItemProxy;
  1.4405 + 			containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
  1.4406 + 			proxyType = 1;
  1.4407 + 			remoteGlobalIDString = D21F97D111CBA0F200239E38;
  1.4408 +@@ -338,16 +344,18 @@
  1.4409 + 		B89E0E741166575200DD08C9 /* macho_dump */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = macho_dump; sourceTree = BUILT_PRODUCTS_DIR; };
  1.4410 + 		B89E0E9511665A6400DD08C9 /* macho_reader_unittest */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = macho_reader_unittest; sourceTree = BUILT_PRODUCTS_DIR; };
  1.4411 + 		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; };
  1.4412 + 		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; };
  1.4413 + 		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; };
  1.4414 + 		B8C5B5111166531A00D34F4E /* dump_syms */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = dump_syms; sourceTree = BUILT_PRODUCTS_DIR; };
  1.4415 + 		B8E8CA0C1156C854009E61B2 /* byteswap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = byteswap.h; path = ../../../common/mac/byteswap.h; sourceTree = SOURCE_ROOT; };
  1.4416 + 		D21F97D211CBA0F200239E38 /* test_assembler_unittest */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = test_assembler_unittest; sourceTree = BUILT_PRODUCTS_DIR; };
  1.4417 ++		D24997CA16B6C16800E588C5 /* unique_string.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = unique_string.cc; path = ../../../common/unique_string.cc; sourceTree = "<group>"; };
  1.4418 ++		D24997CB16B6C16800E588C5 /* unique_string.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = unique_string.h; path = ../../../common/unique_string.h; sourceTree = "<group>"; };
  1.4419 + 		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; };
  1.4420 + 		F95B422C0E0E22D100DBDE83 /* bytereader.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = bytereader.cc; path = ../../../common/dwarf/bytereader.cc; sourceTree = SOURCE_ROOT; };
  1.4421 + 		F95B422D0E0E22D100DBDE83 /* bytereader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = bytereader.h; path = ../../../common/dwarf/bytereader.h; sourceTree = SOURCE_ROOT; };
  1.4422 + 		F95B422E0E0E22D100DBDE83 /* dwarf2enums.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dwarf2enums.h; path = ../../../common/dwarf/dwarf2enums.h; sourceTree = SOURCE_ROOT; };
  1.4423 + 		F95B422F0E0E22D100DBDE83 /* dwarf2reader.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = dwarf2reader.cc; path = ../../../common/dwarf/dwarf2reader.cc; sourceTree = SOURCE_ROOT; };
  1.4424 + 		F95B42300E0E22D100DBDE83 /* dwarf2reader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dwarf2reader.h; path = ../../../common/dwarf/dwarf2reader.h; sourceTree = SOURCE_ROOT; };
  1.4425 + 		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; };
  1.4426 + /* End PBXFileReference section */
  1.4427 +@@ -531,16 +539,18 @@
  1.4428 + 				D21F97D211CBA0F200239E38 /* test_assembler_unittest */,
  1.4429 + 			);
  1.4430 + 			name = Products;
  1.4431 + 			sourceTree = "<group>";
  1.4432 + 		};
  1.4433 + 		B88FAE1C11665FFD00407530 /* MODULE */ = {
  1.4434 + 			isa = PBXGroup;
  1.4435 + 			children = (
  1.4436 ++				D24997CA16B6C16800E588C5 /* unique_string.cc */,
  1.4437 ++				D24997CB16B6C16800E588C5 /* unique_string.h */,
  1.4438 + 				B88FAE1E1166603300407530 /* dwarf_cu_to_module.cc */,
  1.4439 + 				B88FAE1F1166603300407530 /* dwarf_cu_to_module.h */,
  1.4440 + 				B88FB0D6116CEC0600407530 /* dwarf_cu_to_module_unittest.cc */,
  1.4441 + 				B88FAE201166603300407530 /* dwarf_line_to_module.cc */,
  1.4442 + 				B88FAE211166603300407530 /* dwarf_line_to_module.h */,
  1.4443 + 				B88FB0D7116CEC0600407530 /* dwarf_line_to_module_unittest.cc */,
  1.4444 + 				B88FAE221166603300407530 /* language.cc */,
  1.4445 + 				B88FAE231166603300407530 /* language.h */,
  1.4446 +@@ -940,16 +950,17 @@
  1.4447 + 		};
  1.4448 + /* End PBXShellScriptBuildPhase section */
  1.4449 + 
  1.4450 + /* Begin PBXSourcesBuildPhase section */
  1.4451 + 		B84A91F1116CF784006C210E /* Sources */ = {
  1.4452 + 			isa = PBXSourcesBuildPhase;
  1.4453 + 			buildActionMask = 2147483647;
  1.4454 + 			files = (
  1.4455 ++				D2499A0216B9BA9600E588C5 /* unique_string.cc in Sources */,
  1.4456 + 				B84A91FB116CF7AF006C210E /* module.cc in Sources */,
  1.4457 + 				B84A91FC116CF7AF006C210E /* stabs_to_module.cc in Sources */,
  1.4458 + 				B84A91FD116CF7AF006C210E /* stabs_to_module_unittest.cc in Sources */,
  1.4459 + 			);
  1.4460 + 			runOnlyForDeploymentPostprocessing = 0;
  1.4461 + 		};
  1.4462 + 		B88FAF2C116A591D00407530 /* Sources */ = {
  1.4463 + 			isa = PBXSourcesBuildPhase;
  1.4464 +@@ -983,56 +994,60 @@
  1.4465 + 			runOnlyForDeploymentPostprocessing = 0;
  1.4466 + 		};
  1.4467 + 		B88FB0B6116CEABF00407530 /* Sources */ = {
  1.4468 + 			isa = PBXSourcesBuildPhase;
  1.4469 + 			buildActionMask = 2147483647;
  1.4470 + 			files = (
  1.4471 + 				B88FB0BD116CEAE000407530 /* module_unittest.cc in Sources */,
  1.4472 + 				B88FB0C4116CEB4100407530 /* module.cc in Sources */,
  1.4473 ++				D24997CE16B6C16800E588C5 /* unique_string.cc in Sources */,
  1.4474 + 			);
  1.4475 + 			runOnlyForDeploymentPostprocessing = 0;
  1.4476 + 		};
  1.4477 + 		B88FB0DC116CEEA800407530 /* Sources */ = {
  1.4478 + 			isa = PBXSourcesBuildPhase;
  1.4479 + 			buildActionMask = 2147483647;
  1.4480 + 			files = (
  1.4481 + 				B88FB0E5116CEED300407530 /* dwarf2diehandler.cc in Sources */,
  1.4482 + 				B88FB0E6116CEED300407530 /* dwarf2diehandler_unittest.cc in Sources */,
  1.4483 + 			);
  1.4484 + 			runOnlyForDeploymentPostprocessing = 0;
  1.4485 + 		};
  1.4486 + 		B88FB0EF116CEF1900407530 /* Sources */ = {
  1.4487 + 			isa = PBXSourcesBuildPhase;
  1.4488 + 			buildActionMask = 2147483647;
  1.4489 + 			files = (
  1.4490 ++				D2499A0316B9BA9D00E588C5 /* unique_string.cc in Sources */,
  1.4491 + 				B88FB0FA116CF00E00407530 /* dwarf_line_to_module.cc in Sources */,
  1.4492 + 				B88FB0FE116CF02400407530 /* module.cc in Sources */,
  1.4493 + 				B88FB0FB116CF00E00407530 /* dwarf_line_to_module_unittest.cc in Sources */,
  1.4494 + 			);
  1.4495 + 			runOnlyForDeploymentPostprocessing = 0;
  1.4496 + 		};
  1.4497 + 		B88FB107116CF07900407530 /* Sources */ = {
  1.4498 + 			isa = PBXSourcesBuildPhase;
  1.4499 + 			buildActionMask = 2147483647;
  1.4500 + 			files = (
  1.4501 ++				D2499A0016B9BA6A00E588C5 /* unique_string.cc in Sources */,
  1.4502 + 				B88FB112116CF1F000407530 /* dwarf_cu_to_module.cc in Sources */,
  1.4503 + 				B88FB113116CF1F000407530 /* dwarf_cu_to_module_unittest.cc in Sources */,
  1.4504 + 				B88FB114116CF1F000407530 /* language.cc in Sources */,
  1.4505 + 				B88FB115116CF1F000407530 /* module.cc in Sources */,
  1.4506 + 			);
  1.4507 + 			runOnlyForDeploymentPostprocessing = 0;
  1.4508 + 		};
  1.4509 + 		B88FB11C116CF27F00407530 /* Sources */ = {
  1.4510 + 			isa = PBXSourcesBuildPhase;
  1.4511 + 			buildActionMask = 2147483647;
  1.4512 + 			files = (
  1.4513 + 				B88FB129116CF2DD00407530 /* module.cc in Sources */,
  1.4514 + 				B88FB12A116CF2DD00407530 /* dwarf_cfi_to_module.cc in Sources */,
  1.4515 + 				B88FB12B116CF2DD00407530 /* dwarf_cfi_to_module_unittest.cc in Sources */,
  1.4516 ++				D24997CD16B6C16800E588C5 /* unique_string.cc in Sources */,
  1.4517 + 			);
  1.4518 + 			runOnlyForDeploymentPostprocessing = 0;
  1.4519 + 		};
  1.4520 + 		B88FB132116CF30F00407530 /* Sources */ = {
  1.4521 + 			isa = PBXSourcesBuildPhase;
  1.4522 + 			buildActionMask = 2147483647;
  1.4523 + 			files = (
  1.4524 + 				B88FB13D116CF38300407530 /* cfi_assembler.cc in Sources */,
  1.4525 +@@ -1086,16 +1101,17 @@
  1.4526 + 				B88FAE261166603300407530 /* dwarf_cu_to_module.cc in Sources */,
  1.4527 + 				B88FAE271166603300407530 /* dwarf_line_to_module.cc in Sources */,
  1.4528 + 				B88FAE281166603300407530 /* language.cc in Sources */,
  1.4529 + 				B88FAE291166603300407530 /* module.cc in Sources */,
  1.4530 + 				B88FAE351166673E00407530 /* dwarf_cfi_to_module.cc in Sources */,
  1.4531 + 				B88FAE3B11666C6F00407530 /* stabs_reader.cc in Sources */,
  1.4532 + 				B88FAE3E11666C8900407530 /* stabs_to_module.cc in Sources */,
  1.4533 + 				4D72CAF513DFBAC2006CABE3 /* md5.cc in Sources */,
  1.4534 ++				D24997CC16B6C16800E588C5 /* unique_string.cc in Sources */,
  1.4535 + 			);
  1.4536 + 			runOnlyForDeploymentPostprocessing = 0;
  1.4537 + 		};
  1.4538 + 		D21F97CF11CBA0F200239E38 /* Sources */ = {
  1.4539 + 			isa = PBXSourcesBuildPhase;
  1.4540 + 			buildActionMask = 2147483647;
  1.4541 + 			files = (
  1.4542 + 				D21F97E911CBA1FF00239E38 /* test_assembler.cc in Sources */,

mercurial