1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/toolkit/crashreporter/breakpad-patches/04-uniquestringmap.patch Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,1448 @@ 1.4 +# HG changeset patch 1.5 +# User Ted Mielczarek <ted.mielczarek@gmail.com> 1.6 +# Date 1360255134 18000 1.7 +# Node ID 294ce0d64d35a90be8ea91b719ead8b82aed29f7 1.8 +# Parent d7bfb673574a3afe8b4f76f42fb52e2545770dad 1.9 +Rework PostfixEvaluator to use UniqueStringMap 1.10 +Patch by Julian Seward <jseward@acm.org>, R=ted 1.11 + 1.12 +diff --git a/src/common/unique_string.h b/src/common/unique_string.h 1.13 +--- a/src/common/unique_string.h 1.14 ++++ b/src/common/unique_string.h 1.15 +@@ -25,16 +25,17 @@ 1.16 + // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 1.17 + // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 1.18 + // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 1.19 + // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 1.20 + 1.21 + #ifndef COMMON_UNIQUE_STRING_H_ 1.22 + #define COMMON_UNIQUE_STRING_H_ 1.23 + 1.24 ++#include <map> 1.25 + #include <string> 1.26 + #include "common/using_std_string.h" 1.27 + 1.28 + namespace google_breakpad { 1.29 + 1.30 + // Abstract type 1.31 + class UniqueString; 1.32 + 1.33 +@@ -229,11 +230,112 @@ 1.34 + 1.35 + // ".ra" 1.36 + inline static const UniqueString* ustr__ZDra() { 1.37 + static const UniqueString* us = NULL; 1.38 + if (!us) us = ToUniqueString(".ra"); 1.39 + return us; 1.40 + } 1.41 + 1.42 ++template <typename ValueType> 1.43 ++class UniqueStringMap 1.44 ++{ 1.45 ++ private: 1.46 ++ static const int N_FIXED = 10; 1.47 ++ 1.48 ++ public: 1.49 ++ UniqueStringMap() : n_fixed_(0), n_sets_(0), n_gets_(0), n_clears_(0) {}; 1.50 ++ ~UniqueStringMap() {}; 1.51 ++ 1.52 ++ // Empty out the map. 1.53 ++ void clear() { 1.54 ++ ++n_clears_; 1.55 ++ map_.clear(); 1.56 ++ n_fixed_ = 0; 1.57 ++ } 1.58 ++ 1.59 ++ // Do "map[ix] = v". 1.60 ++ void set(const UniqueString* ix, ValueType v) { 1.61 ++ ++n_sets_; 1.62 ++ int i; 1.63 ++ for (i = 0; i < n_fixed_; ++i) { 1.64 ++ if (fixed_keys_[i] == ix) { 1.65 ++ fixed_vals_[i] = v; 1.66 ++ return; 1.67 ++ } 1.68 ++ } 1.69 ++ if (n_fixed_ < N_FIXED) { 1.70 ++ i = n_fixed_; 1.71 ++ fixed_keys_[i] = ix; 1.72 ++ fixed_vals_[i] = v; 1.73 ++ ++n_fixed_; 1.74 ++ } else { 1.75 ++ map_[ix] = v; 1.76 ++ } 1.77 ++ } 1.78 ++ 1.79 ++ // Lookup 'ix' in the map, and also return a success/fail boolean. 1.80 ++ ValueType get(/*OUT*/bool* have, const UniqueString* ix) const { 1.81 ++ ++n_gets_; 1.82 ++ int i; 1.83 ++ for (i = 0; i < n_fixed_; ++i) { 1.84 ++ if (fixed_keys_[i] == ix) { 1.85 ++ *have = true; 1.86 ++ return fixed_vals_[i]; 1.87 ++ } 1.88 ++ } 1.89 ++ typename std::map<const UniqueString*, ValueType>::const_iterator it 1.90 ++ = map_.find(ix); 1.91 ++ if (it == map_.end()) { 1.92 ++ *have = false; 1.93 ++ return ValueType(); 1.94 ++ } else { 1.95 ++ *have = true; 1.96 ++ return it->second; 1.97 ++ } 1.98 ++ }; 1.99 ++ 1.100 ++ // Lookup 'ix' in the map, and return zero if it is not present. 1.101 ++ ValueType get(const UniqueString* ix) const { 1.102 ++ ++n_gets_; 1.103 ++ bool found; 1.104 ++ ValueType v = get(&found, ix); 1.105 ++ return found ? v : ValueType(); 1.106 ++ } 1.107 ++ 1.108 ++ // Find out whether 'ix' is in the map. 1.109 ++ bool have(const UniqueString* ix) const { 1.110 ++ ++n_gets_; 1.111 ++ bool found; 1.112 ++ (void)get(&found, ix); 1.113 ++ return found; 1.114 ++ } 1.115 ++ 1.116 ++ // Copy the contents to a std::map, generally for testing. 1.117 ++ void copy_to_map(std::map<const UniqueString*, ValueType>* m) const { 1.118 ++ m->clear(); 1.119 ++ int i; 1.120 ++ for (i = 0; i < n_fixed_; ++i) { 1.121 ++ (*m)[fixed_keys_[i]] = fixed_vals_[i]; 1.122 ++ } 1.123 ++ m->insert(map_.begin(), map_.end()); 1.124 ++ } 1.125 ++ 1.126 ++ // Note that users of this class rely on having also a sane 1.127 ++ // assignment operator. The default one is OK, though. 1.128 ++ // AFAICT there are no uses of the copy constructor, but if 1.129 ++ // there were, the default one would also suffice. 1.130 ++ 1.131 ++ private: 1.132 ++ // Quick (hopefully) cache 1.133 ++ const UniqueString* fixed_keys_[N_FIXED]; 1.134 ++ ValueType fixed_vals_[N_FIXED]; 1.135 ++ int n_fixed_; // 0 .. N_FIXED inclusive 1.136 ++ // Fallback storage when the cache is filled 1.137 ++ std::map<const UniqueString*, ValueType> map_; 1.138 ++ 1.139 ++ // For tracking usage stats. 1.140 ++ mutable int n_sets_, n_gets_, n_clears_; 1.141 ++}; 1.142 ++ 1.143 + } // namespace google_breakpad 1.144 + 1.145 + #endif // COMMON_UNIQUE_STRING_H_ 1.146 +diff --git a/src/processor/basic_source_line_resolver_unittest.cc b/src/processor/basic_source_line_resolver_unittest.cc 1.147 +--- a/src/processor/basic_source_line_resolver_unittest.cc 1.148 ++++ b/src/processor/basic_source_line_resolver_unittest.cc 1.149 +@@ -24,16 +24,17 @@ 1.150 + // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 1.151 + // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 1.152 + // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 1.153 + // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 1.154 + // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 1.155 + 1.156 + #include <stdio.h> 1.157 + 1.158 ++#include <map> 1.159 + #include <string> 1.160 + 1.161 + #include "breakpad_googletest_includes.h" 1.162 + #include "common/scoped_ptr.h" 1.163 + #include "common/using_std_string.h" 1.164 + #include "google_breakpad/processor/basic_source_line_resolver.h" 1.165 + #include "google_breakpad/processor/code_module.h" 1.166 + #include "google_breakpad/processor/stack_frame.h" 1.167 +@@ -47,16 +48,17 @@ 1.168 + 1.169 + using google_breakpad::BasicSourceLineResolver; 1.170 + using google_breakpad::CFIFrameInfo; 1.171 + using google_breakpad::CodeModule; 1.172 + using google_breakpad::FromUniqueString; 1.173 + using google_breakpad::MemoryRegion; 1.174 + using google_breakpad::StackFrame; 1.175 + using google_breakpad::ToUniqueString; 1.176 ++using google_breakpad::UniqueString; 1.177 + using google_breakpad::WindowsFrameInfo; 1.178 + using google_breakpad::linked_ptr; 1.179 + using google_breakpad::scoped_ptr; 1.180 + using google_breakpad::ustr__ZDcfa; 1.181 + using google_breakpad::ustr__ZDra; 1.182 + using google_breakpad::ustr__ZSebx; 1.183 + using google_breakpad::ustr__ZSebp; 1.184 + using google_breakpad::ustr__ZSedi; 1.185 +@@ -113,27 +115,30 @@ 1.186 + }; 1.187 + 1.188 + // Verify that, for every association in ACTUAL, EXPECTED has the same 1.189 + // association. (That is, ACTUAL's associations should be a subset of 1.190 + // EXPECTED's.) Also verify that ACTUAL has associations for ".ra" and 1.191 + // ".cfa". 1.192 + static bool VerifyRegisters( 1.193 + const char *file, int line, 1.194 +- const CFIFrameInfo::RegisterValueMap<uint32_t> &expected, 1.195 +- const CFIFrameInfo::RegisterValueMap<uint32_t> &actual) { 1.196 +- CFIFrameInfo::RegisterValueMap<uint32_t>::const_iterator a; 1.197 ++ const std::map<const UniqueString*, uint32_t> &expected, 1.198 ++ const CFIFrameInfo::RegisterValueMap<uint32_t> &actual_regmap) { 1.199 ++ std::map<const UniqueString*, uint32_t> actual; 1.200 ++ actual_regmap.copy_to_map(&actual); 1.201 ++ 1.202 ++ std::map<const UniqueString*, uint32_t>::const_iterator a; 1.203 + a = actual.find(ustr__ZDcfa()); 1.204 + if (a == actual.end()) 1.205 + return false; 1.206 + a = actual.find(ustr__ZDra()); 1.207 + if (a == actual.end()) 1.208 + return false; 1.209 + for (a = actual.begin(); a != actual.end(); a++) { 1.210 +- CFIFrameInfo::RegisterValueMap<uint32_t>::const_iterator e = 1.211 ++ std::map<const UniqueString*, uint32_t>::const_iterator e = 1.212 + expected.find(a->first); 1.213 + if (e == expected.end()) { 1.214 + fprintf(stderr, "%s:%d: unexpected register '%s' recovered, value 0x%x\n", 1.215 + file, line, FromUniqueString(a->first), a->second); 1.216 + return false; 1.217 + } 1.218 + if (e->second != a->second) { 1.219 + fprintf(stderr, 1.220 +@@ -258,86 +263,86 @@ 1.221 + 1.222 + frame.instruction = 0x3e9f; 1.223 + frame.module = &module1; 1.224 + cfi_frame_info.reset(resolver.FindCFIFrameInfo(&frame)); 1.225 + ASSERT_FALSE(cfi_frame_info.get()); 1.226 + 1.227 + CFIFrameInfo::RegisterValueMap<uint32_t> current_registers; 1.228 + CFIFrameInfo::RegisterValueMap<uint32_t> caller_registers; 1.229 +- CFIFrameInfo::RegisterValueMap<uint32_t> expected_caller_registers; 1.230 ++ std::map<const UniqueString*, uint32_t> expected_caller_registers; 1.231 + MockMemoryRegion memory; 1.232 + 1.233 + // Regardless of which instruction evaluation takes place at, it 1.234 + // should produce the same values for the caller's registers. 1.235 + expected_caller_registers[ustr__ZDcfa()] = 0x1001c; 1.236 + expected_caller_registers[ustr__ZDra()] = 0xf6438648; 1.237 + expected_caller_registers[ustr__ZSebp()] = 0x10038; 1.238 + expected_caller_registers[ustr__ZSebx()] = 0x98ecadc3; 1.239 + expected_caller_registers[ustr__ZSesi()] = 0x878f7524; 1.240 + expected_caller_registers[ustr__ZSedi()] = 0x6312f9a5; 1.241 + 1.242 + frame.instruction = 0x3d40; 1.243 + frame.module = &module1; 1.244 + current_registers.clear(); 1.245 +- current_registers[ustr__ZSesp()] = 0x10018; 1.246 +- current_registers[ustr__ZSebp()] = 0x10038; 1.247 +- current_registers[ustr__ZSebx()] = 0x98ecadc3; 1.248 +- current_registers[ustr__ZSesi()] = 0x878f7524; 1.249 +- current_registers[ustr__ZSedi()] = 0x6312f9a5; 1.250 ++ current_registers.set(ustr__ZSesp(), 0x10018); 1.251 ++ current_registers.set(ustr__ZSebp(), 0x10038); 1.252 ++ current_registers.set(ustr__ZSebx(), 0x98ecadc3); 1.253 ++ current_registers.set(ustr__ZSesi(), 0x878f7524); 1.254 ++ current_registers.set(ustr__ZSedi(), 0x6312f9a5); 1.255 + cfi_frame_info.reset(resolver.FindCFIFrameInfo(&frame)); 1.256 + ASSERT_TRUE(cfi_frame_info.get()); 1.257 + ASSERT_TRUE(cfi_frame_info.get() 1.258 + ->FindCallerRegs<uint32_t>(current_registers, memory, 1.259 + &caller_registers)); 1.260 + ASSERT_TRUE(VerifyRegisters(__FILE__, __LINE__, 1.261 + expected_caller_registers, caller_registers)); 1.262 + 1.263 + frame.instruction = 0x3d41; 1.264 +- current_registers[ustr__ZSesp()] = 0x10014; 1.265 ++ current_registers.set(ustr__ZSesp(), 0x10014); 1.266 + cfi_frame_info.reset(resolver.FindCFIFrameInfo(&frame)); 1.267 + ASSERT_TRUE(cfi_frame_info.get()); 1.268 + ASSERT_TRUE(cfi_frame_info.get() 1.269 + ->FindCallerRegs<uint32_t>(current_registers, memory, 1.270 + &caller_registers)); 1.271 + ASSERT_TRUE(VerifyRegisters(__FILE__, __LINE__, 1.272 + expected_caller_registers, caller_registers)); 1.273 + 1.274 + frame.instruction = 0x3d43; 1.275 +- current_registers[ustr__ZSebp()] = 0x10014; 1.276 ++ current_registers.set(ustr__ZSebp(), 0x10014); 1.277 + cfi_frame_info.reset(resolver.FindCFIFrameInfo(&frame)); 1.278 + ASSERT_TRUE(cfi_frame_info.get()); 1.279 + ASSERT_TRUE(cfi_frame_info.get() 1.280 + ->FindCallerRegs<uint32_t>(current_registers, memory, 1.281 + &caller_registers)); 1.282 + VerifyRegisters(__FILE__, __LINE__, 1.283 + expected_caller_registers, caller_registers); 1.284 + 1.285 + frame.instruction = 0x3d54; 1.286 +- current_registers[ustr__ZSebx()] = 0x6864f054U; 1.287 ++ current_registers.set(ustr__ZSebx(), 0x6864f054U); 1.288 + cfi_frame_info.reset(resolver.FindCFIFrameInfo(&frame)); 1.289 + ASSERT_TRUE(cfi_frame_info.get()); 1.290 + ASSERT_TRUE(cfi_frame_info.get() 1.291 + ->FindCallerRegs<uint32_t>(current_registers, memory, 1.292 + &caller_registers)); 1.293 + VerifyRegisters(__FILE__, __LINE__, 1.294 + expected_caller_registers, caller_registers); 1.295 + 1.296 + frame.instruction = 0x3d5a; 1.297 +- current_registers[ustr__ZSesi()] = 0x6285f79aU; 1.298 ++ current_registers.set(ustr__ZSesi(), 0x6285f79aU); 1.299 + cfi_frame_info.reset(resolver.FindCFIFrameInfo(&frame)); 1.300 + ASSERT_TRUE(cfi_frame_info.get()); 1.301 + ASSERT_TRUE(cfi_frame_info.get() 1.302 + ->FindCallerRegs<uint32_t>(current_registers, memory, 1.303 + &caller_registers)); 1.304 + VerifyRegisters(__FILE__, __LINE__, 1.305 + expected_caller_registers, caller_registers); 1.306 + 1.307 + frame.instruction = 0x3d84; 1.308 +- current_registers[ustr__ZSedi()] = 0x64061449U; 1.309 ++ current_registers.set(ustr__ZSedi(), 0x64061449U); 1.310 + cfi_frame_info.reset(resolver.FindCFIFrameInfo(&frame)); 1.311 + ASSERT_TRUE(cfi_frame_info.get()); 1.312 + ASSERT_TRUE(cfi_frame_info.get() 1.313 + ->FindCallerRegs<uint32_t>(current_registers, memory, 1.314 + &caller_registers)); 1.315 + VerifyRegisters(__FILE__, __LINE__, 1.316 + expected_caller_registers, caller_registers); 1.317 + 1.318 +diff --git a/src/processor/cfi_frame_info-inl.h b/src/processor/cfi_frame_info-inl.h 1.319 +--- a/src/processor/cfi_frame_info-inl.h 1.320 ++++ b/src/processor/cfi_frame_info-inl.h 1.321 +@@ -35,64 +35,64 @@ 1.322 + 1.323 + #ifndef PROCESSOR_CFI_FRAME_INFO_INL_H_ 1.324 + #define PROCESSOR_CFI_FRAME_INFO_INL_H_ 1.325 + 1.326 + #include <string.h> 1.327 + 1.328 + namespace google_breakpad { 1.329 + 1.330 +-template <typename RegisterType, class RawContextType> 1.331 +-bool SimpleCFIWalker<RegisterType, RawContextType>::FindCallerRegisters( 1.332 ++template <typename RegisterValueType, class RawContextType> 1.333 ++bool SimpleCFIWalker<RegisterValueType, RawContextType>::FindCallerRegisters( 1.334 + const MemoryRegion &memory, 1.335 + const CFIFrameInfo &cfi_frame_info, 1.336 + const RawContextType &callee_context, 1.337 + int callee_validity, 1.338 + RawContextType *caller_context, 1.339 + int *caller_validity) const { 1.340 +- typedef CFIFrameInfo::RegisterValueMap<RegisterType> ValueMap; 1.341 ++ typedef CFIFrameInfo::RegisterValueMap<RegisterValueType> ValueMap; 1.342 + ValueMap callee_registers; 1.343 + ValueMap caller_registers; 1.344 +- // Just for brevity. 1.345 +- typename ValueMap::const_iterator caller_none = caller_registers.end(); 1.346 + 1.347 + // Populate callee_registers with register values from callee_context. 1.348 + for (size_t i = 0; i < map_size_; i++) { 1.349 + const RegisterSet &r = register_map_[i]; 1.350 + if (callee_validity & r.validity_flag) 1.351 +- callee_registers[r.name] = callee_context.*r.context_member; 1.352 ++ callee_registers.set(r.name, callee_context.*r.context_member); 1.353 + } 1.354 + 1.355 + // Apply the rules, and see what register values they yield. 1.356 +- if (!cfi_frame_info.FindCallerRegs<RegisterType>(callee_registers, memory, 1.357 +- &caller_registers)) 1.358 ++ if (!cfi_frame_info 1.359 ++ .FindCallerRegs<RegisterValueType>(callee_registers, memory, 1.360 ++ &caller_registers)) 1.361 + return false; 1.362 + 1.363 + // Populate *caller_context with the values the rules placed in 1.364 + // caller_registers. 1.365 + memset(caller_context, 0xda, sizeof(*caller_context)); 1.366 + *caller_validity = 0; 1.367 + for (size_t i = 0; i < map_size_; i++) { 1.368 + const RegisterSet &r = register_map_[i]; 1.369 +- typename ValueMap::const_iterator caller_entry; 1.370 + 1.371 + // Did the rules provide a value for this register by its name? 1.372 +- caller_entry = caller_registers.find(r.name); 1.373 +- if (caller_entry != caller_none) { 1.374 +- caller_context->*r.context_member = caller_entry->second; 1.375 ++ bool found = false; 1.376 ++ RegisterValueType v = caller_registers.get(&found, r.name); 1.377 ++ if (found) { 1.378 ++ caller_context->*r.context_member = v; 1.379 + *caller_validity |= r.validity_flag; 1.380 + continue; 1.381 + } 1.382 + 1.383 + // Did the rules provide a value for this register under its 1.384 + // alternate name? 1.385 + if (r.alternate_name) { 1.386 +- caller_entry = caller_registers.find(r.alternate_name); 1.387 +- if (caller_entry != caller_none) { 1.388 +- caller_context->*r.context_member = caller_entry->second; 1.389 ++ found = false; 1.390 ++ v = caller_registers.get(&found, r.alternate_name); 1.391 ++ if (found) { 1.392 ++ caller_context->*r.context_member = v; 1.393 + *caller_validity |= r.validity_flag; 1.394 + continue; 1.395 + } 1.396 + } 1.397 + 1.398 + // Is this a callee-saves register? The walker assumes that these 1.399 + // still hold the caller's value if the CFI doesn't mention them. 1.400 + // 1.401 +diff --git a/src/processor/cfi_frame_info.cc b/src/processor/cfi_frame_info.cc 1.402 +--- a/src/processor/cfi_frame_info.cc 1.403 ++++ b/src/processor/cfi_frame_info.cc 1.404 +@@ -66,33 +66,33 @@ 1.405 + V cfa; 1.406 + working = registers; 1.407 + if (!evaluator.EvaluateForValue(cfa_rule_, &cfa)) 1.408 + return false; 1.409 + 1.410 + // Then, compute the return address. 1.411 + V ra; 1.412 + working = registers; 1.413 +- working[ustr__ZDcfa()] = cfa; 1.414 ++ working.set(ustr__ZDcfa(), cfa); 1.415 + if (!evaluator.EvaluateForValue(ra_rule_, &ra)) 1.416 + return false; 1.417 + 1.418 + // Now, compute values for all the registers register_rules_ mentions. 1.419 + for (RuleMap::const_iterator it = register_rules_.begin(); 1.420 + it != register_rules_.end(); it++) { 1.421 + V value; 1.422 + working = registers; 1.423 +- working[ustr__ZDcfa()] = cfa; 1.424 ++ working.set(ustr__ZDcfa(), cfa); 1.425 + if (!evaluator.EvaluateForValue(it->second, &value)) 1.426 + return false; 1.427 +- (*caller_registers)[it->first] = value; 1.428 ++ caller_registers->set(it->first, value); 1.429 + } 1.430 + 1.431 +- (*caller_registers)[ustr__ZDra()] = ra; 1.432 +- (*caller_registers)[ustr__ZDcfa()] = cfa; 1.433 ++ caller_registers->set(ustr__ZDra(), ra); 1.434 ++ caller_registers->set(ustr__ZDcfa(), cfa); 1.435 + 1.436 + return true; 1.437 + } 1.438 + 1.439 + // Explicit instantiations for 32-bit and 64-bit architectures. 1.440 + template bool CFIFrameInfo::FindCallerRegs<uint32_t>( 1.441 + const RegisterValueMap<uint32_t> ®isters, 1.442 + const MemoryRegion &memory, 1.443 +diff --git a/src/processor/cfi_frame_info.h b/src/processor/cfi_frame_info.h 1.444 +--- a/src/processor/cfi_frame_info.h 1.445 ++++ b/src/processor/cfi_frame_info.h 1.446 +@@ -64,17 +64,17 @@ 1.447 + // changes given by the 'STACK CFI' records up to our instruction's 1.448 + // address. Then, use the FindCallerRegs member function to apply the 1.449 + // rules to the callee frame's register values, yielding the caller 1.450 + // frame's register values. 1.451 + class CFIFrameInfo { 1.452 + public: 1.453 + // A map from register names onto values. 1.454 + template<typename ValueType> class RegisterValueMap: 1.455 +- public map<const UniqueString*, ValueType> { }; 1.456 ++ public UniqueStringMap<ValueType> { }; 1.457 + 1.458 + // Set the expression for computing a call frame address, return 1.459 + // address, or register's value. At least the CFA rule and the RA 1.460 + // rule must be set before calling FindCallerRegs. 1.461 + void SetCFARule(const Module::Expr& rule) { cfa_rule_ = rule; } 1.462 + void SetRARule(const Module::Expr& rule) { ra_rule_ = rule; } 1.463 + void SetRegisterRule(const UniqueString* register_name, 1.464 + const Module::Expr& rule) { 1.465 +diff --git a/src/processor/cfi_frame_info_unittest.cc b/src/processor/cfi_frame_info_unittest.cc 1.466 +--- a/src/processor/cfi_frame_info_unittest.cc 1.467 ++++ b/src/processor/cfi_frame_info_unittest.cc 1.468 +@@ -111,19 +111,18 @@ 1.469 + 1.470 + TEST_F(Simple, SetCFAAndRARule) { 1.471 + ExpectNoMemoryReferences(); 1.472 + 1.473 + cfi.SetCFARule(Module::Expr("330903416631436410")); 1.474 + cfi.SetRARule(Module::Expr("5870666104170902211")); 1.475 + ASSERT_TRUE(cfi.FindCallerRegs<uint64_t>(registers, memory, 1.476 + &caller_registers)); 1.477 +- ASSERT_EQ(2U, caller_registers.size()); 1.478 +- ASSERT_EQ(330903416631436410ULL, caller_registers[ustr__ZDcfa()]); 1.479 +- ASSERT_EQ(5870666104170902211ULL, caller_registers[ustr__ZDra()]); 1.480 ++ ASSERT_EQ(330903416631436410ULL, caller_registers.get(ustr__ZDcfa())); 1.481 ++ ASSERT_EQ(5870666104170902211ULL, caller_registers.get(ustr__ZDra())); 1.482 + 1.483 + ASSERT_EQ(".cfa: 330903416631436410 .ra: 5870666104170902211", 1.484 + cfi.Serialize()); 1.485 + } 1.486 + 1.487 + TEST_F(Simple, SetManyRules) { 1.488 + ExpectNoMemoryReferences(); 1.489 + 1.490 +@@ -136,23 +135,22 @@ 1.491 + const UniqueString* reg4 = ToUniqueString("uncopyrightables"); 1.492 + 1.493 + cfi.SetRegisterRule(reg1, Module::Expr(".cfa 54370437 *")); 1.494 + cfi.SetRegisterRule(reg2, Module::Expr("24076308 .cfa +")); 1.495 + cfi.SetRegisterRule(reg3, Module::Expr(".cfa 29801007 -")); 1.496 + cfi.SetRegisterRule(reg4, Module::Expr("92642917 .cfa /")); 1.497 + ASSERT_TRUE(cfi.FindCallerRegs<uint64_t>(registers, memory, 1.498 + &caller_registers)); 1.499 +- ASSERT_EQ(6U, caller_registers.size()); 1.500 +- ASSERT_EQ(7664691U, caller_registers[ustr__ZDcfa()]); 1.501 +- ASSERT_EQ(107469446U, caller_registers[ustr__ZDra()]); 1.502 +- ASSERT_EQ(416732599139967ULL, caller_registers[reg1]); 1.503 +- ASSERT_EQ(31740999U, caller_registers[reg2]); 1.504 +- ASSERT_EQ(-22136316ULL, caller_registers[reg3]); 1.505 +- ASSERT_EQ(12U, caller_registers[reg4]); 1.506 ++ ASSERT_EQ(7664691U, caller_registers.get(ustr__ZDcfa())); 1.507 ++ ASSERT_EQ(107469446U, caller_registers.get(ustr__ZDra())); 1.508 ++ ASSERT_EQ(416732599139967ULL, caller_registers.get(reg1)); 1.509 ++ ASSERT_EQ(31740999U, caller_registers.get(reg2)); 1.510 ++ ASSERT_EQ(-22136316ULL, caller_registers.get(reg3)); 1.511 ++ ASSERT_EQ(12U, caller_registers.get(reg4)); 1.512 + ASSERT_EQ(".cfa: $temp1 68737028 = $temp2 61072337 = $temp1 $temp2 - " 1.513 + ".ra: .cfa 99804755 + " 1.514 + "pubvexingfjordschmaltzy: .cfa 29801007 - " 1.515 + "register1: .cfa 54370437 * " 1.516 + "uncopyrightables: 92642917 .cfa / " 1.517 + "vodkathumbscrewingly: 24076308 .cfa +", 1.518 + cfi.Serialize()); 1.519 + } 1.520 +@@ -160,19 +158,18 @@ 1.521 + TEST_F(Simple, RulesOverride) { 1.522 + ExpectNoMemoryReferences(); 1.523 + 1.524 + cfi.SetCFARule(Module::Expr("330903416631436410")); 1.525 + cfi.SetRARule(Module::Expr("5870666104170902211")); 1.526 + cfi.SetCFARule(Module::Expr("2828089117179001")); 1.527 + ASSERT_TRUE(cfi.FindCallerRegs<uint64_t>(registers, memory, 1.528 + &caller_registers)); 1.529 +- ASSERT_EQ(2U, caller_registers.size()); 1.530 +- ASSERT_EQ(2828089117179001ULL, caller_registers[ustr__ZDcfa()]); 1.531 +- ASSERT_EQ(5870666104170902211ULL, caller_registers[ustr__ZDra()]); 1.532 ++ ASSERT_EQ(2828089117179001ULL, caller_registers.get(ustr__ZDcfa())); 1.533 ++ ASSERT_EQ(5870666104170902211ULL, caller_registers.get(ustr__ZDra())); 1.534 + ASSERT_EQ(".cfa: 2828089117179001 .ra: 5870666104170902211", 1.535 + cfi.Serialize()); 1.536 + } 1.537 + 1.538 + class Scope: public CFIFixture, public Test { }; 1.539 + 1.540 + // There should be no value for .cfa in scope when evaluating the CFA rule. 1.541 + TEST_F(Scope, CFALacksCFA) { 1.542 +@@ -196,37 +193,35 @@ 1.543 + 1.544 + // The current frame's registers should be in scope when evaluating 1.545 + // the CFA rule. 1.546 + TEST_F(Scope, CFASeesCurrentRegs) { 1.547 + ExpectNoMemoryReferences(); 1.548 + 1.549 + const UniqueString* reg1 = ToUniqueString(".baraminology"); 1.550 + const UniqueString* reg2 = ToUniqueString(".ornithorhynchus"); 1.551 +- registers[reg1] = 0x06a7bc63e4f13893ULL; 1.552 +- registers[reg2] = 0x5e0bf850bafce9d2ULL; 1.553 ++ registers.set(reg1, 0x06a7bc63e4f13893ULL); 1.554 ++ registers.set(reg2, 0x5e0bf850bafce9d2ULL); 1.555 + cfi.SetCFARule(Module::Expr(".baraminology .ornithorhynchus +")); 1.556 + cfi.SetRARule(Module::Expr("0")); 1.557 + ASSERT_TRUE(cfi.FindCallerRegs<uint64_t>(registers, memory, 1.558 + &caller_registers)); 1.559 +- ASSERT_EQ(2U, caller_registers.size()); 1.560 + ASSERT_EQ(0x06a7bc63e4f13893ULL + 0x5e0bf850bafce9d2ULL, 1.561 +- caller_registers[ustr__ZDcfa()]); 1.562 ++ caller_registers.get(ustr__ZDcfa())); 1.563 + } 1.564 + 1.565 + // .cfa should be in scope in the return address expression. 1.566 + TEST_F(Scope, RASeesCFA) { 1.567 + ExpectNoMemoryReferences(); 1.568 + 1.569 + cfi.SetCFARule(Module::Expr("48364076")); 1.570 + cfi.SetRARule(Module::Expr(".cfa")); 1.571 + ASSERT_TRUE(cfi.FindCallerRegs<uint64_t>(registers, memory, 1.572 + &caller_registers)); 1.573 +- ASSERT_EQ(2U, caller_registers.size()); 1.574 +- ASSERT_EQ(48364076U, caller_registers[ustr__ZDra()]); 1.575 ++ ASSERT_EQ(48364076U, caller_registers.get(ustr__ZDra())); 1.576 + } 1.577 + 1.578 + // There should be no value for .ra in scope when evaluating the CFA rule. 1.579 + TEST_F(Scope, RALacksRA) { 1.580 + ExpectNoMemoryReferences(); 1.581 + 1.582 + cfi.SetCFARule(Module::Expr("0")); 1.583 + cfi.SetRARule(Module::Expr(".ra")); 1.584 +@@ -236,36 +231,34 @@ 1.585 + 1.586 + // The current frame's registers should be in scope in the return 1.587 + // address expression. 1.588 + TEST_F(Scope, RASeesCurrentRegs) { 1.589 + ExpectNoMemoryReferences(); 1.590 + 1.591 + cfi.SetCFARule(Module::Expr("10359370")); 1.592 + const UniqueString* reg1 = ToUniqueString("noachian"); 1.593 +- registers[reg1] = 0x54dc4a5d8e5eb503ULL; 1.594 ++ registers.set(reg1, 0x54dc4a5d8e5eb503ULL); 1.595 + cfi.SetRARule(Module::Expr(reg1, 0, false)); 1.596 + ASSERT_TRUE(cfi.FindCallerRegs<uint64_t>(registers, memory, 1.597 + &caller_registers)); 1.598 +- ASSERT_EQ(2U, caller_registers.size()); 1.599 +- ASSERT_EQ(0x54dc4a5d8e5eb503ULL, caller_registers[ustr__ZDra()]); 1.600 ++ ASSERT_EQ(0x54dc4a5d8e5eb503ULL, caller_registers.get(ustr__ZDra())); 1.601 + } 1.602 + 1.603 + // .cfa should be in scope for register rules. 1.604 + TEST_F(Scope, RegistersSeeCFA) { 1.605 + ExpectNoMemoryReferences(); 1.606 + 1.607 + cfi.SetCFARule(Module::Expr("6515179")); 1.608 + cfi.SetRARule(Module::Expr(".cfa")); 1.609 + const UniqueString* reg1 = ToUniqueString("rogerian"); 1.610 + cfi.SetRegisterRule(reg1, Module::Expr(".cfa")); 1.611 + ASSERT_TRUE(cfi.FindCallerRegs<uint64_t>(registers, memory, 1.612 + &caller_registers)); 1.613 +- ASSERT_EQ(3U, caller_registers.size()); 1.614 +- ASSERT_EQ(6515179U, caller_registers[reg1]); 1.615 ++ ASSERT_EQ(6515179U, caller_registers.get(reg1)); 1.616 + } 1.617 + 1.618 + // The return address should not be in scope for register rules. 1.619 + TEST_F(Scope, RegsLackRA) { 1.620 + ExpectNoMemoryReferences(); 1.621 + 1.622 + cfi.SetCFARule(Module::Expr("42740329")); 1.623 + cfi.SetRARule(Module::Expr("27045204")); 1.624 +@@ -276,27 +269,26 @@ 1.625 + } 1.626 + 1.627 + // Register rules can see the current frame's register values. 1.628 + TEST_F(Scope, RegsSeeRegs) { 1.629 + ExpectNoMemoryReferences(); 1.630 + 1.631 + const UniqueString* reg1 = ToUniqueString("$r1"); 1.632 + const UniqueString* reg2 = ToUniqueString("$r2"); 1.633 +- registers[reg1] = 0x6ed3582c4bedb9adULL; 1.634 +- registers[reg2] = 0xd27d9e742b8df6d0ULL; 1.635 ++ registers.set(reg1, 0x6ed3582c4bedb9adULL); 1.636 ++ registers.set(reg2, 0xd27d9e742b8df6d0ULL); 1.637 + cfi.SetCFARule(Module::Expr("88239303")); 1.638 + cfi.SetRARule(Module::Expr("30503835")); 1.639 + cfi.SetRegisterRule(reg1, Module::Expr("$r1 42175211 = $r2")); 1.640 + cfi.SetRegisterRule(reg2, Module::Expr("$r2 21357221 = $r1")); 1.641 + ASSERT_TRUE(cfi.FindCallerRegs<uint64_t>(registers, memory, 1.642 + &caller_registers)); 1.643 +- ASSERT_EQ(4U, caller_registers.size()); 1.644 +- ASSERT_EQ(0xd27d9e742b8df6d0ULL, caller_registers[reg1]); 1.645 +- ASSERT_EQ(0x6ed3582c4bedb9adULL, caller_registers[reg2]); 1.646 ++ ASSERT_EQ(0xd27d9e742b8df6d0ULL, caller_registers.get(reg1)); 1.647 ++ ASSERT_EQ(0x6ed3582c4bedb9adULL, caller_registers.get(reg2)); 1.648 + } 1.649 + 1.650 + // Each rule's temporaries are separate. 1.651 + TEST_F(Scope, SeparateTempsRA) { 1.652 + ExpectNoMemoryReferences(); 1.653 + 1.654 + cfi.SetCFARule(Module::Expr("$temp1 76569129 = $temp1")); 1.655 + cfi.SetRARule(Module::Expr("0")); 1.656 +@@ -440,39 +432,39 @@ 1.657 + CFIFrameInfoParseHandler handler; 1.658 + }; 1.659 + 1.660 + class ParseHandler: public ParseHandlerFixture, public Test { }; 1.661 + 1.662 + TEST_F(ParseHandler, CFARARule) { 1.663 + handler.CFARule("reg-for-cfa"); 1.664 + handler.RARule("reg-for-ra"); 1.665 +- registers[ToUniqueString("reg-for-cfa")] = 0x268a9a4a3821a797ULL; 1.666 +- registers[ToUniqueString("reg-for-ra")] = 0x6301b475b8b91c02ULL; 1.667 ++ registers.set(ToUniqueString("reg-for-cfa"), 0x268a9a4a3821a797ULL); 1.668 ++ registers.set(ToUniqueString("reg-for-ra"), 0x6301b475b8b91c02ULL); 1.669 + ASSERT_TRUE(cfi.FindCallerRegs<uint64_t>(registers, memory, 1.670 + &caller_registers)); 1.671 +- ASSERT_EQ(0x268a9a4a3821a797ULL, caller_registers[ustr__ZDcfa()]); 1.672 +- ASSERT_EQ(0x6301b475b8b91c02ULL, caller_registers[ustr__ZDra()]); 1.673 ++ ASSERT_EQ(0x268a9a4a3821a797ULL, caller_registers.get(ustr__ZDcfa())); 1.674 ++ ASSERT_EQ(0x6301b475b8b91c02ULL, caller_registers.get(ustr__ZDra())); 1.675 + } 1.676 + 1.677 + TEST_F(ParseHandler, RegisterRules) { 1.678 + handler.CFARule("reg-for-cfa"); 1.679 + handler.RARule("reg-for-ra"); 1.680 + handler.RegisterRule(ToUniqueString("reg1"), "reg-for-reg1"); 1.681 + handler.RegisterRule(ToUniqueString("reg2"), "reg-for-reg2"); 1.682 +- registers[ToUniqueString("reg-for-cfa")] = 0x268a9a4a3821a797ULL; 1.683 +- registers[ToUniqueString("reg-for-ra")] = 0x6301b475b8b91c02ULL; 1.684 +- registers[ToUniqueString("reg-for-reg1")] = 0x06cde8e2ff062481ULL; 1.685 +- registers[ToUniqueString("reg-for-reg2")] = 0xff0c4f76403173e2ULL; 1.686 ++ registers.set(ToUniqueString("reg-for-cfa"), 0x268a9a4a3821a797ULL); 1.687 ++ registers.set(ToUniqueString("reg-for-ra"), 0x6301b475b8b91c02ULL); 1.688 ++ registers.set(ToUniqueString("reg-for-reg1"), 0x06cde8e2ff062481ULL); 1.689 ++ registers.set(ToUniqueString("reg-for-reg2"), 0xff0c4f76403173e2ULL); 1.690 + ASSERT_TRUE(cfi.FindCallerRegs<uint64_t>(registers, memory, 1.691 + &caller_registers)); 1.692 +- ASSERT_EQ(0x268a9a4a3821a797ULL, caller_registers[ustr__ZDcfa()]); 1.693 +- ASSERT_EQ(0x6301b475b8b91c02ULL, caller_registers[ustr__ZDra()]); 1.694 +- ASSERT_EQ(0x06cde8e2ff062481ULL, caller_registers[ToUniqueString("reg1")]); 1.695 +- ASSERT_EQ(0xff0c4f76403173e2ULL, caller_registers[ToUniqueString("reg2")]); 1.696 ++ ASSERT_EQ(0x268a9a4a3821a797ULL, caller_registers.get(ustr__ZDcfa())); 1.697 ++ ASSERT_EQ(0x6301b475b8b91c02ULL, caller_registers.get(ustr__ZDra())); 1.698 ++ ASSERT_EQ(0x06cde8e2ff062481ULL, caller_registers.get(ToUniqueString("reg1"))); 1.699 ++ ASSERT_EQ(0xff0c4f76403173e2ULL, caller_registers.get(ToUniqueString("reg2"))); 1.700 + } 1.701 + 1.702 + struct SimpleCFIWalkerFixture { 1.703 + struct RawContext { 1.704 + uint64_t r0, r1, r2, r3, r4, sp, pc; 1.705 + }; 1.706 + enum Validity { 1.707 + R0_VALID = 0x01, 1.708 +diff --git a/src/processor/fast_source_line_resolver_unittest.cc b/src/processor/fast_source_line_resolver_unittest.cc 1.709 +--- a/src/processor/fast_source_line_resolver_unittest.cc 1.710 ++++ b/src/processor/fast_source_line_resolver_unittest.cc 1.711 +@@ -59,16 +59,17 @@ 1.712 + using google_breakpad::FromUniqueString; 1.713 + using google_breakpad::ModuleSerializer; 1.714 + using google_breakpad::ModuleComparer; 1.715 + using google_breakpad::CFIFrameInfo; 1.716 + using google_breakpad::CodeModule; 1.717 + using google_breakpad::MemoryRegion; 1.718 + using google_breakpad::StackFrame; 1.719 + using google_breakpad::ToUniqueString; 1.720 ++using google_breakpad::UniqueString; 1.721 + using google_breakpad::WindowsFrameInfo; 1.722 + using google_breakpad::linked_ptr; 1.723 + using google_breakpad::scoped_ptr; 1.724 + using google_breakpad::ustr__ZDcfa; 1.725 + using google_breakpad::ustr__ZDra; 1.726 + using google_breakpad::ustr__ZSebx; 1.727 + using google_breakpad::ustr__ZSebp; 1.728 + using google_breakpad::ustr__ZSedi; 1.729 +@@ -125,27 +126,30 @@ 1.730 + }; 1.731 + 1.732 + // Verify that, for every association in ACTUAL, EXPECTED has the same 1.733 + // association. (That is, ACTUAL's associations should be a subset of 1.734 + // EXPECTED's.) Also verify that ACTUAL has associations for ".ra" and 1.735 + // ".cfa". 1.736 + static bool VerifyRegisters( 1.737 + const char *file, int line, 1.738 +- const CFIFrameInfo::RegisterValueMap<uint32_t> &expected, 1.739 +- const CFIFrameInfo::RegisterValueMap<uint32_t> &actual) { 1.740 +- CFIFrameInfo::RegisterValueMap<uint32_t>::const_iterator a; 1.741 ++ const std::map<const UniqueString*, uint32_t> &expected, 1.742 ++ const CFIFrameInfo::RegisterValueMap<uint32_t> &actual_regmap) { 1.743 ++ std::map<const UniqueString*, uint32_t> actual; 1.744 ++ actual_regmap.copy_to_map(&actual); 1.745 ++ 1.746 ++ std::map<const UniqueString*, uint32_t>::const_iterator a; 1.747 + a = actual.find(ustr__ZDcfa()); 1.748 + if (a == actual.end()) 1.749 + return false; 1.750 + a = actual.find(ustr__ZDra()); 1.751 + if (a == actual.end()) 1.752 + return false; 1.753 + for (a = actual.begin(); a != actual.end(); a++) { 1.754 +- CFIFrameInfo::RegisterValueMap<uint32_t>::const_iterator e = 1.755 ++ std::map<const UniqueString*, uint32_t>::const_iterator e = 1.756 + expected.find(a->first); 1.757 + if (e == expected.end()) { 1.758 + fprintf(stderr, "%s:%d: unexpected register '%s' recovered, value 0x%x\n", 1.759 + file, line, FromUniqueString(a->first), a->second); 1.760 + return false; 1.761 + } 1.762 + if (e->second != a->second) { 1.763 + fprintf(stderr, 1.764 +@@ -286,86 +290,87 @@ 1.765 + 1.766 + frame.instruction = 0x3e9f; 1.767 + frame.module = &module1; 1.768 + cfi_frame_info.reset(fast_resolver.FindCFIFrameInfo(&frame)); 1.769 + ASSERT_FALSE(cfi_frame_info.get()); 1.770 + 1.771 + CFIFrameInfo::RegisterValueMap<uint32_t> current_registers; 1.772 + CFIFrameInfo::RegisterValueMap<uint32_t> caller_registers; 1.773 +- CFIFrameInfo::RegisterValueMap<uint32_t> expected_caller_registers; 1.774 ++ std::map<const UniqueString*, uint32_t> expected_caller_registers; 1.775 + MockMemoryRegion memory; 1.776 + 1.777 + // Regardless of which instruction evaluation takes place at, it 1.778 + // should produce the same values for the caller's registers. 1.779 ++ // should produce the same values for the caller's registers. 1.780 + expected_caller_registers[ustr__ZDcfa()] = 0x1001c; 1.781 +- expected_caller_registers[ustr__ZDra()] = 0xf6438648; 1.782 ++ expected_caller_registers[ustr__ZDra()] = 0xf6438648; 1.783 + expected_caller_registers[ustr__ZSebp()] = 0x10038; 1.784 + expected_caller_registers[ustr__ZSebx()] = 0x98ecadc3; 1.785 + expected_caller_registers[ustr__ZSesi()] = 0x878f7524; 1.786 + expected_caller_registers[ustr__ZSedi()] = 0x6312f9a5; 1.787 + 1.788 + frame.instruction = 0x3d40; 1.789 + frame.module = &module1; 1.790 + current_registers.clear(); 1.791 +- current_registers[ustr__ZSesp()] = 0x10018; 1.792 +- current_registers[ustr__ZSebp()] = 0x10038; 1.793 +- current_registers[ustr__ZSebx()] = 0x98ecadc3; 1.794 +- current_registers[ustr__ZSesi()] = 0x878f7524; 1.795 +- current_registers[ustr__ZSedi()] = 0x6312f9a5; 1.796 ++ current_registers.set(ustr__ZSesp(), 0x10018); 1.797 ++ current_registers.set(ustr__ZSebp(), 0x10038); 1.798 ++ current_registers.set(ustr__ZSebx(), 0x98ecadc3); 1.799 ++ current_registers.set(ustr__ZSesi(), 0x878f7524); 1.800 ++ current_registers.set(ustr__ZSedi(), 0x6312f9a5); 1.801 + cfi_frame_info.reset(fast_resolver.FindCFIFrameInfo(&frame)); 1.802 + ASSERT_TRUE(cfi_frame_info.get()); 1.803 + ASSERT_TRUE(cfi_frame_info.get() 1.804 + ->FindCallerRegs<uint32_t>(current_registers, memory, 1.805 + &caller_registers)); 1.806 + ASSERT_TRUE(VerifyRegisters(__FILE__, __LINE__, 1.807 + expected_caller_registers, caller_registers)); 1.808 + 1.809 + frame.instruction = 0x3d41; 1.810 +- current_registers[ustr__ZSesp()] = 0x10014; 1.811 ++ current_registers.set(ustr__ZSesp(), 0x10014); 1.812 + cfi_frame_info.reset(fast_resolver.FindCFIFrameInfo(&frame)); 1.813 + ASSERT_TRUE(cfi_frame_info.get()); 1.814 + ASSERT_TRUE(cfi_frame_info.get() 1.815 + ->FindCallerRegs<uint32_t>(current_registers, memory, 1.816 + &caller_registers)); 1.817 + ASSERT_TRUE(VerifyRegisters(__FILE__, __LINE__, 1.818 + expected_caller_registers, caller_registers)); 1.819 + 1.820 + frame.instruction = 0x3d43; 1.821 +- current_registers[ustr__ZSebp()] = 0x10014; 1.822 ++ current_registers.set(ustr__ZSebp(), 0x10014); 1.823 + cfi_frame_info.reset(fast_resolver.FindCFIFrameInfo(&frame)); 1.824 + ASSERT_TRUE(cfi_frame_info.get()); 1.825 + ASSERT_TRUE(cfi_frame_info.get() 1.826 + ->FindCallerRegs<uint32_t>(current_registers, memory, 1.827 + &caller_registers)); 1.828 + VerifyRegisters(__FILE__, __LINE__, 1.829 + expected_caller_registers, caller_registers); 1.830 + 1.831 + frame.instruction = 0x3d54; 1.832 +- current_registers[ustr__ZSebx()] = 0x6864f054U; 1.833 ++ current_registers.set(ustr__ZSebx(), 0x6864f054U); 1.834 + cfi_frame_info.reset(fast_resolver.FindCFIFrameInfo(&frame)); 1.835 + ASSERT_TRUE(cfi_frame_info.get()); 1.836 + ASSERT_TRUE(cfi_frame_info.get() 1.837 + ->FindCallerRegs<uint32_t>(current_registers, memory, 1.838 + &caller_registers)); 1.839 + VerifyRegisters(__FILE__, __LINE__, 1.840 + expected_caller_registers, caller_registers); 1.841 + 1.842 + frame.instruction = 0x3d5a; 1.843 +- current_registers[ustr__ZSesi()] = 0x6285f79aU; 1.844 ++ current_registers.set(ustr__ZSesi(), 0x6285f79aU); 1.845 + cfi_frame_info.reset(fast_resolver.FindCFIFrameInfo(&frame)); 1.846 + ASSERT_TRUE(cfi_frame_info.get()); 1.847 + ASSERT_TRUE(cfi_frame_info.get() 1.848 + ->FindCallerRegs<uint32_t>(current_registers, memory, 1.849 + &caller_registers)); 1.850 + VerifyRegisters(__FILE__, __LINE__, 1.851 + expected_caller_registers, caller_registers); 1.852 + 1.853 + frame.instruction = 0x3d84; 1.854 +- current_registers[ustr__ZSedi()] = 0x64061449U; 1.855 ++ current_registers.set(ustr__ZSedi(), 0x64061449U); 1.856 + cfi_frame_info.reset(fast_resolver.FindCFIFrameInfo(&frame)); 1.857 + ASSERT_TRUE(cfi_frame_info.get()); 1.858 + ASSERT_TRUE(cfi_frame_info.get() 1.859 + ->FindCallerRegs<uint32_t>(current_registers, memory, 1.860 + &caller_registers)); 1.861 + VerifyRegisters(__FILE__, __LINE__, 1.862 + expected_caller_registers, caller_registers); 1.863 + 1.864 +diff --git a/src/processor/postfix_evaluator-inl.h b/src/processor/postfix_evaluator-inl.h 1.865 +--- a/src/processor/postfix_evaluator-inl.h 1.866 ++++ b/src/processor/postfix_evaluator-inl.h 1.867 +@@ -185,19 +185,19 @@ 1.868 + return false; 1.869 + } 1.870 + if (identifier == ustr__empty() || Index(identifier,0) != '$') { 1.871 + BPLOG(ERROR) << "Can't assign " << HexString(value) << " to " << 1.872 + identifier << ": " << expression; 1.873 + return false; 1.874 + } 1.875 + 1.876 +- (*dictionary_)[identifier] = value; 1.877 ++ dictionary_->set(identifier, value); 1.878 + if (assigned) 1.879 +- (*assigned)[identifier] = true; 1.880 ++ assigned->set(identifier, true); 1.881 + } else { 1.882 + // Push it onto the stack as-is, but first convert it either to a 1.883 + // ValueType (if a literal) or to a UniqueString* (if an identifier). 1.884 + // 1.885 + // First, try to treat the value as a literal. Literals may have leading 1.886 + // '-' sign, and the entire remaining string must be parseable as 1.887 + // ValueType. If this isn't possible, it can't be a literal, so treat it 1.888 + // as an identifier instead. 1.889 +@@ -300,28 +300,28 @@ 1.890 + 1.891 + return PopValue(result); 1.892 + } 1.893 + 1.894 + // Simple-form expressions 1.895 + case Module::kExprSimple: 1.896 + case Module::kExprSimpleMem: { 1.897 + // Look up the base value 1.898 +- typename DictionaryType::const_iterator iterator 1.899 +- = dictionary_->find(expr.ident_); 1.900 +- if (iterator == dictionary_->end()) { 1.901 ++ bool found = false; 1.902 ++ ValueType v = dictionary_->get(&found, expr.ident_); 1.903 ++ if (!found) { 1.904 + // The identifier wasn't found in the dictionary. Don't imply any 1.905 + // default value, just fail. 1.906 +- BPLOG(INFO) << "Identifier " << expr.ident_ 1.907 ++ BPLOG(INFO) << "Identifier " << FromUniqueString(expr.ident_) 1.908 + << " not in dictionary (kExprSimple{Mem})"; 1.909 + return false; 1.910 + } 1.911 + 1.912 + // Form the sum 1.913 +- ValueType sum = iterator->second + (int64_t)expr.offset_; 1.914 ++ ValueType sum = v + (int64_t)expr.offset_; 1.915 + 1.916 + // and dereference if necessary 1.917 + if (expr.how_ == Module::kExprSimpleMem) { 1.918 + ValueType derefd; 1.919 + if (!memory_ || !memory_->GetMemoryAtAddress(sum, &derefd)) { 1.920 + return false; 1.921 + } 1.922 + *result = derefd; 1.923 +@@ -368,27 +368,27 @@ 1.924 + if ((result = PopValueOrIdentifier(&literal, &token)) == POP_RESULT_FAIL) { 1.925 + return false; 1.926 + } else if (result == POP_RESULT_VALUE) { 1.927 + // This is the easy case. 1.928 + *value = literal; 1.929 + } else { // result == POP_RESULT_IDENTIFIER 1.930 + // There was an identifier at the top of the stack. Resolve it to a 1.931 + // value by looking it up in the dictionary. 1.932 +- typename DictionaryType::const_iterator iterator = 1.933 +- dictionary_->find(token); 1.934 +- if (iterator == dictionary_->end()) { 1.935 ++ bool found = false; 1.936 ++ ValueType v = dictionary_->get(&found, token); 1.937 ++ if (!found) { 1.938 + // The identifier wasn't found in the dictionary. Don't imply any 1.939 + // default value, just fail. 1.940 + BPLOG(INFO) << "Identifier " << FromUniqueString(token) 1.941 + << " not in dictionary"; 1.942 + return false; 1.943 + } 1.944 + 1.945 +- *value = iterator->second; 1.946 ++ *value = v; 1.947 + } 1.948 + 1.949 + return true; 1.950 + } 1.951 + 1.952 + 1.953 + template<typename ValueType> 1.954 + bool PostfixEvaluator<ValueType>::PopValues(ValueType *value1, 1.955 +diff --git a/src/processor/postfix_evaluator.h b/src/processor/postfix_evaluator.h 1.956 +--- a/src/processor/postfix_evaluator.h 1.957 ++++ b/src/processor/postfix_evaluator.h 1.958 +@@ -93,18 +93,18 @@ 1.959 + StackElem(const UniqueString* ustr) { isValue = false; u.ustr = ustr; } 1.960 + bool isValue; 1.961 + union { ValueType val; const UniqueString* ustr; } u; 1.962 + }; 1.963 + 1.964 + template<typename ValueType> 1.965 + class PostfixEvaluator { 1.966 + public: 1.967 +- typedef map<const UniqueString*, ValueType> DictionaryType; 1.968 +- typedef map<const UniqueString*, bool> DictionaryValidityType; 1.969 ++ typedef UniqueStringMap<ValueType> DictionaryType; 1.970 ++ typedef UniqueStringMap<bool> DictionaryValidityType; 1.971 + 1.972 + // Create a PostfixEvaluator object that may be used (with Evaluate) on 1.973 + // one or more expressions. PostfixEvaluator does not take ownership of 1.974 + // either argument. |memory| may be NULL, in which case dereferencing 1.975 + // (^) will not be supported. |dictionary| may be NULL, but evaluation 1.976 + // will fail in that case unless set_dictionary is used before calling 1.977 + // Evaluate. 1.978 + PostfixEvaluator(DictionaryType *dictionary, const MemoryRegion *memory) 1.979 +diff --git a/src/processor/postfix_evaluator_unittest.cc b/src/processor/postfix_evaluator_unittest.cc 1.980 +--- a/src/processor/postfix_evaluator_unittest.cc 1.981 ++++ b/src/processor/postfix_evaluator_unittest.cc 1.982 +@@ -178,22 +178,22 @@ 1.983 + validate_data_0[ToUniqueString("$rAdd3")] = 4; 1.984 + validate_data_0[ToUniqueString("$rMul2")] = 54; 1.985 + 1.986 + // The second test set simulates a couple of MSVC program strings. 1.987 + // The data is fudged a little bit because the tests use FakeMemoryRegion 1.988 + // instead of a real stack snapshot, but the program strings are real and 1.989 + // the implementation doesn't know or care that the data is not real. 1.990 + PostfixEvaluator<unsigned int>::DictionaryType dictionary_1; 1.991 +- dictionary_1[ustr__ZSebp()] = 0xbfff0010; 1.992 +- dictionary_1[ustr__ZSeip()] = 0x10000000; 1.993 +- dictionary_1[ustr__ZSesp()] = 0xbfff0000; 1.994 +- dictionary_1[ustr__ZDcbSavedRegs()] = 4; 1.995 +- dictionary_1[ustr__ZDcbParams()] = 4; 1.996 +- dictionary_1[ustr__ZDraSearchStart()] = 0xbfff0020; 1.997 ++ dictionary_1.set(ustr__ZSebp(), 0xbfff0010); 1.998 ++ dictionary_1.set(ustr__ZSeip(), 0x10000000); 1.999 ++ dictionary_1.set(ustr__ZSesp(), 0xbfff0000); 1.1000 ++ dictionary_1.set(ustr__ZDcbSavedRegs(), 4); 1.1001 ++ dictionary_1.set(ustr__ZDcbParams(), 4); 1.1002 ++ dictionary_1.set(ustr__ZDraSearchStart(), 0xbfff0020); 1.1003 + const EvaluateTest evaluate_tests_1[] = { 1.1004 + { "$T0 $ebp = $eip $T0 4 + ^ = $ebp $T0 ^ = $esp $T0 8 + = " 1.1005 + "$L $T0 .cbSavedRegs - = $P $T0 8 + .cbParams + =", true }, 1.1006 + // Intermediate state: $T0 = 0xbfff0010, $eip = 0xbfff0015, 1.1007 + // $ebp = 0xbfff0011, $esp = 0xbfff0018, 1.1008 + // $L = 0xbfff000c, $P = 0xbfff001c 1.1009 + { "$T0 $ebp = $eip $T0 4 + ^ = $ebp $T0 ^ = $esp $T0 8 + = " 1.1010 + "$L $T0 .cbSavedRegs - = $P $T0 8 + .cbParams + = $ebx $T0 28 - ^ =", 1.1011 +@@ -273,70 +273,65 @@ 1.1012 + for (map<const UniqueString*, unsigned int>::const_iterator 1.1013 + validate_iterator = 1.1014 + evaluate_test_set->validate_data->begin(); 1.1015 + validate_iterator != evaluate_test_set->validate_data->end(); 1.1016 + ++validate_iterator) { 1.1017 + const UniqueString* identifier = validate_iterator->first; 1.1018 + unsigned int expected_value = validate_iterator->second; 1.1019 + 1.1020 +- map<const UniqueString*, unsigned int>::const_iterator 1.1021 +- dictionary_iterator = 1.1022 +- evaluate_test_set->dictionary->find(identifier); 1.1023 +- 1.1024 + // The identifier must exist in the dictionary. 1.1025 +- if (dictionary_iterator == evaluate_test_set->dictionary->end()) { 1.1026 ++ if (!evaluate_test_set->dictionary->have(identifier)) { 1.1027 + fprintf(stderr, "FAIL: evaluate test set %d/%d, " 1.1028 + "validate identifier \"%s\", " 1.1029 + "expected %d, observed not found\n", 1.1030 + evaluate_test_set_index, evaluate_test_set_count, 1.1031 + FromUniqueString(identifier), expected_value); 1.1032 + return false; 1.1033 + } 1.1034 + 1.1035 + // The value in the dictionary must be the same as the expected value. 1.1036 +- unsigned int observed_value = dictionary_iterator->second; 1.1037 ++ unsigned int observed_value = 1.1038 ++ evaluate_test_set->dictionary->get(identifier); 1.1039 + if (expected_value != observed_value) { 1.1040 + fprintf(stderr, "FAIL: evaluate test set %d/%d, " 1.1041 + "validate identifier \"%s\", " 1.1042 + "expected %d, observed %d\n", 1.1043 + evaluate_test_set_index, evaluate_test_set_count, 1.1044 + FromUniqueString(identifier), expected_value, observed_value); 1.1045 + return false; 1.1046 + } 1.1047 + 1.1048 + // The value must be set in the "assigned" dictionary if it was a 1.1049 + // variable. It must not have been assigned if it was a constant. 1.1050 + bool expected_assigned = FromUniqueString(identifier)[0] == '$'; 1.1051 + bool observed_assigned = false; 1.1052 +- PostfixEvaluator<unsigned int>::DictionaryValidityType::const_iterator 1.1053 +- iterator_assigned = assigned.find(identifier); 1.1054 +- if (iterator_assigned != assigned.end()) { 1.1055 +- observed_assigned = iterator_assigned->second; 1.1056 ++ if (assigned.have(identifier)) { 1.1057 ++ observed_assigned = assigned.get(identifier); 1.1058 + } 1.1059 + if (expected_assigned != observed_assigned) { 1.1060 + fprintf(stderr, "FAIL: evaluate test set %d/%d, " 1.1061 + "validate assignment of \"%s\", " 1.1062 + "expected %d, observed %d\n", 1.1063 + evaluate_test_set_index, evaluate_test_set_count, 1.1064 + FromUniqueString(identifier), expected_assigned, 1.1065 + observed_assigned); 1.1066 + return false; 1.1067 + } 1.1068 + } 1.1069 + } 1.1070 + 1.1071 + // EvaluateForValue tests. 1.1072 + PostfixEvaluator<unsigned int>::DictionaryType dictionary_2; 1.1073 +- dictionary_2[ustr__ZSebp()] = 0xbfff0010; 1.1074 +- dictionary_2[ustr__ZSeip()] = 0x10000000; 1.1075 +- dictionary_2[ustr__ZSesp()] = 0xbfff0000; 1.1076 +- dictionary_2[ustr__ZDcbSavedRegs()] = 4; 1.1077 +- dictionary_2[ustr__ZDcbParams()] = 4; 1.1078 +- dictionary_2[ustr__ZDraSearchStart()] = 0xbfff0020; 1.1079 ++ dictionary_2.set(ustr__ZSebp(), 0xbfff0010); 1.1080 ++ dictionary_2.set(ustr__ZSeip(), 0x10000000); 1.1081 ++ dictionary_2.set(ustr__ZSesp(), 0xbfff0000); 1.1082 ++ dictionary_2.set(ustr__ZDcbSavedRegs(), 4); 1.1083 ++ dictionary_2.set(ustr__ZDcbParams(), 4); 1.1084 ++ dictionary_2.set(ustr__ZDraSearchStart(), 0xbfff0020); 1.1085 + const EvaluateForValueTest evaluate_for_value_tests_2[] = { 1.1086 + { "28907223", true, 28907223 }, // simple constant 1.1087 + { "89854293 40010015 +", true, 89854293 + 40010015 }, // arithmetic 1.1088 + { "-870245 8769343 +", true, 7899098 }, // negative constants 1.1089 + { "$ebp $esp - $eip +", true, 0x10000010 }, // variable references 1.1090 + { "18929794 34015074", false, 0 }, // too many values 1.1091 + { "$ebp $ebp 4 - =", false, 0 }, // too few values 1.1092 + { "$new $eip = $new", true, 0x10000000 }, // make new variable 1.1093 +@@ -370,41 +365,43 @@ 1.1094 + if (test->evaluable && result != test->value) { 1.1095 + fprintf(stderr, "FAIL: evaluate for value test %d, " 1.1096 + "expected value to be 0x%x, but it was 0x%x\n", 1.1097 + i, test->value, result); 1.1098 + return false; 1.1099 + } 1.1100 + } 1.1101 + 1.1102 ++ map<const UniqueString*, unsigned int> dictionary_2_map; 1.1103 ++ dictionary_2.copy_to_map(&dictionary_2_map); 1.1104 + for (map<const UniqueString*, unsigned int>::iterator v = 1.1105 + validate_data_2.begin(); 1.1106 + v != validate_data_2.end(); v++) { 1.1107 + map<const UniqueString*, unsigned int>::iterator a = 1.1108 +- dictionary_2.find(v->first); 1.1109 +- if (a == dictionary_2.end()) { 1.1110 ++ dictionary_2_map.find(v->first); 1.1111 ++ if (a == dictionary_2_map.end()) { 1.1112 + fprintf(stderr, "FAIL: evaluate for value dictionary check: " 1.1113 + "expected dict[\"%s\"] to be 0x%x, but it was unset\n", 1.1114 + FromUniqueString(v->first), v->second); 1.1115 + return false; 1.1116 + } else if (a->second != v->second) { 1.1117 + fprintf(stderr, "FAIL: evaluate for value dictionary check: " 1.1118 + "expected dict[\"%s\"] to be 0x%x, but it was 0x%x\n", 1.1119 + FromUniqueString(v->first), v->second, a->second); 1.1120 + return false; 1.1121 +- } 1.1122 +- dictionary_2.erase(a); 1.1123 ++ } 1.1124 ++ dictionary_2_map.erase(a); 1.1125 + } 1.1126 +- 1.1127 ++ 1.1128 + map<const UniqueString*, unsigned int>::iterator remaining = 1.1129 +- dictionary_2.begin(); 1.1130 +- if (remaining != dictionary_2.end()) { 1.1131 ++ dictionary_2_map.begin(); 1.1132 ++ if (remaining != dictionary_2_map.end()) { 1.1133 + fprintf(stderr, "FAIL: evaluation of test expressions put unexpected " 1.1134 + "values in dictionary:\n"); 1.1135 +- for (; remaining != dictionary_2.end(); remaining++) 1.1136 ++ for (; remaining != dictionary_2_map.end(); remaining++) 1.1137 + fprintf(stderr, " dict[\"%s\"] == 0x%x\n", 1.1138 + FromUniqueString(remaining->first), remaining->second); 1.1139 + return false; 1.1140 + } 1.1141 + 1.1142 + return true; 1.1143 + } 1.1144 + 1.1145 +diff --git a/src/processor/stackwalker_arm.cc b/src/processor/stackwalker_arm.cc 1.1146 +--- a/src/processor/stackwalker_arm.cc 1.1147 ++++ b/src/processor/stackwalker_arm.cc 1.1148 +@@ -97,70 +97,70 @@ 1.1149 + ToUniqueString("fps"), ToUniqueString("cpsr"), 1.1150 + NULL 1.1151 + }; 1.1152 + 1.1153 + // Populate a dictionary with the valid register values in last_frame. 1.1154 + CFIFrameInfo::RegisterValueMap<uint32_t> callee_registers; 1.1155 + for (int i = 0; register_names[i]; i++) 1.1156 + if (last_frame->context_validity & StackFrameARM::RegisterValidFlag(i)) 1.1157 +- callee_registers[register_names[i]] = last_frame->context.iregs[i]; 1.1158 ++ callee_registers.set(register_names[i], last_frame->context.iregs[i]); 1.1159 + 1.1160 + // Use the STACK CFI data to recover the caller's register values. 1.1161 + CFIFrameInfo::RegisterValueMap<uint32_t> caller_registers; 1.1162 + if (!cfi_frame_info->FindCallerRegs(callee_registers, *memory_, 1.1163 + &caller_registers)) 1.1164 + return NULL; 1.1165 + 1.1166 + // Construct a new stack frame given the values the CFI recovered. 1.1167 + scoped_ptr<StackFrameARM> frame(new StackFrameARM()); 1.1168 + for (int i = 0; register_names[i]; i++) { 1.1169 +- CFIFrameInfo::RegisterValueMap<uint32_t>::iterator entry = 1.1170 +- caller_registers.find(register_names[i]); 1.1171 +- if (entry != caller_registers.end()) { 1.1172 ++ bool found = false; 1.1173 ++ uint32_t v = caller_registers.get(&found, register_names[i]); 1.1174 ++ if (found) { 1.1175 + // We recovered the value of this register; fill the context with the 1.1176 + // value from caller_registers. 1.1177 + frame->context_validity |= StackFrameARM::RegisterValidFlag(i); 1.1178 +- frame->context.iregs[i] = entry->second; 1.1179 ++ frame->context.iregs[i] = v; 1.1180 + } else if (4 <= i && i <= 11 && (last_frame->context_validity & 1.1181 + StackFrameARM::RegisterValidFlag(i))) { 1.1182 + // If the STACK CFI data doesn't mention some callee-saves register, and 1.1183 + // it is valid in the callee, assume the callee has not yet changed it. 1.1184 + // Registers r4 through r11 are callee-saves, according to the Procedure 1.1185 + // Call Standard for the ARM Architecture, which the Linux ABI follows. 1.1186 + frame->context_validity |= StackFrameARM::RegisterValidFlag(i); 1.1187 + frame->context.iregs[i] = last_frame->context.iregs[i]; 1.1188 + } 1.1189 + } 1.1190 + // If the CFI doesn't recover the PC explicitly, then use .ra. 1.1191 + if (!(frame->context_validity & StackFrameARM::CONTEXT_VALID_PC)) { 1.1192 +- CFIFrameInfo::RegisterValueMap<uint32_t>::iterator entry = 1.1193 +- caller_registers.find(ustr__ZDra()); 1.1194 +- if (entry != caller_registers.end()) { 1.1195 ++ bool found = false; 1.1196 ++ uint32_t v = caller_registers.get(&found, ustr__ZDra()); 1.1197 ++ if (found) { 1.1198 + if (fp_register_ == -1) { 1.1199 + frame->context_validity |= StackFrameARM::CONTEXT_VALID_PC; 1.1200 +- frame->context.iregs[MD_CONTEXT_ARM_REG_PC] = entry->second; 1.1201 ++ frame->context.iregs[MD_CONTEXT_ARM_REG_PC] = v; 1.1202 + } else { 1.1203 + // The CFI updated the link register and not the program counter. 1.1204 + // Handle getting the program counter from the link register. 1.1205 + frame->context_validity |= StackFrameARM::CONTEXT_VALID_PC; 1.1206 + frame->context_validity |= StackFrameARM::CONTEXT_VALID_LR; 1.1207 +- frame->context.iregs[MD_CONTEXT_ARM_REG_LR] = entry->second; 1.1208 ++ frame->context.iregs[MD_CONTEXT_ARM_REG_LR] = v; 1.1209 + frame->context.iregs[MD_CONTEXT_ARM_REG_PC] = 1.1210 + last_frame->context.iregs[MD_CONTEXT_ARM_REG_LR]; 1.1211 + } 1.1212 + } 1.1213 + } 1.1214 + // If the CFI doesn't recover the SP explicitly, then use .cfa. 1.1215 + if (!(frame->context_validity & StackFrameARM::CONTEXT_VALID_SP)) { 1.1216 +- CFIFrameInfo::RegisterValueMap<uint32_t>::iterator entry = 1.1217 +- caller_registers.find(ustr__ZDcfa()); 1.1218 +- if (entry != caller_registers.end()) { 1.1219 ++ bool found = false; 1.1220 ++ uint32_t v = caller_registers.get(&found, ustr__ZDcfa()); 1.1221 ++ if (found) { 1.1222 + frame->context_validity |= StackFrameARM::CONTEXT_VALID_SP; 1.1223 +- frame->context.iregs[MD_CONTEXT_ARM_REG_SP] = entry->second; 1.1224 ++ frame->context.iregs[MD_CONTEXT_ARM_REG_SP] = v; 1.1225 + } 1.1226 + } 1.1227 + 1.1228 + // If we didn't recover the PC and the SP, then the frame isn't very useful. 1.1229 + static const int essentials = (StackFrameARM::CONTEXT_VALID_SP 1.1230 + | StackFrameARM::CONTEXT_VALID_PC); 1.1231 + if ((frame->context_validity & essentials) != essentials) 1.1232 + return NULL; 1.1233 +diff --git a/src/processor/stackwalker_x86.cc b/src/processor/stackwalker_x86.cc 1.1234 +--- a/src/processor/stackwalker_x86.cc 1.1235 ++++ b/src/processor/stackwalker_x86.cc 1.1236 +@@ -194,26 +194,26 @@ 1.1237 + } 1.1238 + } 1.1239 + 1.1240 + // Set up the dictionary for the PostfixEvaluator. %ebp and %esp are used 1.1241 + // in each program string, and their previous values are known, so set them 1.1242 + // here. 1.1243 + PostfixEvaluator<uint32_t>::DictionaryType dictionary; 1.1244 + // Provide the current register values. 1.1245 +- dictionary[ustr__ZSebp()] = last_frame->context.ebp; 1.1246 +- dictionary[ustr__ZSesp()] = last_frame->context.esp; 1.1247 ++ dictionary.set(ustr__ZSebp(), last_frame->context.ebp); 1.1248 ++ dictionary.set(ustr__ZSesp(), last_frame->context.esp); 1.1249 + // Provide constants from the debug info for last_frame and its callee. 1.1250 + // .cbCalleeParams is a Breakpad extension that allows us to use the 1.1251 + // PostfixEvaluator engine when certain types of debugging information 1.1252 + // are present without having to write the constants into the program 1.1253 + // string as literals. 1.1254 +- dictionary[ustr__ZDcbCalleeParams()] = last_frame_callee_parameter_size; 1.1255 +- dictionary[ustr__ZDcbSavedRegs()] = last_frame_info->saved_register_size; 1.1256 +- dictionary[ustr__ZDcbLocals()] = last_frame_info->local_size; 1.1257 ++ dictionary.set(ustr__ZDcbCalleeParams(), last_frame_callee_parameter_size); 1.1258 ++ dictionary.set(ustr__ZDcbSavedRegs(), last_frame_info->saved_register_size); 1.1259 ++ dictionary.set(ustr__ZDcbLocals(), last_frame_info->local_size); 1.1260 + 1.1261 + uint32_t raSearchStart = last_frame->context.esp + 1.1262 + last_frame_callee_parameter_size + 1.1263 + last_frame_info->local_size + 1.1264 + last_frame_info->saved_register_size; 1.1265 + 1.1266 + uint32_t raSearchStartOld = raSearchStart; 1.1267 + uint32_t found = 0; // dummy value 1.1268 +@@ -232,20 +232,20 @@ 1.1269 + // Skip one slot from the stack and do another scan in order to get the 1.1270 + // actual return address. 1.1271 + raSearchStart += 4; 1.1272 + ScanForReturnAddress(raSearchStart, &raSearchStart, &found, 3); 1.1273 + } 1.1274 + 1.1275 + // The difference between raSearch and raSearchStart is unknown, 1.1276 + // but making them the same seems to work well in practice. 1.1277 +- dictionary[ustr__ZDraSearchStart()] = raSearchStart; 1.1278 +- dictionary[ustr__ZDraSearch()] = raSearchStart; 1.1279 ++ dictionary.set(ustr__ZDraSearchStart(), raSearchStart); 1.1280 ++ dictionary.set(ustr__ZDraSearch(), raSearchStart); 1.1281 + 1.1282 +- dictionary[ustr__ZDcbParams()] = last_frame_info->parameter_size; 1.1283 ++ dictionary.set(ustr__ZDcbParams(), last_frame_info->parameter_size); 1.1284 + 1.1285 + // Decide what type of program string to use. The program string is in 1.1286 + // postfix notation and will be passed to PostfixEvaluator::Evaluate. 1.1287 + // Given the dictionary and the program string, it is possible to compute 1.1288 + // the return address and the values of other registers in the calling 1.1289 + // function. Because of bugs described below, the stack may need to be 1.1290 + // scanned for these values. The results of program string evaluation 1.1291 + // will be used to determine whether to scan for better values. 1.1292 +@@ -325,18 +325,18 @@ 1.1293 + } 1.1294 + 1.1295 + // Now crank it out, making sure that the program string set at least the 1.1296 + // two required variables. 1.1297 + PostfixEvaluator<uint32_t> evaluator = 1.1298 + PostfixEvaluator<uint32_t>(&dictionary, memory_); 1.1299 + PostfixEvaluator<uint32_t>::DictionaryValidityType dictionary_validity; 1.1300 + if (!evaluator.Evaluate(program_string, &dictionary_validity) || 1.1301 +- dictionary_validity.find(ustr__ZSeip()) == dictionary_validity.end() || 1.1302 +- dictionary_validity.find(ustr__ZSesp()) == dictionary_validity.end()) { 1.1303 ++ !dictionary_validity.have(ustr__ZSeip()) || 1.1304 ++ !dictionary_validity.have(ustr__ZSesp())) { 1.1305 + // Program string evaluation failed. It may be that %eip is not somewhere 1.1306 + // with stack frame info, and %ebp is pointing to non-stack memory, so 1.1307 + // our evaluation couldn't succeed. We'll scan the stack for a return 1.1308 + // address. This can happen if the stack is in a module for which 1.1309 + // we don't have symbols, and that module is compiled without a 1.1310 + // frame pointer. 1.1311 + uint32_t location_start = last_frame->context.esp; 1.1312 + uint32_t location, eip; 1.1313 +@@ -344,69 +344,70 @@ 1.1314 + // if we can't find an instruction pointer even with stack scanning, 1.1315 + // give up. 1.1316 + return NULL; 1.1317 + } 1.1318 + 1.1319 + // This seems like a reasonable return address. Since program string 1.1320 + // evaluation failed, use it and set %esp to the location above the 1.1321 + // one where the return address was found. 1.1322 +- dictionary[ustr__ZSeip()] = eip; 1.1323 +- dictionary[ustr__ZSesp()] = location + 4; 1.1324 ++ dictionary.set(ustr__ZSeip(), eip); 1.1325 ++ dictionary.set(ustr__ZSesp(), location + 4); 1.1326 + trust = StackFrame::FRAME_TRUST_SCAN; 1.1327 + } 1.1328 + 1.1329 + // Since this stack frame did not use %ebp in a traditional way, 1.1330 + // locating the return address isn't entirely deterministic. In that 1.1331 + // case, the stack can be scanned to locate the return address. 1.1332 + // 1.1333 + // However, if program string evaluation resulted in both %eip and 1.1334 + // %ebp values of 0, trust that the end of the stack has been 1.1335 + // reached and don't scan for anything else. 1.1336 +- if (dictionary[ustr__ZSeip()] != 0 || dictionary[ustr__ZSebp()] != 0) { 1.1337 ++ if (dictionary.get(ustr__ZSeip()) != 0 || 1.1338 ++ dictionary.get(ustr__ZSebp()) != 0) { 1.1339 + int offset = 0; 1.1340 + 1.1341 + // This scan can only be done if a CodeModules object is available, to 1.1342 + // check that candidate return addresses are in fact inside a module. 1.1343 + // 1.1344 + // TODO(mmentovai): This ignores dynamically-generated code. One possible 1.1345 + // solution is to check the minidump's memory map to see if the candidate 1.1346 + // %eip value comes from a mapped executable page, although this would 1.1347 + // require dumps that contain MINIDUMP_MEMORY_INFO, which the Breakpad 1.1348 + // client doesn't currently write (it would need to call MiniDumpWriteDump 1.1349 + // with the MiniDumpWithFullMemoryInfo type bit set). Even given this 1.1350 + // ability, older OSes (pre-XP SP2) and CPUs (pre-P4) don't enforce 1.1351 + // an independent execute privilege on memory pages. 1.1352 + 1.1353 +- uint32_t eip = dictionary[ustr__ZSeip()]; 1.1354 ++ uint32_t eip = dictionary.get(ustr__ZSeip()); 1.1355 + if (modules_ && !modules_->GetModuleForAddress(eip)) { 1.1356 + // The instruction pointer at .raSearchStart was invalid, so start 1.1357 + // looking one 32-bit word above that location. 1.1358 +- uint32_t location_start = dictionary[ustr__ZDraSearchStart()] + 4; 1.1359 ++ uint32_t location_start = dictionary.get(ustr__ZDraSearchStart()) + 4; 1.1360 + uint32_t location; 1.1361 + if (ScanForReturnAddress(location_start, &location, &eip)) { 1.1362 + // This is a better return address that what program string 1.1363 + // evaluation found. Use it, and set %esp to the location above the 1.1364 + // one where the return address was found. 1.1365 +- dictionary[ustr__ZSeip()] = eip; 1.1366 +- dictionary[ustr__ZSesp()] = location + 4; 1.1367 ++ dictionary.set(ustr__ZSeip(), eip); 1.1368 ++ dictionary.set(ustr__ZSesp(), location + 4); 1.1369 + offset = location - location_start; 1.1370 + trust = StackFrame::FRAME_TRUST_CFI_SCAN; 1.1371 + } 1.1372 + } 1.1373 + 1.1374 + if (recover_ebp) { 1.1375 + // When trying to recover the previous value of the frame pointer (%ebp), 1.1376 + // start looking at the lowest possible address in the saved-register 1.1377 + // area, and look at the entire saved register area, increased by the 1.1378 + // size of |offset| to account for additional data that may be on the 1.1379 + // stack. The scan is performed from the highest possible address to 1.1380 + // the lowest, because the expectation is that the function's prolog 1.1381 + // would have saved %ebp early. 1.1382 +- uint32_t ebp = dictionary[ustr__ZSebp()]; 1.1383 ++ uint32_t ebp = dictionary.get(ustr__ZSebp()); 1.1384 + 1.1385 + // When a scan for return address is used, it is possible to skip one or 1.1386 + // more frames (when return address is not in a known module). One 1.1387 + // indication for skipped frames is when the value of %ebp is lower than 1.1388 + // the location of the return address on the stack 1.1389 + bool has_skipped_frames = 1.1390 + (trust != StackFrame::FRAME_TRUST_CFI && ebp <= raSearchStart + offset); 1.1391 + 1.1392 +@@ -420,49 +421,49 @@ 1.1393 + location >= location_end; 1.1394 + location -= 4) { 1.1395 + if (!memory_->GetMemoryAtAddress(location, &ebp)) 1.1396 + break; 1.1397 + 1.1398 + if (memory_->GetMemoryAtAddress(ebp, &value)) { 1.1399 + // The candidate value is a pointer to the same memory region 1.1400 + // (the stack). Prefer it as a recovered %ebp result. 1.1401 +- dictionary[ustr__ZSebp()] = ebp; 1.1402 ++ dictionary.set(ustr__ZSebp(), ebp); 1.1403 + break; 1.1404 + } 1.1405 + } 1.1406 + } 1.1407 + } 1.1408 + } 1.1409 + 1.1410 + // Create a new stack frame (ownership will be transferred to the caller) 1.1411 + // and fill it in. 1.1412 + StackFrameX86* frame = new StackFrameX86(); 1.1413 + 1.1414 + frame->trust = trust; 1.1415 + frame->context = last_frame->context; 1.1416 +- frame->context.eip = dictionary[ustr__ZSeip()]; 1.1417 +- frame->context.esp = dictionary[ustr__ZSesp()]; 1.1418 +- frame->context.ebp = dictionary[ustr__ZSebp()]; 1.1419 ++ frame->context.eip = dictionary.get(ustr__ZSeip()); 1.1420 ++ frame->context.esp = dictionary.get(ustr__ZSesp()); 1.1421 ++ frame->context.ebp = dictionary.get(ustr__ZSebp()); 1.1422 + frame->context_validity = StackFrameX86::CONTEXT_VALID_EIP | 1.1423 + StackFrameX86::CONTEXT_VALID_ESP | 1.1424 + StackFrameX86::CONTEXT_VALID_EBP; 1.1425 + 1.1426 + // These are nonvolatile (callee-save) registers, and the program string 1.1427 + // may have filled them in. 1.1428 +- if (dictionary_validity.find(ustr__ZSebx()) != dictionary_validity.end()) { 1.1429 +- frame->context.ebx = dictionary[ustr__ZSebx()]; 1.1430 ++ if (dictionary_validity.have(ustr__ZSebx())) { 1.1431 ++ frame->context.ebx = dictionary.get(ustr__ZSebx()); 1.1432 + frame->context_validity |= StackFrameX86::CONTEXT_VALID_EBX; 1.1433 + } 1.1434 +- if (dictionary_validity.find(ustr__ZSesi()) != dictionary_validity.end()) { 1.1435 +- frame->context.esi = dictionary[ustr__ZSesi()]; 1.1436 ++ if (dictionary_validity.have(ustr__ZSesi())) { 1.1437 ++ frame->context.esi = dictionary.get(ustr__ZSesi()); 1.1438 + frame->context_validity |= StackFrameX86::CONTEXT_VALID_ESI; 1.1439 + } 1.1440 +- if (dictionary_validity.find(ustr__ZSedi()) != dictionary_validity.end()) { 1.1441 +- frame->context.edi = dictionary[ustr__ZSedi()]; 1.1442 ++ if (dictionary_validity.have(ustr__ZSedi())) { 1.1443 ++ frame->context.edi = dictionary.get(ustr__ZSedi()); 1.1444 + frame->context_validity |= StackFrameX86::CONTEXT_VALID_EDI; 1.1445 + } 1.1446 + 1.1447 + return frame; 1.1448 + } 1.1449 + 1.1450 + StackFrameX86* StackwalkerX86::GetCallerByCFIFrameInfo( 1.1451 + const vector<StackFrame*> &frames,