diff -r 000000000000 -r 6474c204b198 toolkit/crashreporter/breakpad-patches/04-uniquestringmap.patch --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/toolkit/crashreporter/breakpad-patches/04-uniquestringmap.patch Wed Dec 31 06:09:35 2014 +0100 @@ -0,0 +1,1448 @@ +# HG changeset patch +# User Ted Mielczarek +# Date 1360255134 18000 +# Node ID 294ce0d64d35a90be8ea91b719ead8b82aed29f7 +# Parent d7bfb673574a3afe8b4f76f42fb52e2545770dad +Rework PostfixEvaluator to use UniqueStringMap +Patch by Julian Seward , R=ted + +diff --git a/src/common/unique_string.h b/src/common/unique_string.h +--- a/src/common/unique_string.h ++++ b/src/common/unique_string.h +@@ -25,16 +25,17 @@ + // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + #ifndef COMMON_UNIQUE_STRING_H_ + #define COMMON_UNIQUE_STRING_H_ + ++#include + #include + #include "common/using_std_string.h" + + namespace google_breakpad { + + // Abstract type + class UniqueString; + +@@ -229,11 +230,112 @@ + + // ".ra" + inline static const UniqueString* ustr__ZDra() { + static const UniqueString* us = NULL; + if (!us) us = ToUniqueString(".ra"); + return us; + } + ++template ++class UniqueStringMap ++{ ++ private: ++ static const int N_FIXED = 10; ++ ++ public: ++ UniqueStringMap() : n_fixed_(0), n_sets_(0), n_gets_(0), n_clears_(0) {}; ++ ~UniqueStringMap() {}; ++ ++ // Empty out the map. ++ void clear() { ++ ++n_clears_; ++ map_.clear(); ++ n_fixed_ = 0; ++ } ++ ++ // Do "map[ix] = v". ++ void set(const UniqueString* ix, ValueType v) { ++ ++n_sets_; ++ int i; ++ for (i = 0; i < n_fixed_; ++i) { ++ if (fixed_keys_[i] == ix) { ++ fixed_vals_[i] = v; ++ return; ++ } ++ } ++ if (n_fixed_ < N_FIXED) { ++ i = n_fixed_; ++ fixed_keys_[i] = ix; ++ fixed_vals_[i] = v; ++ ++n_fixed_; ++ } else { ++ map_[ix] = v; ++ } ++ } ++ ++ // Lookup 'ix' in the map, and also return a success/fail boolean. ++ ValueType get(/*OUT*/bool* have, const UniqueString* ix) const { ++ ++n_gets_; ++ int i; ++ for (i = 0; i < n_fixed_; ++i) { ++ if (fixed_keys_[i] == ix) { ++ *have = true; ++ return fixed_vals_[i]; ++ } ++ } ++ typename std::map::const_iterator it ++ = map_.find(ix); ++ if (it == map_.end()) { ++ *have = false; ++ return ValueType(); ++ } else { ++ *have = true; ++ return it->second; ++ } ++ }; ++ ++ // Lookup 'ix' in the map, and return zero if it is not present. ++ ValueType get(const UniqueString* ix) const { ++ ++n_gets_; ++ bool found; ++ ValueType v = get(&found, ix); ++ return found ? v : ValueType(); ++ } ++ ++ // Find out whether 'ix' is in the map. ++ bool have(const UniqueString* ix) const { ++ ++n_gets_; ++ bool found; ++ (void)get(&found, ix); ++ return found; ++ } ++ ++ // Copy the contents to a std::map, generally for testing. ++ void copy_to_map(std::map* m) const { ++ m->clear(); ++ int i; ++ for (i = 0; i < n_fixed_; ++i) { ++ (*m)[fixed_keys_[i]] = fixed_vals_[i]; ++ } ++ m->insert(map_.begin(), map_.end()); ++ } ++ ++ // Note that users of this class rely on having also a sane ++ // assignment operator. The default one is OK, though. ++ // AFAICT there are no uses of the copy constructor, but if ++ // there were, the default one would also suffice. ++ ++ private: ++ // Quick (hopefully) cache ++ const UniqueString* fixed_keys_[N_FIXED]; ++ ValueType fixed_vals_[N_FIXED]; ++ int n_fixed_; // 0 .. N_FIXED inclusive ++ // Fallback storage when the cache is filled ++ std::map map_; ++ ++ // For tracking usage stats. ++ mutable int n_sets_, n_gets_, n_clears_; ++}; ++ + } // namespace google_breakpad + + #endif // COMMON_UNIQUE_STRING_H_ +diff --git a/src/processor/basic_source_line_resolver_unittest.cc b/src/processor/basic_source_line_resolver_unittest.cc +--- a/src/processor/basic_source_line_resolver_unittest.cc ++++ b/src/processor/basic_source_line_resolver_unittest.cc +@@ -24,16 +24,17 @@ + // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + #include + ++#include + #include + + #include "breakpad_googletest_includes.h" + #include "common/scoped_ptr.h" + #include "common/using_std_string.h" + #include "google_breakpad/processor/basic_source_line_resolver.h" + #include "google_breakpad/processor/code_module.h" + #include "google_breakpad/processor/stack_frame.h" +@@ -47,16 +48,17 @@ + + using google_breakpad::BasicSourceLineResolver; + using google_breakpad::CFIFrameInfo; + using google_breakpad::CodeModule; + using google_breakpad::FromUniqueString; + using google_breakpad::MemoryRegion; + using google_breakpad::StackFrame; + using google_breakpad::ToUniqueString; ++using google_breakpad::UniqueString; + using google_breakpad::WindowsFrameInfo; + using google_breakpad::linked_ptr; + using google_breakpad::scoped_ptr; + using google_breakpad::ustr__ZDcfa; + using google_breakpad::ustr__ZDra; + using google_breakpad::ustr__ZSebx; + using google_breakpad::ustr__ZSebp; + using google_breakpad::ustr__ZSedi; +@@ -113,27 +115,30 @@ + }; + + // Verify that, for every association in ACTUAL, EXPECTED has the same + // association. (That is, ACTUAL's associations should be a subset of + // EXPECTED's.) Also verify that ACTUAL has associations for ".ra" and + // ".cfa". + static bool VerifyRegisters( + const char *file, int line, +- const CFIFrameInfo::RegisterValueMap &expected, +- const CFIFrameInfo::RegisterValueMap &actual) { +- CFIFrameInfo::RegisterValueMap::const_iterator a; ++ const std::map &expected, ++ const CFIFrameInfo::RegisterValueMap &actual_regmap) { ++ std::map actual; ++ actual_regmap.copy_to_map(&actual); ++ ++ std::map::const_iterator a; + a = actual.find(ustr__ZDcfa()); + if (a == actual.end()) + return false; + a = actual.find(ustr__ZDra()); + if (a == actual.end()) + return false; + for (a = actual.begin(); a != actual.end(); a++) { +- CFIFrameInfo::RegisterValueMap::const_iterator e = ++ std::map::const_iterator e = + expected.find(a->first); + if (e == expected.end()) { + fprintf(stderr, "%s:%d: unexpected register '%s' recovered, value 0x%x\n", + file, line, FromUniqueString(a->first), a->second); + return false; + } + if (e->second != a->second) { + fprintf(stderr, +@@ -258,86 +263,86 @@ + + frame.instruction = 0x3e9f; + frame.module = &module1; + cfi_frame_info.reset(resolver.FindCFIFrameInfo(&frame)); + ASSERT_FALSE(cfi_frame_info.get()); + + CFIFrameInfo::RegisterValueMap current_registers; + CFIFrameInfo::RegisterValueMap caller_registers; +- CFIFrameInfo::RegisterValueMap expected_caller_registers; ++ std::map expected_caller_registers; + MockMemoryRegion memory; + + // Regardless of which instruction evaluation takes place at, it + // should produce the same values for the caller's registers. + expected_caller_registers[ustr__ZDcfa()] = 0x1001c; + expected_caller_registers[ustr__ZDra()] = 0xf6438648; + expected_caller_registers[ustr__ZSebp()] = 0x10038; + expected_caller_registers[ustr__ZSebx()] = 0x98ecadc3; + expected_caller_registers[ustr__ZSesi()] = 0x878f7524; + expected_caller_registers[ustr__ZSedi()] = 0x6312f9a5; + + frame.instruction = 0x3d40; + frame.module = &module1; + current_registers.clear(); +- current_registers[ustr__ZSesp()] = 0x10018; +- current_registers[ustr__ZSebp()] = 0x10038; +- current_registers[ustr__ZSebx()] = 0x98ecadc3; +- current_registers[ustr__ZSesi()] = 0x878f7524; +- current_registers[ustr__ZSedi()] = 0x6312f9a5; ++ current_registers.set(ustr__ZSesp(), 0x10018); ++ current_registers.set(ustr__ZSebp(), 0x10038); ++ current_registers.set(ustr__ZSebx(), 0x98ecadc3); ++ current_registers.set(ustr__ZSesi(), 0x878f7524); ++ current_registers.set(ustr__ZSedi(), 0x6312f9a5); + cfi_frame_info.reset(resolver.FindCFIFrameInfo(&frame)); + ASSERT_TRUE(cfi_frame_info.get()); + ASSERT_TRUE(cfi_frame_info.get() + ->FindCallerRegs(current_registers, memory, + &caller_registers)); + ASSERT_TRUE(VerifyRegisters(__FILE__, __LINE__, + expected_caller_registers, caller_registers)); + + frame.instruction = 0x3d41; +- current_registers[ustr__ZSesp()] = 0x10014; ++ current_registers.set(ustr__ZSesp(), 0x10014); + cfi_frame_info.reset(resolver.FindCFIFrameInfo(&frame)); + ASSERT_TRUE(cfi_frame_info.get()); + ASSERT_TRUE(cfi_frame_info.get() + ->FindCallerRegs(current_registers, memory, + &caller_registers)); + ASSERT_TRUE(VerifyRegisters(__FILE__, __LINE__, + expected_caller_registers, caller_registers)); + + frame.instruction = 0x3d43; +- current_registers[ustr__ZSebp()] = 0x10014; ++ current_registers.set(ustr__ZSebp(), 0x10014); + cfi_frame_info.reset(resolver.FindCFIFrameInfo(&frame)); + ASSERT_TRUE(cfi_frame_info.get()); + ASSERT_TRUE(cfi_frame_info.get() + ->FindCallerRegs(current_registers, memory, + &caller_registers)); + VerifyRegisters(__FILE__, __LINE__, + expected_caller_registers, caller_registers); + + frame.instruction = 0x3d54; +- current_registers[ustr__ZSebx()] = 0x6864f054U; ++ current_registers.set(ustr__ZSebx(), 0x6864f054U); + cfi_frame_info.reset(resolver.FindCFIFrameInfo(&frame)); + ASSERT_TRUE(cfi_frame_info.get()); + ASSERT_TRUE(cfi_frame_info.get() + ->FindCallerRegs(current_registers, memory, + &caller_registers)); + VerifyRegisters(__FILE__, __LINE__, + expected_caller_registers, caller_registers); + + frame.instruction = 0x3d5a; +- current_registers[ustr__ZSesi()] = 0x6285f79aU; ++ current_registers.set(ustr__ZSesi(), 0x6285f79aU); + cfi_frame_info.reset(resolver.FindCFIFrameInfo(&frame)); + ASSERT_TRUE(cfi_frame_info.get()); + ASSERT_TRUE(cfi_frame_info.get() + ->FindCallerRegs(current_registers, memory, + &caller_registers)); + VerifyRegisters(__FILE__, __LINE__, + expected_caller_registers, caller_registers); + + frame.instruction = 0x3d84; +- current_registers[ustr__ZSedi()] = 0x64061449U; ++ current_registers.set(ustr__ZSedi(), 0x64061449U); + cfi_frame_info.reset(resolver.FindCFIFrameInfo(&frame)); + ASSERT_TRUE(cfi_frame_info.get()); + ASSERT_TRUE(cfi_frame_info.get() + ->FindCallerRegs(current_registers, memory, + &caller_registers)); + VerifyRegisters(__FILE__, __LINE__, + expected_caller_registers, caller_registers); + +diff --git a/src/processor/cfi_frame_info-inl.h b/src/processor/cfi_frame_info-inl.h +--- a/src/processor/cfi_frame_info-inl.h ++++ b/src/processor/cfi_frame_info-inl.h +@@ -35,64 +35,64 @@ + + #ifndef PROCESSOR_CFI_FRAME_INFO_INL_H_ + #define PROCESSOR_CFI_FRAME_INFO_INL_H_ + + #include + + namespace google_breakpad { + +-template +-bool SimpleCFIWalker::FindCallerRegisters( ++template ++bool SimpleCFIWalker::FindCallerRegisters( + const MemoryRegion &memory, + const CFIFrameInfo &cfi_frame_info, + const RawContextType &callee_context, + int callee_validity, + RawContextType *caller_context, + int *caller_validity) const { +- typedef CFIFrameInfo::RegisterValueMap ValueMap; ++ typedef CFIFrameInfo::RegisterValueMap ValueMap; + ValueMap callee_registers; + ValueMap caller_registers; +- // Just for brevity. +- typename ValueMap::const_iterator caller_none = caller_registers.end(); + + // Populate callee_registers with register values from callee_context. + for (size_t i = 0; i < map_size_; i++) { + const RegisterSet &r = register_map_[i]; + if (callee_validity & r.validity_flag) +- callee_registers[r.name] = callee_context.*r.context_member; ++ callee_registers.set(r.name, callee_context.*r.context_member); + } + + // Apply the rules, and see what register values they yield. +- if (!cfi_frame_info.FindCallerRegs(callee_registers, memory, +- &caller_registers)) ++ if (!cfi_frame_info ++ .FindCallerRegs(callee_registers, memory, ++ &caller_registers)) + return false; + + // Populate *caller_context with the values the rules placed in + // caller_registers. + memset(caller_context, 0xda, sizeof(*caller_context)); + *caller_validity = 0; + for (size_t i = 0; i < map_size_; i++) { + const RegisterSet &r = register_map_[i]; +- typename ValueMap::const_iterator caller_entry; + + // Did the rules provide a value for this register by its name? +- caller_entry = caller_registers.find(r.name); +- if (caller_entry != caller_none) { +- caller_context->*r.context_member = caller_entry->second; ++ bool found = false; ++ RegisterValueType v = caller_registers.get(&found, r.name); ++ if (found) { ++ caller_context->*r.context_member = v; + *caller_validity |= r.validity_flag; + continue; + } + + // Did the rules provide a value for this register under its + // alternate name? + if (r.alternate_name) { +- caller_entry = caller_registers.find(r.alternate_name); +- if (caller_entry != caller_none) { +- caller_context->*r.context_member = caller_entry->second; ++ found = false; ++ v = caller_registers.get(&found, r.alternate_name); ++ if (found) { ++ caller_context->*r.context_member = v; + *caller_validity |= r.validity_flag; + continue; + } + } + + // Is this a callee-saves register? The walker assumes that these + // still hold the caller's value if the CFI doesn't mention them. + // +diff --git a/src/processor/cfi_frame_info.cc b/src/processor/cfi_frame_info.cc +--- a/src/processor/cfi_frame_info.cc ++++ b/src/processor/cfi_frame_info.cc +@@ -66,33 +66,33 @@ + V cfa; + working = registers; + if (!evaluator.EvaluateForValue(cfa_rule_, &cfa)) + return false; + + // Then, compute the return address. + V ra; + working = registers; +- working[ustr__ZDcfa()] = cfa; ++ working.set(ustr__ZDcfa(), cfa); + if (!evaluator.EvaluateForValue(ra_rule_, &ra)) + return false; + + // Now, compute values for all the registers register_rules_ mentions. + for (RuleMap::const_iterator it = register_rules_.begin(); + it != register_rules_.end(); it++) { + V value; + working = registers; +- working[ustr__ZDcfa()] = cfa; ++ working.set(ustr__ZDcfa(), cfa); + if (!evaluator.EvaluateForValue(it->second, &value)) + return false; +- (*caller_registers)[it->first] = value; ++ caller_registers->set(it->first, value); + } + +- (*caller_registers)[ustr__ZDra()] = ra; +- (*caller_registers)[ustr__ZDcfa()] = cfa; ++ caller_registers->set(ustr__ZDra(), ra); ++ caller_registers->set(ustr__ZDcfa(), cfa); + + return true; + } + + // Explicit instantiations for 32-bit and 64-bit architectures. + template bool CFIFrameInfo::FindCallerRegs( + const RegisterValueMap ®isters, + const MemoryRegion &memory, +diff --git a/src/processor/cfi_frame_info.h b/src/processor/cfi_frame_info.h +--- a/src/processor/cfi_frame_info.h ++++ b/src/processor/cfi_frame_info.h +@@ -64,17 +64,17 @@ + // changes given by the 'STACK CFI' records up to our instruction's + // address. Then, use the FindCallerRegs member function to apply the + // rules to the callee frame's register values, yielding the caller + // frame's register values. + class CFIFrameInfo { + public: + // A map from register names onto values. + template class RegisterValueMap: +- public map { }; ++ public UniqueStringMap { }; + + // Set the expression for computing a call frame address, return + // address, or register's value. At least the CFA rule and the RA + // rule must be set before calling FindCallerRegs. + void SetCFARule(const Module::Expr& rule) { cfa_rule_ = rule; } + void SetRARule(const Module::Expr& rule) { ra_rule_ = rule; } + void SetRegisterRule(const UniqueString* register_name, + const Module::Expr& rule) { +diff --git a/src/processor/cfi_frame_info_unittest.cc b/src/processor/cfi_frame_info_unittest.cc +--- a/src/processor/cfi_frame_info_unittest.cc ++++ b/src/processor/cfi_frame_info_unittest.cc +@@ -111,19 +111,18 @@ + + TEST_F(Simple, SetCFAAndRARule) { + ExpectNoMemoryReferences(); + + cfi.SetCFARule(Module::Expr("330903416631436410")); + cfi.SetRARule(Module::Expr("5870666104170902211")); + ASSERT_TRUE(cfi.FindCallerRegs(registers, memory, + &caller_registers)); +- ASSERT_EQ(2U, caller_registers.size()); +- ASSERT_EQ(330903416631436410ULL, caller_registers[ustr__ZDcfa()]); +- ASSERT_EQ(5870666104170902211ULL, caller_registers[ustr__ZDra()]); ++ ASSERT_EQ(330903416631436410ULL, caller_registers.get(ustr__ZDcfa())); ++ ASSERT_EQ(5870666104170902211ULL, caller_registers.get(ustr__ZDra())); + + ASSERT_EQ(".cfa: 330903416631436410 .ra: 5870666104170902211", + cfi.Serialize()); + } + + TEST_F(Simple, SetManyRules) { + ExpectNoMemoryReferences(); + +@@ -136,23 +135,22 @@ + const UniqueString* reg4 = ToUniqueString("uncopyrightables"); + + cfi.SetRegisterRule(reg1, Module::Expr(".cfa 54370437 *")); + cfi.SetRegisterRule(reg2, Module::Expr("24076308 .cfa +")); + cfi.SetRegisterRule(reg3, Module::Expr(".cfa 29801007 -")); + cfi.SetRegisterRule(reg4, Module::Expr("92642917 .cfa /")); + ASSERT_TRUE(cfi.FindCallerRegs(registers, memory, + &caller_registers)); +- ASSERT_EQ(6U, caller_registers.size()); +- ASSERT_EQ(7664691U, caller_registers[ustr__ZDcfa()]); +- ASSERT_EQ(107469446U, caller_registers[ustr__ZDra()]); +- ASSERT_EQ(416732599139967ULL, caller_registers[reg1]); +- ASSERT_EQ(31740999U, caller_registers[reg2]); +- ASSERT_EQ(-22136316ULL, caller_registers[reg3]); +- ASSERT_EQ(12U, caller_registers[reg4]); ++ ASSERT_EQ(7664691U, caller_registers.get(ustr__ZDcfa())); ++ ASSERT_EQ(107469446U, caller_registers.get(ustr__ZDra())); ++ ASSERT_EQ(416732599139967ULL, caller_registers.get(reg1)); ++ ASSERT_EQ(31740999U, caller_registers.get(reg2)); ++ ASSERT_EQ(-22136316ULL, caller_registers.get(reg3)); ++ ASSERT_EQ(12U, caller_registers.get(reg4)); + ASSERT_EQ(".cfa: $temp1 68737028 = $temp2 61072337 = $temp1 $temp2 - " + ".ra: .cfa 99804755 + " + "pubvexingfjordschmaltzy: .cfa 29801007 - " + "register1: .cfa 54370437 * " + "uncopyrightables: 92642917 .cfa / " + "vodkathumbscrewingly: 24076308 .cfa +", + cfi.Serialize()); + } +@@ -160,19 +158,18 @@ + TEST_F(Simple, RulesOverride) { + ExpectNoMemoryReferences(); + + cfi.SetCFARule(Module::Expr("330903416631436410")); + cfi.SetRARule(Module::Expr("5870666104170902211")); + cfi.SetCFARule(Module::Expr("2828089117179001")); + ASSERT_TRUE(cfi.FindCallerRegs(registers, memory, + &caller_registers)); +- ASSERT_EQ(2U, caller_registers.size()); +- ASSERT_EQ(2828089117179001ULL, caller_registers[ustr__ZDcfa()]); +- ASSERT_EQ(5870666104170902211ULL, caller_registers[ustr__ZDra()]); ++ ASSERT_EQ(2828089117179001ULL, caller_registers.get(ustr__ZDcfa())); ++ ASSERT_EQ(5870666104170902211ULL, caller_registers.get(ustr__ZDra())); + ASSERT_EQ(".cfa: 2828089117179001 .ra: 5870666104170902211", + cfi.Serialize()); + } + + class Scope: public CFIFixture, public Test { }; + + // There should be no value for .cfa in scope when evaluating the CFA rule. + TEST_F(Scope, CFALacksCFA) { +@@ -196,37 +193,35 @@ + + // The current frame's registers should be in scope when evaluating + // the CFA rule. + TEST_F(Scope, CFASeesCurrentRegs) { + ExpectNoMemoryReferences(); + + const UniqueString* reg1 = ToUniqueString(".baraminology"); + const UniqueString* reg2 = ToUniqueString(".ornithorhynchus"); +- registers[reg1] = 0x06a7bc63e4f13893ULL; +- registers[reg2] = 0x5e0bf850bafce9d2ULL; ++ registers.set(reg1, 0x06a7bc63e4f13893ULL); ++ registers.set(reg2, 0x5e0bf850bafce9d2ULL); + cfi.SetCFARule(Module::Expr(".baraminology .ornithorhynchus +")); + cfi.SetRARule(Module::Expr("0")); + ASSERT_TRUE(cfi.FindCallerRegs(registers, memory, + &caller_registers)); +- ASSERT_EQ(2U, caller_registers.size()); + ASSERT_EQ(0x06a7bc63e4f13893ULL + 0x5e0bf850bafce9d2ULL, +- caller_registers[ustr__ZDcfa()]); ++ caller_registers.get(ustr__ZDcfa())); + } + + // .cfa should be in scope in the return address expression. + TEST_F(Scope, RASeesCFA) { + ExpectNoMemoryReferences(); + + cfi.SetCFARule(Module::Expr("48364076")); + cfi.SetRARule(Module::Expr(".cfa")); + ASSERT_TRUE(cfi.FindCallerRegs(registers, memory, + &caller_registers)); +- ASSERT_EQ(2U, caller_registers.size()); +- ASSERT_EQ(48364076U, caller_registers[ustr__ZDra()]); ++ ASSERT_EQ(48364076U, caller_registers.get(ustr__ZDra())); + } + + // There should be no value for .ra in scope when evaluating the CFA rule. + TEST_F(Scope, RALacksRA) { + ExpectNoMemoryReferences(); + + cfi.SetCFARule(Module::Expr("0")); + cfi.SetRARule(Module::Expr(".ra")); +@@ -236,36 +231,34 @@ + + // The current frame's registers should be in scope in the return + // address expression. + TEST_F(Scope, RASeesCurrentRegs) { + ExpectNoMemoryReferences(); + + cfi.SetCFARule(Module::Expr("10359370")); + const UniqueString* reg1 = ToUniqueString("noachian"); +- registers[reg1] = 0x54dc4a5d8e5eb503ULL; ++ registers.set(reg1, 0x54dc4a5d8e5eb503ULL); + cfi.SetRARule(Module::Expr(reg1, 0, false)); + ASSERT_TRUE(cfi.FindCallerRegs(registers, memory, + &caller_registers)); +- ASSERT_EQ(2U, caller_registers.size()); +- ASSERT_EQ(0x54dc4a5d8e5eb503ULL, caller_registers[ustr__ZDra()]); ++ ASSERT_EQ(0x54dc4a5d8e5eb503ULL, caller_registers.get(ustr__ZDra())); + } + + // .cfa should be in scope for register rules. + TEST_F(Scope, RegistersSeeCFA) { + ExpectNoMemoryReferences(); + + cfi.SetCFARule(Module::Expr("6515179")); + cfi.SetRARule(Module::Expr(".cfa")); + const UniqueString* reg1 = ToUniqueString("rogerian"); + cfi.SetRegisterRule(reg1, Module::Expr(".cfa")); + ASSERT_TRUE(cfi.FindCallerRegs(registers, memory, + &caller_registers)); +- ASSERT_EQ(3U, caller_registers.size()); +- ASSERT_EQ(6515179U, caller_registers[reg1]); ++ ASSERT_EQ(6515179U, caller_registers.get(reg1)); + } + + // The return address should not be in scope for register rules. + TEST_F(Scope, RegsLackRA) { + ExpectNoMemoryReferences(); + + cfi.SetCFARule(Module::Expr("42740329")); + cfi.SetRARule(Module::Expr("27045204")); +@@ -276,27 +269,26 @@ + } + + // Register rules can see the current frame's register values. + TEST_F(Scope, RegsSeeRegs) { + ExpectNoMemoryReferences(); + + const UniqueString* reg1 = ToUniqueString("$r1"); + const UniqueString* reg2 = ToUniqueString("$r2"); +- registers[reg1] = 0x6ed3582c4bedb9adULL; +- registers[reg2] = 0xd27d9e742b8df6d0ULL; ++ registers.set(reg1, 0x6ed3582c4bedb9adULL); ++ registers.set(reg2, 0xd27d9e742b8df6d0ULL); + cfi.SetCFARule(Module::Expr("88239303")); + cfi.SetRARule(Module::Expr("30503835")); + cfi.SetRegisterRule(reg1, Module::Expr("$r1 42175211 = $r2")); + cfi.SetRegisterRule(reg2, Module::Expr("$r2 21357221 = $r1")); + ASSERT_TRUE(cfi.FindCallerRegs(registers, memory, + &caller_registers)); +- ASSERT_EQ(4U, caller_registers.size()); +- ASSERT_EQ(0xd27d9e742b8df6d0ULL, caller_registers[reg1]); +- ASSERT_EQ(0x6ed3582c4bedb9adULL, caller_registers[reg2]); ++ ASSERT_EQ(0xd27d9e742b8df6d0ULL, caller_registers.get(reg1)); ++ ASSERT_EQ(0x6ed3582c4bedb9adULL, caller_registers.get(reg2)); + } + + // Each rule's temporaries are separate. + TEST_F(Scope, SeparateTempsRA) { + ExpectNoMemoryReferences(); + + cfi.SetCFARule(Module::Expr("$temp1 76569129 = $temp1")); + cfi.SetRARule(Module::Expr("0")); +@@ -440,39 +432,39 @@ + CFIFrameInfoParseHandler handler; + }; + + class ParseHandler: public ParseHandlerFixture, public Test { }; + + TEST_F(ParseHandler, CFARARule) { + handler.CFARule("reg-for-cfa"); + handler.RARule("reg-for-ra"); +- registers[ToUniqueString("reg-for-cfa")] = 0x268a9a4a3821a797ULL; +- registers[ToUniqueString("reg-for-ra")] = 0x6301b475b8b91c02ULL; ++ registers.set(ToUniqueString("reg-for-cfa"), 0x268a9a4a3821a797ULL); ++ registers.set(ToUniqueString("reg-for-ra"), 0x6301b475b8b91c02ULL); + ASSERT_TRUE(cfi.FindCallerRegs(registers, memory, + &caller_registers)); +- ASSERT_EQ(0x268a9a4a3821a797ULL, caller_registers[ustr__ZDcfa()]); +- ASSERT_EQ(0x6301b475b8b91c02ULL, caller_registers[ustr__ZDra()]); ++ ASSERT_EQ(0x268a9a4a3821a797ULL, caller_registers.get(ustr__ZDcfa())); ++ ASSERT_EQ(0x6301b475b8b91c02ULL, caller_registers.get(ustr__ZDra())); + } + + TEST_F(ParseHandler, RegisterRules) { + handler.CFARule("reg-for-cfa"); + handler.RARule("reg-for-ra"); + handler.RegisterRule(ToUniqueString("reg1"), "reg-for-reg1"); + handler.RegisterRule(ToUniqueString("reg2"), "reg-for-reg2"); +- registers[ToUniqueString("reg-for-cfa")] = 0x268a9a4a3821a797ULL; +- registers[ToUniqueString("reg-for-ra")] = 0x6301b475b8b91c02ULL; +- registers[ToUniqueString("reg-for-reg1")] = 0x06cde8e2ff062481ULL; +- registers[ToUniqueString("reg-for-reg2")] = 0xff0c4f76403173e2ULL; ++ registers.set(ToUniqueString("reg-for-cfa"), 0x268a9a4a3821a797ULL); ++ registers.set(ToUniqueString("reg-for-ra"), 0x6301b475b8b91c02ULL); ++ registers.set(ToUniqueString("reg-for-reg1"), 0x06cde8e2ff062481ULL); ++ registers.set(ToUniqueString("reg-for-reg2"), 0xff0c4f76403173e2ULL); + ASSERT_TRUE(cfi.FindCallerRegs(registers, memory, + &caller_registers)); +- ASSERT_EQ(0x268a9a4a3821a797ULL, caller_registers[ustr__ZDcfa()]); +- ASSERT_EQ(0x6301b475b8b91c02ULL, caller_registers[ustr__ZDra()]); +- ASSERT_EQ(0x06cde8e2ff062481ULL, caller_registers[ToUniqueString("reg1")]); +- ASSERT_EQ(0xff0c4f76403173e2ULL, caller_registers[ToUniqueString("reg2")]); ++ ASSERT_EQ(0x268a9a4a3821a797ULL, caller_registers.get(ustr__ZDcfa())); ++ ASSERT_EQ(0x6301b475b8b91c02ULL, caller_registers.get(ustr__ZDra())); ++ ASSERT_EQ(0x06cde8e2ff062481ULL, caller_registers.get(ToUniqueString("reg1"))); ++ ASSERT_EQ(0xff0c4f76403173e2ULL, caller_registers.get(ToUniqueString("reg2"))); + } + + struct SimpleCFIWalkerFixture { + struct RawContext { + uint64_t r0, r1, r2, r3, r4, sp, pc; + }; + enum Validity { + R0_VALID = 0x01, +diff --git a/src/processor/fast_source_line_resolver_unittest.cc b/src/processor/fast_source_line_resolver_unittest.cc +--- a/src/processor/fast_source_line_resolver_unittest.cc ++++ b/src/processor/fast_source_line_resolver_unittest.cc +@@ -59,16 +59,17 @@ + using google_breakpad::FromUniqueString; + using google_breakpad::ModuleSerializer; + using google_breakpad::ModuleComparer; + using google_breakpad::CFIFrameInfo; + using google_breakpad::CodeModule; + using google_breakpad::MemoryRegion; + using google_breakpad::StackFrame; + using google_breakpad::ToUniqueString; ++using google_breakpad::UniqueString; + using google_breakpad::WindowsFrameInfo; + using google_breakpad::linked_ptr; + using google_breakpad::scoped_ptr; + using google_breakpad::ustr__ZDcfa; + using google_breakpad::ustr__ZDra; + using google_breakpad::ustr__ZSebx; + using google_breakpad::ustr__ZSebp; + using google_breakpad::ustr__ZSedi; +@@ -125,27 +126,30 @@ + }; + + // Verify that, for every association in ACTUAL, EXPECTED has the same + // association. (That is, ACTUAL's associations should be a subset of + // EXPECTED's.) Also verify that ACTUAL has associations for ".ra" and + // ".cfa". + static bool VerifyRegisters( + const char *file, int line, +- const CFIFrameInfo::RegisterValueMap &expected, +- const CFIFrameInfo::RegisterValueMap &actual) { +- CFIFrameInfo::RegisterValueMap::const_iterator a; ++ const std::map &expected, ++ const CFIFrameInfo::RegisterValueMap &actual_regmap) { ++ std::map actual; ++ actual_regmap.copy_to_map(&actual); ++ ++ std::map::const_iterator a; + a = actual.find(ustr__ZDcfa()); + if (a == actual.end()) + return false; + a = actual.find(ustr__ZDra()); + if (a == actual.end()) + return false; + for (a = actual.begin(); a != actual.end(); a++) { +- CFIFrameInfo::RegisterValueMap::const_iterator e = ++ std::map::const_iterator e = + expected.find(a->first); + if (e == expected.end()) { + fprintf(stderr, "%s:%d: unexpected register '%s' recovered, value 0x%x\n", + file, line, FromUniqueString(a->first), a->second); + return false; + } + if (e->second != a->second) { + fprintf(stderr, +@@ -286,86 +290,87 @@ + + frame.instruction = 0x3e9f; + frame.module = &module1; + cfi_frame_info.reset(fast_resolver.FindCFIFrameInfo(&frame)); + ASSERT_FALSE(cfi_frame_info.get()); + + CFIFrameInfo::RegisterValueMap current_registers; + CFIFrameInfo::RegisterValueMap caller_registers; +- CFIFrameInfo::RegisterValueMap expected_caller_registers; ++ std::map expected_caller_registers; + MockMemoryRegion memory; + + // Regardless of which instruction evaluation takes place at, it + // should produce the same values for the caller's registers. ++ // should produce the same values for the caller's registers. + expected_caller_registers[ustr__ZDcfa()] = 0x1001c; +- expected_caller_registers[ustr__ZDra()] = 0xf6438648; ++ expected_caller_registers[ustr__ZDra()] = 0xf6438648; + expected_caller_registers[ustr__ZSebp()] = 0x10038; + expected_caller_registers[ustr__ZSebx()] = 0x98ecadc3; + expected_caller_registers[ustr__ZSesi()] = 0x878f7524; + expected_caller_registers[ustr__ZSedi()] = 0x6312f9a5; + + frame.instruction = 0x3d40; + frame.module = &module1; + current_registers.clear(); +- current_registers[ustr__ZSesp()] = 0x10018; +- current_registers[ustr__ZSebp()] = 0x10038; +- current_registers[ustr__ZSebx()] = 0x98ecadc3; +- current_registers[ustr__ZSesi()] = 0x878f7524; +- current_registers[ustr__ZSedi()] = 0x6312f9a5; ++ current_registers.set(ustr__ZSesp(), 0x10018); ++ current_registers.set(ustr__ZSebp(), 0x10038); ++ current_registers.set(ustr__ZSebx(), 0x98ecadc3); ++ current_registers.set(ustr__ZSesi(), 0x878f7524); ++ current_registers.set(ustr__ZSedi(), 0x6312f9a5); + cfi_frame_info.reset(fast_resolver.FindCFIFrameInfo(&frame)); + ASSERT_TRUE(cfi_frame_info.get()); + ASSERT_TRUE(cfi_frame_info.get() + ->FindCallerRegs(current_registers, memory, + &caller_registers)); + ASSERT_TRUE(VerifyRegisters(__FILE__, __LINE__, + expected_caller_registers, caller_registers)); + + frame.instruction = 0x3d41; +- current_registers[ustr__ZSesp()] = 0x10014; ++ current_registers.set(ustr__ZSesp(), 0x10014); + cfi_frame_info.reset(fast_resolver.FindCFIFrameInfo(&frame)); + ASSERT_TRUE(cfi_frame_info.get()); + ASSERT_TRUE(cfi_frame_info.get() + ->FindCallerRegs(current_registers, memory, + &caller_registers)); + ASSERT_TRUE(VerifyRegisters(__FILE__, __LINE__, + expected_caller_registers, caller_registers)); + + frame.instruction = 0x3d43; +- current_registers[ustr__ZSebp()] = 0x10014; ++ current_registers.set(ustr__ZSebp(), 0x10014); + cfi_frame_info.reset(fast_resolver.FindCFIFrameInfo(&frame)); + ASSERT_TRUE(cfi_frame_info.get()); + ASSERT_TRUE(cfi_frame_info.get() + ->FindCallerRegs(current_registers, memory, + &caller_registers)); + VerifyRegisters(__FILE__, __LINE__, + expected_caller_registers, caller_registers); + + frame.instruction = 0x3d54; +- current_registers[ustr__ZSebx()] = 0x6864f054U; ++ current_registers.set(ustr__ZSebx(), 0x6864f054U); + cfi_frame_info.reset(fast_resolver.FindCFIFrameInfo(&frame)); + ASSERT_TRUE(cfi_frame_info.get()); + ASSERT_TRUE(cfi_frame_info.get() + ->FindCallerRegs(current_registers, memory, + &caller_registers)); + VerifyRegisters(__FILE__, __LINE__, + expected_caller_registers, caller_registers); + + frame.instruction = 0x3d5a; +- current_registers[ustr__ZSesi()] = 0x6285f79aU; ++ current_registers.set(ustr__ZSesi(), 0x6285f79aU); + cfi_frame_info.reset(fast_resolver.FindCFIFrameInfo(&frame)); + ASSERT_TRUE(cfi_frame_info.get()); + ASSERT_TRUE(cfi_frame_info.get() + ->FindCallerRegs(current_registers, memory, + &caller_registers)); + VerifyRegisters(__FILE__, __LINE__, + expected_caller_registers, caller_registers); + + frame.instruction = 0x3d84; +- current_registers[ustr__ZSedi()] = 0x64061449U; ++ current_registers.set(ustr__ZSedi(), 0x64061449U); + cfi_frame_info.reset(fast_resolver.FindCFIFrameInfo(&frame)); + ASSERT_TRUE(cfi_frame_info.get()); + ASSERT_TRUE(cfi_frame_info.get() + ->FindCallerRegs(current_registers, memory, + &caller_registers)); + VerifyRegisters(__FILE__, __LINE__, + expected_caller_registers, caller_registers); + +diff --git a/src/processor/postfix_evaluator-inl.h b/src/processor/postfix_evaluator-inl.h +--- a/src/processor/postfix_evaluator-inl.h ++++ b/src/processor/postfix_evaluator-inl.h +@@ -185,19 +185,19 @@ + return false; + } + if (identifier == ustr__empty() || Index(identifier,0) != '$') { + BPLOG(ERROR) << "Can't assign " << HexString(value) << " to " << + identifier << ": " << expression; + return false; + } + +- (*dictionary_)[identifier] = value; ++ dictionary_->set(identifier, value); + if (assigned) +- (*assigned)[identifier] = true; ++ assigned->set(identifier, true); + } else { + // Push it onto the stack as-is, but first convert it either to a + // ValueType (if a literal) or to a UniqueString* (if an identifier). + // + // First, try to treat the value as a literal. Literals may have leading + // '-' sign, and the entire remaining string must be parseable as + // ValueType. If this isn't possible, it can't be a literal, so treat it + // as an identifier instead. +@@ -300,28 +300,28 @@ + + return PopValue(result); + } + + // Simple-form expressions + case Module::kExprSimple: + case Module::kExprSimpleMem: { + // Look up the base value +- typename DictionaryType::const_iterator iterator +- = dictionary_->find(expr.ident_); +- if (iterator == dictionary_->end()) { ++ bool found = false; ++ ValueType v = dictionary_->get(&found, expr.ident_); ++ if (!found) { + // The identifier wasn't found in the dictionary. Don't imply any + // default value, just fail. +- BPLOG(INFO) << "Identifier " << expr.ident_ ++ BPLOG(INFO) << "Identifier " << FromUniqueString(expr.ident_) + << " not in dictionary (kExprSimple{Mem})"; + return false; + } + + // Form the sum +- ValueType sum = iterator->second + (int64_t)expr.offset_; ++ ValueType sum = v + (int64_t)expr.offset_; + + // and dereference if necessary + if (expr.how_ == Module::kExprSimpleMem) { + ValueType derefd; + if (!memory_ || !memory_->GetMemoryAtAddress(sum, &derefd)) { + return false; + } + *result = derefd; +@@ -368,27 +368,27 @@ + if ((result = PopValueOrIdentifier(&literal, &token)) == POP_RESULT_FAIL) { + return false; + } else if (result == POP_RESULT_VALUE) { + // This is the easy case. + *value = literal; + } else { // result == POP_RESULT_IDENTIFIER + // There was an identifier at the top of the stack. Resolve it to a + // value by looking it up in the dictionary. +- typename DictionaryType::const_iterator iterator = +- dictionary_->find(token); +- if (iterator == dictionary_->end()) { ++ bool found = false; ++ ValueType v = dictionary_->get(&found, token); ++ if (!found) { + // The identifier wasn't found in the dictionary. Don't imply any + // default value, just fail. + BPLOG(INFO) << "Identifier " << FromUniqueString(token) + << " not in dictionary"; + return false; + } + +- *value = iterator->second; ++ *value = v; + } + + return true; + } + + + template + bool PostfixEvaluator::PopValues(ValueType *value1, +diff --git a/src/processor/postfix_evaluator.h b/src/processor/postfix_evaluator.h +--- a/src/processor/postfix_evaluator.h ++++ b/src/processor/postfix_evaluator.h +@@ -93,18 +93,18 @@ + StackElem(const UniqueString* ustr) { isValue = false; u.ustr = ustr; } + bool isValue; + union { ValueType val; const UniqueString* ustr; } u; + }; + + template + class PostfixEvaluator { + public: +- typedef map DictionaryType; +- typedef map DictionaryValidityType; ++ typedef UniqueStringMap DictionaryType; ++ typedef UniqueStringMap DictionaryValidityType; + + // Create a PostfixEvaluator object that may be used (with Evaluate) on + // one or more expressions. PostfixEvaluator does not take ownership of + // either argument. |memory| may be NULL, in which case dereferencing + // (^) will not be supported. |dictionary| may be NULL, but evaluation + // will fail in that case unless set_dictionary is used before calling + // Evaluate. + PostfixEvaluator(DictionaryType *dictionary, const MemoryRegion *memory) +diff --git a/src/processor/postfix_evaluator_unittest.cc b/src/processor/postfix_evaluator_unittest.cc +--- a/src/processor/postfix_evaluator_unittest.cc ++++ b/src/processor/postfix_evaluator_unittest.cc +@@ -178,22 +178,22 @@ + validate_data_0[ToUniqueString("$rAdd3")] = 4; + validate_data_0[ToUniqueString("$rMul2")] = 54; + + // The second test set simulates a couple of MSVC program strings. + // The data is fudged a little bit because the tests use FakeMemoryRegion + // instead of a real stack snapshot, but the program strings are real and + // the implementation doesn't know or care that the data is not real. + PostfixEvaluator::DictionaryType dictionary_1; +- dictionary_1[ustr__ZSebp()] = 0xbfff0010; +- dictionary_1[ustr__ZSeip()] = 0x10000000; +- dictionary_1[ustr__ZSesp()] = 0xbfff0000; +- dictionary_1[ustr__ZDcbSavedRegs()] = 4; +- dictionary_1[ustr__ZDcbParams()] = 4; +- dictionary_1[ustr__ZDraSearchStart()] = 0xbfff0020; ++ dictionary_1.set(ustr__ZSebp(), 0xbfff0010); ++ dictionary_1.set(ustr__ZSeip(), 0x10000000); ++ dictionary_1.set(ustr__ZSesp(), 0xbfff0000); ++ dictionary_1.set(ustr__ZDcbSavedRegs(), 4); ++ dictionary_1.set(ustr__ZDcbParams(), 4); ++ dictionary_1.set(ustr__ZDraSearchStart(), 0xbfff0020); + const EvaluateTest evaluate_tests_1[] = { + { "$T0 $ebp = $eip $T0 4 + ^ = $ebp $T0 ^ = $esp $T0 8 + = " + "$L $T0 .cbSavedRegs - = $P $T0 8 + .cbParams + =", true }, + // Intermediate state: $T0 = 0xbfff0010, $eip = 0xbfff0015, + // $ebp = 0xbfff0011, $esp = 0xbfff0018, + // $L = 0xbfff000c, $P = 0xbfff001c + { "$T0 $ebp = $eip $T0 4 + ^ = $ebp $T0 ^ = $esp $T0 8 + = " + "$L $T0 .cbSavedRegs - = $P $T0 8 + .cbParams + = $ebx $T0 28 - ^ =", +@@ -273,70 +273,65 @@ + for (map::const_iterator + validate_iterator = + evaluate_test_set->validate_data->begin(); + validate_iterator != evaluate_test_set->validate_data->end(); + ++validate_iterator) { + const UniqueString* identifier = validate_iterator->first; + unsigned int expected_value = validate_iterator->second; + +- map::const_iterator +- dictionary_iterator = +- evaluate_test_set->dictionary->find(identifier); +- + // The identifier must exist in the dictionary. +- if (dictionary_iterator == evaluate_test_set->dictionary->end()) { ++ if (!evaluate_test_set->dictionary->have(identifier)) { + fprintf(stderr, "FAIL: evaluate test set %d/%d, " + "validate identifier \"%s\", " + "expected %d, observed not found\n", + evaluate_test_set_index, evaluate_test_set_count, + FromUniqueString(identifier), expected_value); + return false; + } + + // The value in the dictionary must be the same as the expected value. +- unsigned int observed_value = dictionary_iterator->second; ++ unsigned int observed_value = ++ evaluate_test_set->dictionary->get(identifier); + if (expected_value != observed_value) { + fprintf(stderr, "FAIL: evaluate test set %d/%d, " + "validate identifier \"%s\", " + "expected %d, observed %d\n", + evaluate_test_set_index, evaluate_test_set_count, + FromUniqueString(identifier), expected_value, observed_value); + return false; + } + + // The value must be set in the "assigned" dictionary if it was a + // variable. It must not have been assigned if it was a constant. + bool expected_assigned = FromUniqueString(identifier)[0] == '$'; + bool observed_assigned = false; +- PostfixEvaluator::DictionaryValidityType::const_iterator +- iterator_assigned = assigned.find(identifier); +- if (iterator_assigned != assigned.end()) { +- observed_assigned = iterator_assigned->second; ++ if (assigned.have(identifier)) { ++ observed_assigned = assigned.get(identifier); + } + if (expected_assigned != observed_assigned) { + fprintf(stderr, "FAIL: evaluate test set %d/%d, " + "validate assignment of \"%s\", " + "expected %d, observed %d\n", + evaluate_test_set_index, evaluate_test_set_count, + FromUniqueString(identifier), expected_assigned, + observed_assigned); + return false; + } + } + } + + // EvaluateForValue tests. + PostfixEvaluator::DictionaryType dictionary_2; +- dictionary_2[ustr__ZSebp()] = 0xbfff0010; +- dictionary_2[ustr__ZSeip()] = 0x10000000; +- dictionary_2[ustr__ZSesp()] = 0xbfff0000; +- dictionary_2[ustr__ZDcbSavedRegs()] = 4; +- dictionary_2[ustr__ZDcbParams()] = 4; +- dictionary_2[ustr__ZDraSearchStart()] = 0xbfff0020; ++ dictionary_2.set(ustr__ZSebp(), 0xbfff0010); ++ dictionary_2.set(ustr__ZSeip(), 0x10000000); ++ dictionary_2.set(ustr__ZSesp(), 0xbfff0000); ++ dictionary_2.set(ustr__ZDcbSavedRegs(), 4); ++ dictionary_2.set(ustr__ZDcbParams(), 4); ++ dictionary_2.set(ustr__ZDraSearchStart(), 0xbfff0020); + const EvaluateForValueTest evaluate_for_value_tests_2[] = { + { "28907223", true, 28907223 }, // simple constant + { "89854293 40010015 +", true, 89854293 + 40010015 }, // arithmetic + { "-870245 8769343 +", true, 7899098 }, // negative constants + { "$ebp $esp - $eip +", true, 0x10000010 }, // variable references + { "18929794 34015074", false, 0 }, // too many values + { "$ebp $ebp 4 - =", false, 0 }, // too few values + { "$new $eip = $new", true, 0x10000000 }, // make new variable +@@ -370,41 +365,43 @@ + if (test->evaluable && result != test->value) { + fprintf(stderr, "FAIL: evaluate for value test %d, " + "expected value to be 0x%x, but it was 0x%x\n", + i, test->value, result); + return false; + } + } + ++ map dictionary_2_map; ++ dictionary_2.copy_to_map(&dictionary_2_map); + for (map::iterator v = + validate_data_2.begin(); + v != validate_data_2.end(); v++) { + map::iterator a = +- dictionary_2.find(v->first); +- if (a == dictionary_2.end()) { ++ dictionary_2_map.find(v->first); ++ if (a == dictionary_2_map.end()) { + fprintf(stderr, "FAIL: evaluate for value dictionary check: " + "expected dict[\"%s\"] to be 0x%x, but it was unset\n", + FromUniqueString(v->first), v->second); + return false; + } else if (a->second != v->second) { + fprintf(stderr, "FAIL: evaluate for value dictionary check: " + "expected dict[\"%s\"] to be 0x%x, but it was 0x%x\n", + FromUniqueString(v->first), v->second, a->second); + return false; +- } +- dictionary_2.erase(a); ++ } ++ dictionary_2_map.erase(a); + } +- ++ + map::iterator remaining = +- dictionary_2.begin(); +- if (remaining != dictionary_2.end()) { ++ dictionary_2_map.begin(); ++ if (remaining != dictionary_2_map.end()) { + fprintf(stderr, "FAIL: evaluation of test expressions put unexpected " + "values in dictionary:\n"); +- for (; remaining != dictionary_2.end(); remaining++) ++ for (; remaining != dictionary_2_map.end(); remaining++) + fprintf(stderr, " dict[\"%s\"] == 0x%x\n", + FromUniqueString(remaining->first), remaining->second); + return false; + } + + return true; + } + +diff --git a/src/processor/stackwalker_arm.cc b/src/processor/stackwalker_arm.cc +--- a/src/processor/stackwalker_arm.cc ++++ b/src/processor/stackwalker_arm.cc +@@ -97,70 +97,70 @@ + ToUniqueString("fps"), ToUniqueString("cpsr"), + NULL + }; + + // Populate a dictionary with the valid register values in last_frame. + CFIFrameInfo::RegisterValueMap callee_registers; + for (int i = 0; register_names[i]; i++) + if (last_frame->context_validity & StackFrameARM::RegisterValidFlag(i)) +- callee_registers[register_names[i]] = last_frame->context.iregs[i]; ++ callee_registers.set(register_names[i], last_frame->context.iregs[i]); + + // Use the STACK CFI data to recover the caller's register values. + CFIFrameInfo::RegisterValueMap caller_registers; + if (!cfi_frame_info->FindCallerRegs(callee_registers, *memory_, + &caller_registers)) + return NULL; + + // Construct a new stack frame given the values the CFI recovered. + scoped_ptr frame(new StackFrameARM()); + for (int i = 0; register_names[i]; i++) { +- CFIFrameInfo::RegisterValueMap::iterator entry = +- caller_registers.find(register_names[i]); +- if (entry != caller_registers.end()) { ++ bool found = false; ++ uint32_t v = caller_registers.get(&found, register_names[i]); ++ if (found) { + // We recovered the value of this register; fill the context with the + // value from caller_registers. + frame->context_validity |= StackFrameARM::RegisterValidFlag(i); +- frame->context.iregs[i] = entry->second; ++ frame->context.iregs[i] = v; + } else if (4 <= i && i <= 11 && (last_frame->context_validity & + StackFrameARM::RegisterValidFlag(i))) { + // If the STACK CFI data doesn't mention some callee-saves register, and + // it is valid in the callee, assume the callee has not yet changed it. + // Registers r4 through r11 are callee-saves, according to the Procedure + // Call Standard for the ARM Architecture, which the Linux ABI follows. + frame->context_validity |= StackFrameARM::RegisterValidFlag(i); + frame->context.iregs[i] = last_frame->context.iregs[i]; + } + } + // If the CFI doesn't recover the PC explicitly, then use .ra. + if (!(frame->context_validity & StackFrameARM::CONTEXT_VALID_PC)) { +- CFIFrameInfo::RegisterValueMap::iterator entry = +- caller_registers.find(ustr__ZDra()); +- if (entry != caller_registers.end()) { ++ bool found = false; ++ uint32_t v = caller_registers.get(&found, ustr__ZDra()); ++ if (found) { + if (fp_register_ == -1) { + frame->context_validity |= StackFrameARM::CONTEXT_VALID_PC; +- frame->context.iregs[MD_CONTEXT_ARM_REG_PC] = entry->second; ++ frame->context.iregs[MD_CONTEXT_ARM_REG_PC] = v; + } else { + // The CFI updated the link register and not the program counter. + // Handle getting the program counter from the link register. + frame->context_validity |= StackFrameARM::CONTEXT_VALID_PC; + frame->context_validity |= StackFrameARM::CONTEXT_VALID_LR; +- frame->context.iregs[MD_CONTEXT_ARM_REG_LR] = entry->second; ++ frame->context.iregs[MD_CONTEXT_ARM_REG_LR] = v; + frame->context.iregs[MD_CONTEXT_ARM_REG_PC] = + last_frame->context.iregs[MD_CONTEXT_ARM_REG_LR]; + } + } + } + // If the CFI doesn't recover the SP explicitly, then use .cfa. + if (!(frame->context_validity & StackFrameARM::CONTEXT_VALID_SP)) { +- CFIFrameInfo::RegisterValueMap::iterator entry = +- caller_registers.find(ustr__ZDcfa()); +- if (entry != caller_registers.end()) { ++ bool found = false; ++ uint32_t v = caller_registers.get(&found, ustr__ZDcfa()); ++ if (found) { + frame->context_validity |= StackFrameARM::CONTEXT_VALID_SP; +- frame->context.iregs[MD_CONTEXT_ARM_REG_SP] = entry->second; ++ frame->context.iregs[MD_CONTEXT_ARM_REG_SP] = v; + } + } + + // If we didn't recover the PC and the SP, then the frame isn't very useful. + static const int essentials = (StackFrameARM::CONTEXT_VALID_SP + | StackFrameARM::CONTEXT_VALID_PC); + if ((frame->context_validity & essentials) != essentials) + return NULL; +diff --git a/src/processor/stackwalker_x86.cc b/src/processor/stackwalker_x86.cc +--- a/src/processor/stackwalker_x86.cc ++++ b/src/processor/stackwalker_x86.cc +@@ -194,26 +194,26 @@ + } + } + + // Set up the dictionary for the PostfixEvaluator. %ebp and %esp are used + // in each program string, and their previous values are known, so set them + // here. + PostfixEvaluator::DictionaryType dictionary; + // Provide the current register values. +- dictionary[ustr__ZSebp()] = last_frame->context.ebp; +- dictionary[ustr__ZSesp()] = last_frame->context.esp; ++ dictionary.set(ustr__ZSebp(), last_frame->context.ebp); ++ dictionary.set(ustr__ZSesp(), last_frame->context.esp); + // Provide constants from the debug info for last_frame and its callee. + // .cbCalleeParams is a Breakpad extension that allows us to use the + // PostfixEvaluator engine when certain types of debugging information + // are present without having to write the constants into the program + // string as literals. +- dictionary[ustr__ZDcbCalleeParams()] = last_frame_callee_parameter_size; +- dictionary[ustr__ZDcbSavedRegs()] = last_frame_info->saved_register_size; +- dictionary[ustr__ZDcbLocals()] = last_frame_info->local_size; ++ dictionary.set(ustr__ZDcbCalleeParams(), last_frame_callee_parameter_size); ++ dictionary.set(ustr__ZDcbSavedRegs(), last_frame_info->saved_register_size); ++ dictionary.set(ustr__ZDcbLocals(), last_frame_info->local_size); + + uint32_t raSearchStart = last_frame->context.esp + + last_frame_callee_parameter_size + + last_frame_info->local_size + + last_frame_info->saved_register_size; + + uint32_t raSearchStartOld = raSearchStart; + uint32_t found = 0; // dummy value +@@ -232,20 +232,20 @@ + // Skip one slot from the stack and do another scan in order to get the + // actual return address. + raSearchStart += 4; + ScanForReturnAddress(raSearchStart, &raSearchStart, &found, 3); + } + + // The difference between raSearch and raSearchStart is unknown, + // but making them the same seems to work well in practice. +- dictionary[ustr__ZDraSearchStart()] = raSearchStart; +- dictionary[ustr__ZDraSearch()] = raSearchStart; ++ dictionary.set(ustr__ZDraSearchStart(), raSearchStart); ++ dictionary.set(ustr__ZDraSearch(), raSearchStart); + +- dictionary[ustr__ZDcbParams()] = last_frame_info->parameter_size; ++ dictionary.set(ustr__ZDcbParams(), last_frame_info->parameter_size); + + // Decide what type of program string to use. The program string is in + // postfix notation and will be passed to PostfixEvaluator::Evaluate. + // Given the dictionary and the program string, it is possible to compute + // the return address and the values of other registers in the calling + // function. Because of bugs described below, the stack may need to be + // scanned for these values. The results of program string evaluation + // will be used to determine whether to scan for better values. +@@ -325,18 +325,18 @@ + } + + // Now crank it out, making sure that the program string set at least the + // two required variables. + PostfixEvaluator evaluator = + PostfixEvaluator(&dictionary, memory_); + PostfixEvaluator::DictionaryValidityType dictionary_validity; + if (!evaluator.Evaluate(program_string, &dictionary_validity) || +- dictionary_validity.find(ustr__ZSeip()) == dictionary_validity.end() || +- dictionary_validity.find(ustr__ZSesp()) == dictionary_validity.end()) { ++ !dictionary_validity.have(ustr__ZSeip()) || ++ !dictionary_validity.have(ustr__ZSesp())) { + // Program string evaluation failed. It may be that %eip is not somewhere + // with stack frame info, and %ebp is pointing to non-stack memory, so + // our evaluation couldn't succeed. We'll scan the stack for a return + // address. This can happen if the stack is in a module for which + // we don't have symbols, and that module is compiled without a + // frame pointer. + uint32_t location_start = last_frame->context.esp; + uint32_t location, eip; +@@ -344,69 +344,70 @@ + // if we can't find an instruction pointer even with stack scanning, + // give up. + return NULL; + } + + // This seems like a reasonable return address. Since program string + // evaluation failed, use it and set %esp to the location above the + // one where the return address was found. +- dictionary[ustr__ZSeip()] = eip; +- dictionary[ustr__ZSesp()] = location + 4; ++ dictionary.set(ustr__ZSeip(), eip); ++ dictionary.set(ustr__ZSesp(), location + 4); + trust = StackFrame::FRAME_TRUST_SCAN; + } + + // Since this stack frame did not use %ebp in a traditional way, + // locating the return address isn't entirely deterministic. In that + // case, the stack can be scanned to locate the return address. + // + // However, if program string evaluation resulted in both %eip and + // %ebp values of 0, trust that the end of the stack has been + // reached and don't scan for anything else. +- if (dictionary[ustr__ZSeip()] != 0 || dictionary[ustr__ZSebp()] != 0) { ++ if (dictionary.get(ustr__ZSeip()) != 0 || ++ dictionary.get(ustr__ZSebp()) != 0) { + int offset = 0; + + // This scan can only be done if a CodeModules object is available, to + // check that candidate return addresses are in fact inside a module. + // + // TODO(mmentovai): This ignores dynamically-generated code. One possible + // solution is to check the minidump's memory map to see if the candidate + // %eip value comes from a mapped executable page, although this would + // require dumps that contain MINIDUMP_MEMORY_INFO, which the Breakpad + // client doesn't currently write (it would need to call MiniDumpWriteDump + // with the MiniDumpWithFullMemoryInfo type bit set). Even given this + // ability, older OSes (pre-XP SP2) and CPUs (pre-P4) don't enforce + // an independent execute privilege on memory pages. + +- uint32_t eip = dictionary[ustr__ZSeip()]; ++ uint32_t eip = dictionary.get(ustr__ZSeip()); + if (modules_ && !modules_->GetModuleForAddress(eip)) { + // The instruction pointer at .raSearchStart was invalid, so start + // looking one 32-bit word above that location. +- uint32_t location_start = dictionary[ustr__ZDraSearchStart()] + 4; ++ uint32_t location_start = dictionary.get(ustr__ZDraSearchStart()) + 4; + uint32_t location; + if (ScanForReturnAddress(location_start, &location, &eip)) { + // This is a better return address that what program string + // evaluation found. Use it, and set %esp to the location above the + // one where the return address was found. +- dictionary[ustr__ZSeip()] = eip; +- dictionary[ustr__ZSesp()] = location + 4; ++ dictionary.set(ustr__ZSeip(), eip); ++ dictionary.set(ustr__ZSesp(), location + 4); + offset = location - location_start; + trust = StackFrame::FRAME_TRUST_CFI_SCAN; + } + } + + if (recover_ebp) { + // When trying to recover the previous value of the frame pointer (%ebp), + // start looking at the lowest possible address in the saved-register + // area, and look at the entire saved register area, increased by the + // size of |offset| to account for additional data that may be on the + // stack. The scan is performed from the highest possible address to + // the lowest, because the expectation is that the function's prolog + // would have saved %ebp early. +- uint32_t ebp = dictionary[ustr__ZSebp()]; ++ uint32_t ebp = dictionary.get(ustr__ZSebp()); + + // When a scan for return address is used, it is possible to skip one or + // more frames (when return address is not in a known module). One + // indication for skipped frames is when the value of %ebp is lower than + // the location of the return address on the stack + bool has_skipped_frames = + (trust != StackFrame::FRAME_TRUST_CFI && ebp <= raSearchStart + offset); + +@@ -420,49 +421,49 @@ + location >= location_end; + location -= 4) { + if (!memory_->GetMemoryAtAddress(location, &ebp)) + break; + + if (memory_->GetMemoryAtAddress(ebp, &value)) { + // The candidate value is a pointer to the same memory region + // (the stack). Prefer it as a recovered %ebp result. +- dictionary[ustr__ZSebp()] = ebp; ++ dictionary.set(ustr__ZSebp(), ebp); + break; + } + } + } + } + } + + // Create a new stack frame (ownership will be transferred to the caller) + // and fill it in. + StackFrameX86* frame = new StackFrameX86(); + + frame->trust = trust; + frame->context = last_frame->context; +- frame->context.eip = dictionary[ustr__ZSeip()]; +- frame->context.esp = dictionary[ustr__ZSesp()]; +- frame->context.ebp = dictionary[ustr__ZSebp()]; ++ frame->context.eip = dictionary.get(ustr__ZSeip()); ++ frame->context.esp = dictionary.get(ustr__ZSesp()); ++ frame->context.ebp = dictionary.get(ustr__ZSebp()); + frame->context_validity = StackFrameX86::CONTEXT_VALID_EIP | + StackFrameX86::CONTEXT_VALID_ESP | + StackFrameX86::CONTEXT_VALID_EBP; + + // These are nonvolatile (callee-save) registers, and the program string + // may have filled them in. +- if (dictionary_validity.find(ustr__ZSebx()) != dictionary_validity.end()) { +- frame->context.ebx = dictionary[ustr__ZSebx()]; ++ if (dictionary_validity.have(ustr__ZSebx())) { ++ frame->context.ebx = dictionary.get(ustr__ZSebx()); + frame->context_validity |= StackFrameX86::CONTEXT_VALID_EBX; + } +- if (dictionary_validity.find(ustr__ZSesi()) != dictionary_validity.end()) { +- frame->context.esi = dictionary[ustr__ZSesi()]; ++ if (dictionary_validity.have(ustr__ZSesi())) { ++ frame->context.esi = dictionary.get(ustr__ZSesi()); + frame->context_validity |= StackFrameX86::CONTEXT_VALID_ESI; + } +- if (dictionary_validity.find(ustr__ZSedi()) != dictionary_validity.end()) { +- frame->context.edi = dictionary[ustr__ZSedi()]; ++ if (dictionary_validity.have(ustr__ZSedi())) { ++ frame->context.edi = dictionary.get(ustr__ZSedi()); + frame->context_validity |= StackFrameX86::CONTEXT_VALID_EDI; + } + + return frame; + } + + StackFrameX86* StackwalkerX86::GetCallerByCFIFrameInfo( + const vector &frames,