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