Sat, 03 Jan 2015 20:18:00 +0100
Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.
michael@0 | 1 | # HG changeset patch |
michael@0 | 2 | # User Ted Mielczarek <ted.mielczarek@gmail.com> |
michael@0 | 3 | # Date 1360255134 18000 |
michael@0 | 4 | # Node ID 294ce0d64d35a90be8ea91b719ead8b82aed29f7 |
michael@0 | 5 | # Parent d7bfb673574a3afe8b4f76f42fb52e2545770dad |
michael@0 | 6 | Rework PostfixEvaluator to use UniqueStringMap |
michael@0 | 7 | Patch by Julian Seward <jseward@acm.org>, R=ted |
michael@0 | 8 | |
michael@0 | 9 | diff --git a/src/common/unique_string.h b/src/common/unique_string.h |
michael@0 | 10 | --- a/src/common/unique_string.h |
michael@0 | 11 | +++ b/src/common/unique_string.h |
michael@0 | 12 | @@ -25,16 +25,17 @@ |
michael@0 | 13 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
michael@0 | 14 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
michael@0 | 15 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
michael@0 | 16 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
michael@0 | 17 | |
michael@0 | 18 | #ifndef COMMON_UNIQUE_STRING_H_ |
michael@0 | 19 | #define COMMON_UNIQUE_STRING_H_ |
michael@0 | 20 | |
michael@0 | 21 | +#include <map> |
michael@0 | 22 | #include <string> |
michael@0 | 23 | #include "common/using_std_string.h" |
michael@0 | 24 | |
michael@0 | 25 | namespace google_breakpad { |
michael@0 | 26 | |
michael@0 | 27 | // Abstract type |
michael@0 | 28 | class UniqueString; |
michael@0 | 29 | |
michael@0 | 30 | @@ -229,11 +230,112 @@ |
michael@0 | 31 | |
michael@0 | 32 | // ".ra" |
michael@0 | 33 | inline static const UniqueString* ustr__ZDra() { |
michael@0 | 34 | static const UniqueString* us = NULL; |
michael@0 | 35 | if (!us) us = ToUniqueString(".ra"); |
michael@0 | 36 | return us; |
michael@0 | 37 | } |
michael@0 | 38 | |
michael@0 | 39 | +template <typename ValueType> |
michael@0 | 40 | +class UniqueStringMap |
michael@0 | 41 | +{ |
michael@0 | 42 | + private: |
michael@0 | 43 | + static const int N_FIXED = 10; |
michael@0 | 44 | + |
michael@0 | 45 | + public: |
michael@0 | 46 | + UniqueStringMap() : n_fixed_(0), n_sets_(0), n_gets_(0), n_clears_(0) {}; |
michael@0 | 47 | + ~UniqueStringMap() {}; |
michael@0 | 48 | + |
michael@0 | 49 | + // Empty out the map. |
michael@0 | 50 | + void clear() { |
michael@0 | 51 | + ++n_clears_; |
michael@0 | 52 | + map_.clear(); |
michael@0 | 53 | + n_fixed_ = 0; |
michael@0 | 54 | + } |
michael@0 | 55 | + |
michael@0 | 56 | + // Do "map[ix] = v". |
michael@0 | 57 | + void set(const UniqueString* ix, ValueType v) { |
michael@0 | 58 | + ++n_sets_; |
michael@0 | 59 | + int i; |
michael@0 | 60 | + for (i = 0; i < n_fixed_; ++i) { |
michael@0 | 61 | + if (fixed_keys_[i] == ix) { |
michael@0 | 62 | + fixed_vals_[i] = v; |
michael@0 | 63 | + return; |
michael@0 | 64 | + } |
michael@0 | 65 | + } |
michael@0 | 66 | + if (n_fixed_ < N_FIXED) { |
michael@0 | 67 | + i = n_fixed_; |
michael@0 | 68 | + fixed_keys_[i] = ix; |
michael@0 | 69 | + fixed_vals_[i] = v; |
michael@0 | 70 | + ++n_fixed_; |
michael@0 | 71 | + } else { |
michael@0 | 72 | + map_[ix] = v; |
michael@0 | 73 | + } |
michael@0 | 74 | + } |
michael@0 | 75 | + |
michael@0 | 76 | + // Lookup 'ix' in the map, and also return a success/fail boolean. |
michael@0 | 77 | + ValueType get(/*OUT*/bool* have, const UniqueString* ix) const { |
michael@0 | 78 | + ++n_gets_; |
michael@0 | 79 | + int i; |
michael@0 | 80 | + for (i = 0; i < n_fixed_; ++i) { |
michael@0 | 81 | + if (fixed_keys_[i] == ix) { |
michael@0 | 82 | + *have = true; |
michael@0 | 83 | + return fixed_vals_[i]; |
michael@0 | 84 | + } |
michael@0 | 85 | + } |
michael@0 | 86 | + typename std::map<const UniqueString*, ValueType>::const_iterator it |
michael@0 | 87 | + = map_.find(ix); |
michael@0 | 88 | + if (it == map_.end()) { |
michael@0 | 89 | + *have = false; |
michael@0 | 90 | + return ValueType(); |
michael@0 | 91 | + } else { |
michael@0 | 92 | + *have = true; |
michael@0 | 93 | + return it->second; |
michael@0 | 94 | + } |
michael@0 | 95 | + }; |
michael@0 | 96 | + |
michael@0 | 97 | + // Lookup 'ix' in the map, and return zero if it is not present. |
michael@0 | 98 | + ValueType get(const UniqueString* ix) const { |
michael@0 | 99 | + ++n_gets_; |
michael@0 | 100 | + bool found; |
michael@0 | 101 | + ValueType v = get(&found, ix); |
michael@0 | 102 | + return found ? v : ValueType(); |
michael@0 | 103 | + } |
michael@0 | 104 | + |
michael@0 | 105 | + // Find out whether 'ix' is in the map. |
michael@0 | 106 | + bool have(const UniqueString* ix) const { |
michael@0 | 107 | + ++n_gets_; |
michael@0 | 108 | + bool found; |
michael@0 | 109 | + (void)get(&found, ix); |
michael@0 | 110 | + return found; |
michael@0 | 111 | + } |
michael@0 | 112 | + |
michael@0 | 113 | + // Copy the contents to a std::map, generally for testing. |
michael@0 | 114 | + void copy_to_map(std::map<const UniqueString*, ValueType>* m) const { |
michael@0 | 115 | + m->clear(); |
michael@0 | 116 | + int i; |
michael@0 | 117 | + for (i = 0; i < n_fixed_; ++i) { |
michael@0 | 118 | + (*m)[fixed_keys_[i]] = fixed_vals_[i]; |
michael@0 | 119 | + } |
michael@0 | 120 | + m->insert(map_.begin(), map_.end()); |
michael@0 | 121 | + } |
michael@0 | 122 | + |
michael@0 | 123 | + // Note that users of this class rely on having also a sane |
michael@0 | 124 | + // assignment operator. The default one is OK, though. |
michael@0 | 125 | + // AFAICT there are no uses of the copy constructor, but if |
michael@0 | 126 | + // there were, the default one would also suffice. |
michael@0 | 127 | + |
michael@0 | 128 | + private: |
michael@0 | 129 | + // Quick (hopefully) cache |
michael@0 | 130 | + const UniqueString* fixed_keys_[N_FIXED]; |
michael@0 | 131 | + ValueType fixed_vals_[N_FIXED]; |
michael@0 | 132 | + int n_fixed_; // 0 .. N_FIXED inclusive |
michael@0 | 133 | + // Fallback storage when the cache is filled |
michael@0 | 134 | + std::map<const UniqueString*, ValueType> map_; |
michael@0 | 135 | + |
michael@0 | 136 | + // For tracking usage stats. |
michael@0 | 137 | + mutable int n_sets_, n_gets_, n_clears_; |
michael@0 | 138 | +}; |
michael@0 | 139 | + |
michael@0 | 140 | } // namespace google_breakpad |
michael@0 | 141 | |
michael@0 | 142 | #endif // COMMON_UNIQUE_STRING_H_ |
michael@0 | 143 | diff --git a/src/processor/basic_source_line_resolver_unittest.cc b/src/processor/basic_source_line_resolver_unittest.cc |
michael@0 | 144 | --- a/src/processor/basic_source_line_resolver_unittest.cc |
michael@0 | 145 | +++ b/src/processor/basic_source_line_resolver_unittest.cc |
michael@0 | 146 | @@ -24,16 +24,17 @@ |
michael@0 | 147 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
michael@0 | 148 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
michael@0 | 149 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
michael@0 | 150 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
michael@0 | 151 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
michael@0 | 152 | |
michael@0 | 153 | #include <stdio.h> |
michael@0 | 154 | |
michael@0 | 155 | +#include <map> |
michael@0 | 156 | #include <string> |
michael@0 | 157 | |
michael@0 | 158 | #include "breakpad_googletest_includes.h" |
michael@0 | 159 | #include "common/scoped_ptr.h" |
michael@0 | 160 | #include "common/using_std_string.h" |
michael@0 | 161 | #include "google_breakpad/processor/basic_source_line_resolver.h" |
michael@0 | 162 | #include "google_breakpad/processor/code_module.h" |
michael@0 | 163 | #include "google_breakpad/processor/stack_frame.h" |
michael@0 | 164 | @@ -47,16 +48,17 @@ |
michael@0 | 165 | |
michael@0 | 166 | using google_breakpad::BasicSourceLineResolver; |
michael@0 | 167 | using google_breakpad::CFIFrameInfo; |
michael@0 | 168 | using google_breakpad::CodeModule; |
michael@0 | 169 | using google_breakpad::FromUniqueString; |
michael@0 | 170 | using google_breakpad::MemoryRegion; |
michael@0 | 171 | using google_breakpad::StackFrame; |
michael@0 | 172 | using google_breakpad::ToUniqueString; |
michael@0 | 173 | +using google_breakpad::UniqueString; |
michael@0 | 174 | using google_breakpad::WindowsFrameInfo; |
michael@0 | 175 | using google_breakpad::linked_ptr; |
michael@0 | 176 | using google_breakpad::scoped_ptr; |
michael@0 | 177 | using google_breakpad::ustr__ZDcfa; |
michael@0 | 178 | using google_breakpad::ustr__ZDra; |
michael@0 | 179 | using google_breakpad::ustr__ZSebx; |
michael@0 | 180 | using google_breakpad::ustr__ZSebp; |
michael@0 | 181 | using google_breakpad::ustr__ZSedi; |
michael@0 | 182 | @@ -113,27 +115,30 @@ |
michael@0 | 183 | }; |
michael@0 | 184 | |
michael@0 | 185 | // Verify that, for every association in ACTUAL, EXPECTED has the same |
michael@0 | 186 | // association. (That is, ACTUAL's associations should be a subset of |
michael@0 | 187 | // EXPECTED's.) Also verify that ACTUAL has associations for ".ra" and |
michael@0 | 188 | // ".cfa". |
michael@0 | 189 | static bool VerifyRegisters( |
michael@0 | 190 | const char *file, int line, |
michael@0 | 191 | - const CFIFrameInfo::RegisterValueMap<uint32_t> &expected, |
michael@0 | 192 | - const CFIFrameInfo::RegisterValueMap<uint32_t> &actual) { |
michael@0 | 193 | - CFIFrameInfo::RegisterValueMap<uint32_t>::const_iterator a; |
michael@0 | 194 | + const std::map<const UniqueString*, uint32_t> &expected, |
michael@0 | 195 | + const CFIFrameInfo::RegisterValueMap<uint32_t> &actual_regmap) { |
michael@0 | 196 | + std::map<const UniqueString*, uint32_t> actual; |
michael@0 | 197 | + actual_regmap.copy_to_map(&actual); |
michael@0 | 198 | + |
michael@0 | 199 | + std::map<const UniqueString*, uint32_t>::const_iterator a; |
michael@0 | 200 | a = actual.find(ustr__ZDcfa()); |
michael@0 | 201 | if (a == actual.end()) |
michael@0 | 202 | return false; |
michael@0 | 203 | a = actual.find(ustr__ZDra()); |
michael@0 | 204 | if (a == actual.end()) |
michael@0 | 205 | return false; |
michael@0 | 206 | for (a = actual.begin(); a != actual.end(); a++) { |
michael@0 | 207 | - CFIFrameInfo::RegisterValueMap<uint32_t>::const_iterator e = |
michael@0 | 208 | + std::map<const UniqueString*, uint32_t>::const_iterator e = |
michael@0 | 209 | expected.find(a->first); |
michael@0 | 210 | if (e == expected.end()) { |
michael@0 | 211 | fprintf(stderr, "%s:%d: unexpected register '%s' recovered, value 0x%x\n", |
michael@0 | 212 | file, line, FromUniqueString(a->first), a->second); |
michael@0 | 213 | return false; |
michael@0 | 214 | } |
michael@0 | 215 | if (e->second != a->second) { |
michael@0 | 216 | fprintf(stderr, |
michael@0 | 217 | @@ -258,86 +263,86 @@ |
michael@0 | 218 | |
michael@0 | 219 | frame.instruction = 0x3e9f; |
michael@0 | 220 | frame.module = &module1; |
michael@0 | 221 | cfi_frame_info.reset(resolver.FindCFIFrameInfo(&frame)); |
michael@0 | 222 | ASSERT_FALSE(cfi_frame_info.get()); |
michael@0 | 223 | |
michael@0 | 224 | CFIFrameInfo::RegisterValueMap<uint32_t> current_registers; |
michael@0 | 225 | CFIFrameInfo::RegisterValueMap<uint32_t> caller_registers; |
michael@0 | 226 | - CFIFrameInfo::RegisterValueMap<uint32_t> expected_caller_registers; |
michael@0 | 227 | + std::map<const UniqueString*, uint32_t> expected_caller_registers; |
michael@0 | 228 | MockMemoryRegion memory; |
michael@0 | 229 | |
michael@0 | 230 | // Regardless of which instruction evaluation takes place at, it |
michael@0 | 231 | // should produce the same values for the caller's registers. |
michael@0 | 232 | expected_caller_registers[ustr__ZDcfa()] = 0x1001c; |
michael@0 | 233 | expected_caller_registers[ustr__ZDra()] = 0xf6438648; |
michael@0 | 234 | expected_caller_registers[ustr__ZSebp()] = 0x10038; |
michael@0 | 235 | expected_caller_registers[ustr__ZSebx()] = 0x98ecadc3; |
michael@0 | 236 | expected_caller_registers[ustr__ZSesi()] = 0x878f7524; |
michael@0 | 237 | expected_caller_registers[ustr__ZSedi()] = 0x6312f9a5; |
michael@0 | 238 | |
michael@0 | 239 | frame.instruction = 0x3d40; |
michael@0 | 240 | frame.module = &module1; |
michael@0 | 241 | current_registers.clear(); |
michael@0 | 242 | - current_registers[ustr__ZSesp()] = 0x10018; |
michael@0 | 243 | - current_registers[ustr__ZSebp()] = 0x10038; |
michael@0 | 244 | - current_registers[ustr__ZSebx()] = 0x98ecadc3; |
michael@0 | 245 | - current_registers[ustr__ZSesi()] = 0x878f7524; |
michael@0 | 246 | - current_registers[ustr__ZSedi()] = 0x6312f9a5; |
michael@0 | 247 | + current_registers.set(ustr__ZSesp(), 0x10018); |
michael@0 | 248 | + current_registers.set(ustr__ZSebp(), 0x10038); |
michael@0 | 249 | + current_registers.set(ustr__ZSebx(), 0x98ecadc3); |
michael@0 | 250 | + current_registers.set(ustr__ZSesi(), 0x878f7524); |
michael@0 | 251 | + current_registers.set(ustr__ZSedi(), 0x6312f9a5); |
michael@0 | 252 | cfi_frame_info.reset(resolver.FindCFIFrameInfo(&frame)); |
michael@0 | 253 | ASSERT_TRUE(cfi_frame_info.get()); |
michael@0 | 254 | ASSERT_TRUE(cfi_frame_info.get() |
michael@0 | 255 | ->FindCallerRegs<uint32_t>(current_registers, memory, |
michael@0 | 256 | &caller_registers)); |
michael@0 | 257 | ASSERT_TRUE(VerifyRegisters(__FILE__, __LINE__, |
michael@0 | 258 | expected_caller_registers, caller_registers)); |
michael@0 | 259 | |
michael@0 | 260 | frame.instruction = 0x3d41; |
michael@0 | 261 | - current_registers[ustr__ZSesp()] = 0x10014; |
michael@0 | 262 | + current_registers.set(ustr__ZSesp(), 0x10014); |
michael@0 | 263 | cfi_frame_info.reset(resolver.FindCFIFrameInfo(&frame)); |
michael@0 | 264 | ASSERT_TRUE(cfi_frame_info.get()); |
michael@0 | 265 | ASSERT_TRUE(cfi_frame_info.get() |
michael@0 | 266 | ->FindCallerRegs<uint32_t>(current_registers, memory, |
michael@0 | 267 | &caller_registers)); |
michael@0 | 268 | ASSERT_TRUE(VerifyRegisters(__FILE__, __LINE__, |
michael@0 | 269 | expected_caller_registers, caller_registers)); |
michael@0 | 270 | |
michael@0 | 271 | frame.instruction = 0x3d43; |
michael@0 | 272 | - current_registers[ustr__ZSebp()] = 0x10014; |
michael@0 | 273 | + current_registers.set(ustr__ZSebp(), 0x10014); |
michael@0 | 274 | cfi_frame_info.reset(resolver.FindCFIFrameInfo(&frame)); |
michael@0 | 275 | ASSERT_TRUE(cfi_frame_info.get()); |
michael@0 | 276 | ASSERT_TRUE(cfi_frame_info.get() |
michael@0 | 277 | ->FindCallerRegs<uint32_t>(current_registers, memory, |
michael@0 | 278 | &caller_registers)); |
michael@0 | 279 | VerifyRegisters(__FILE__, __LINE__, |
michael@0 | 280 | expected_caller_registers, caller_registers); |
michael@0 | 281 | |
michael@0 | 282 | frame.instruction = 0x3d54; |
michael@0 | 283 | - current_registers[ustr__ZSebx()] = 0x6864f054U; |
michael@0 | 284 | + current_registers.set(ustr__ZSebx(), 0x6864f054U); |
michael@0 | 285 | cfi_frame_info.reset(resolver.FindCFIFrameInfo(&frame)); |
michael@0 | 286 | ASSERT_TRUE(cfi_frame_info.get()); |
michael@0 | 287 | ASSERT_TRUE(cfi_frame_info.get() |
michael@0 | 288 | ->FindCallerRegs<uint32_t>(current_registers, memory, |
michael@0 | 289 | &caller_registers)); |
michael@0 | 290 | VerifyRegisters(__FILE__, __LINE__, |
michael@0 | 291 | expected_caller_registers, caller_registers); |
michael@0 | 292 | |
michael@0 | 293 | frame.instruction = 0x3d5a; |
michael@0 | 294 | - current_registers[ustr__ZSesi()] = 0x6285f79aU; |
michael@0 | 295 | + current_registers.set(ustr__ZSesi(), 0x6285f79aU); |
michael@0 | 296 | cfi_frame_info.reset(resolver.FindCFIFrameInfo(&frame)); |
michael@0 | 297 | ASSERT_TRUE(cfi_frame_info.get()); |
michael@0 | 298 | ASSERT_TRUE(cfi_frame_info.get() |
michael@0 | 299 | ->FindCallerRegs<uint32_t>(current_registers, memory, |
michael@0 | 300 | &caller_registers)); |
michael@0 | 301 | VerifyRegisters(__FILE__, __LINE__, |
michael@0 | 302 | expected_caller_registers, caller_registers); |
michael@0 | 303 | |
michael@0 | 304 | frame.instruction = 0x3d84; |
michael@0 | 305 | - current_registers[ustr__ZSedi()] = 0x64061449U; |
michael@0 | 306 | + current_registers.set(ustr__ZSedi(), 0x64061449U); |
michael@0 | 307 | cfi_frame_info.reset(resolver.FindCFIFrameInfo(&frame)); |
michael@0 | 308 | ASSERT_TRUE(cfi_frame_info.get()); |
michael@0 | 309 | ASSERT_TRUE(cfi_frame_info.get() |
michael@0 | 310 | ->FindCallerRegs<uint32_t>(current_registers, memory, |
michael@0 | 311 | &caller_registers)); |
michael@0 | 312 | VerifyRegisters(__FILE__, __LINE__, |
michael@0 | 313 | expected_caller_registers, caller_registers); |
michael@0 | 314 | |
michael@0 | 315 | diff --git a/src/processor/cfi_frame_info-inl.h b/src/processor/cfi_frame_info-inl.h |
michael@0 | 316 | --- a/src/processor/cfi_frame_info-inl.h |
michael@0 | 317 | +++ b/src/processor/cfi_frame_info-inl.h |
michael@0 | 318 | @@ -35,64 +35,64 @@ |
michael@0 | 319 | |
michael@0 | 320 | #ifndef PROCESSOR_CFI_FRAME_INFO_INL_H_ |
michael@0 | 321 | #define PROCESSOR_CFI_FRAME_INFO_INL_H_ |
michael@0 | 322 | |
michael@0 | 323 | #include <string.h> |
michael@0 | 324 | |
michael@0 | 325 | namespace google_breakpad { |
michael@0 | 326 | |
michael@0 | 327 | -template <typename RegisterType, class RawContextType> |
michael@0 | 328 | -bool SimpleCFIWalker<RegisterType, RawContextType>::FindCallerRegisters( |
michael@0 | 329 | +template <typename RegisterValueType, class RawContextType> |
michael@0 | 330 | +bool SimpleCFIWalker<RegisterValueType, RawContextType>::FindCallerRegisters( |
michael@0 | 331 | const MemoryRegion &memory, |
michael@0 | 332 | const CFIFrameInfo &cfi_frame_info, |
michael@0 | 333 | const RawContextType &callee_context, |
michael@0 | 334 | int callee_validity, |
michael@0 | 335 | RawContextType *caller_context, |
michael@0 | 336 | int *caller_validity) const { |
michael@0 | 337 | - typedef CFIFrameInfo::RegisterValueMap<RegisterType> ValueMap; |
michael@0 | 338 | + typedef CFIFrameInfo::RegisterValueMap<RegisterValueType> ValueMap; |
michael@0 | 339 | ValueMap callee_registers; |
michael@0 | 340 | ValueMap caller_registers; |
michael@0 | 341 | - // Just for brevity. |
michael@0 | 342 | - typename ValueMap::const_iterator caller_none = caller_registers.end(); |
michael@0 | 343 | |
michael@0 | 344 | // Populate callee_registers with register values from callee_context. |
michael@0 | 345 | for (size_t i = 0; i < map_size_; i++) { |
michael@0 | 346 | const RegisterSet &r = register_map_[i]; |
michael@0 | 347 | if (callee_validity & r.validity_flag) |
michael@0 | 348 | - callee_registers[r.name] = callee_context.*r.context_member; |
michael@0 | 349 | + callee_registers.set(r.name, callee_context.*r.context_member); |
michael@0 | 350 | } |
michael@0 | 351 | |
michael@0 | 352 | // Apply the rules, and see what register values they yield. |
michael@0 | 353 | - if (!cfi_frame_info.FindCallerRegs<RegisterType>(callee_registers, memory, |
michael@0 | 354 | - &caller_registers)) |
michael@0 | 355 | + if (!cfi_frame_info |
michael@0 | 356 | + .FindCallerRegs<RegisterValueType>(callee_registers, memory, |
michael@0 | 357 | + &caller_registers)) |
michael@0 | 358 | return false; |
michael@0 | 359 | |
michael@0 | 360 | // Populate *caller_context with the values the rules placed in |
michael@0 | 361 | // caller_registers. |
michael@0 | 362 | memset(caller_context, 0xda, sizeof(*caller_context)); |
michael@0 | 363 | *caller_validity = 0; |
michael@0 | 364 | for (size_t i = 0; i < map_size_; i++) { |
michael@0 | 365 | const RegisterSet &r = register_map_[i]; |
michael@0 | 366 | - typename ValueMap::const_iterator caller_entry; |
michael@0 | 367 | |
michael@0 | 368 | // Did the rules provide a value for this register by its name? |
michael@0 | 369 | - caller_entry = caller_registers.find(r.name); |
michael@0 | 370 | - if (caller_entry != caller_none) { |
michael@0 | 371 | - caller_context->*r.context_member = caller_entry->second; |
michael@0 | 372 | + bool found = false; |
michael@0 | 373 | + RegisterValueType v = caller_registers.get(&found, r.name); |
michael@0 | 374 | + if (found) { |
michael@0 | 375 | + caller_context->*r.context_member = v; |
michael@0 | 376 | *caller_validity |= r.validity_flag; |
michael@0 | 377 | continue; |
michael@0 | 378 | } |
michael@0 | 379 | |
michael@0 | 380 | // Did the rules provide a value for this register under its |
michael@0 | 381 | // alternate name? |
michael@0 | 382 | if (r.alternate_name) { |
michael@0 | 383 | - caller_entry = caller_registers.find(r.alternate_name); |
michael@0 | 384 | - if (caller_entry != caller_none) { |
michael@0 | 385 | - caller_context->*r.context_member = caller_entry->second; |
michael@0 | 386 | + found = false; |
michael@0 | 387 | + v = caller_registers.get(&found, r.alternate_name); |
michael@0 | 388 | + if (found) { |
michael@0 | 389 | + caller_context->*r.context_member = v; |
michael@0 | 390 | *caller_validity |= r.validity_flag; |
michael@0 | 391 | continue; |
michael@0 | 392 | } |
michael@0 | 393 | } |
michael@0 | 394 | |
michael@0 | 395 | // Is this a callee-saves register? The walker assumes that these |
michael@0 | 396 | // still hold the caller's value if the CFI doesn't mention them. |
michael@0 | 397 | // |
michael@0 | 398 | diff --git a/src/processor/cfi_frame_info.cc b/src/processor/cfi_frame_info.cc |
michael@0 | 399 | --- a/src/processor/cfi_frame_info.cc |
michael@0 | 400 | +++ b/src/processor/cfi_frame_info.cc |
michael@0 | 401 | @@ -66,33 +66,33 @@ |
michael@0 | 402 | V cfa; |
michael@0 | 403 | working = registers; |
michael@0 | 404 | if (!evaluator.EvaluateForValue(cfa_rule_, &cfa)) |
michael@0 | 405 | return false; |
michael@0 | 406 | |
michael@0 | 407 | // Then, compute the return address. |
michael@0 | 408 | V ra; |
michael@0 | 409 | working = registers; |
michael@0 | 410 | - working[ustr__ZDcfa()] = cfa; |
michael@0 | 411 | + working.set(ustr__ZDcfa(), cfa); |
michael@0 | 412 | if (!evaluator.EvaluateForValue(ra_rule_, &ra)) |
michael@0 | 413 | return false; |
michael@0 | 414 | |
michael@0 | 415 | // Now, compute values for all the registers register_rules_ mentions. |
michael@0 | 416 | for (RuleMap::const_iterator it = register_rules_.begin(); |
michael@0 | 417 | it != register_rules_.end(); it++) { |
michael@0 | 418 | V value; |
michael@0 | 419 | working = registers; |
michael@0 | 420 | - working[ustr__ZDcfa()] = cfa; |
michael@0 | 421 | + working.set(ustr__ZDcfa(), cfa); |
michael@0 | 422 | if (!evaluator.EvaluateForValue(it->second, &value)) |
michael@0 | 423 | return false; |
michael@0 | 424 | - (*caller_registers)[it->first] = value; |
michael@0 | 425 | + caller_registers->set(it->first, value); |
michael@0 | 426 | } |
michael@0 | 427 | |
michael@0 | 428 | - (*caller_registers)[ustr__ZDra()] = ra; |
michael@0 | 429 | - (*caller_registers)[ustr__ZDcfa()] = cfa; |
michael@0 | 430 | + caller_registers->set(ustr__ZDra(), ra); |
michael@0 | 431 | + caller_registers->set(ustr__ZDcfa(), cfa); |
michael@0 | 432 | |
michael@0 | 433 | return true; |
michael@0 | 434 | } |
michael@0 | 435 | |
michael@0 | 436 | // Explicit instantiations for 32-bit and 64-bit architectures. |
michael@0 | 437 | template bool CFIFrameInfo::FindCallerRegs<uint32_t>( |
michael@0 | 438 | const RegisterValueMap<uint32_t> ®isters, |
michael@0 | 439 | const MemoryRegion &memory, |
michael@0 | 440 | diff --git a/src/processor/cfi_frame_info.h b/src/processor/cfi_frame_info.h |
michael@0 | 441 | --- a/src/processor/cfi_frame_info.h |
michael@0 | 442 | +++ b/src/processor/cfi_frame_info.h |
michael@0 | 443 | @@ -64,17 +64,17 @@ |
michael@0 | 444 | // changes given by the 'STACK CFI' records up to our instruction's |
michael@0 | 445 | // address. Then, use the FindCallerRegs member function to apply the |
michael@0 | 446 | // rules to the callee frame's register values, yielding the caller |
michael@0 | 447 | // frame's register values. |
michael@0 | 448 | class CFIFrameInfo { |
michael@0 | 449 | public: |
michael@0 | 450 | // A map from register names onto values. |
michael@0 | 451 | template<typename ValueType> class RegisterValueMap: |
michael@0 | 452 | - public map<const UniqueString*, ValueType> { }; |
michael@0 | 453 | + public UniqueStringMap<ValueType> { }; |
michael@0 | 454 | |
michael@0 | 455 | // Set the expression for computing a call frame address, return |
michael@0 | 456 | // address, or register's value. At least the CFA rule and the RA |
michael@0 | 457 | // rule must be set before calling FindCallerRegs. |
michael@0 | 458 | void SetCFARule(const Module::Expr& rule) { cfa_rule_ = rule; } |
michael@0 | 459 | void SetRARule(const Module::Expr& rule) { ra_rule_ = rule; } |
michael@0 | 460 | void SetRegisterRule(const UniqueString* register_name, |
michael@0 | 461 | const Module::Expr& rule) { |
michael@0 | 462 | diff --git a/src/processor/cfi_frame_info_unittest.cc b/src/processor/cfi_frame_info_unittest.cc |
michael@0 | 463 | --- a/src/processor/cfi_frame_info_unittest.cc |
michael@0 | 464 | +++ b/src/processor/cfi_frame_info_unittest.cc |
michael@0 | 465 | @@ -111,19 +111,18 @@ |
michael@0 | 466 | |
michael@0 | 467 | TEST_F(Simple, SetCFAAndRARule) { |
michael@0 | 468 | ExpectNoMemoryReferences(); |
michael@0 | 469 | |
michael@0 | 470 | cfi.SetCFARule(Module::Expr("330903416631436410")); |
michael@0 | 471 | cfi.SetRARule(Module::Expr("5870666104170902211")); |
michael@0 | 472 | ASSERT_TRUE(cfi.FindCallerRegs<uint64_t>(registers, memory, |
michael@0 | 473 | &caller_registers)); |
michael@0 | 474 | - ASSERT_EQ(2U, caller_registers.size()); |
michael@0 | 475 | - ASSERT_EQ(330903416631436410ULL, caller_registers[ustr__ZDcfa()]); |
michael@0 | 476 | - ASSERT_EQ(5870666104170902211ULL, caller_registers[ustr__ZDra()]); |
michael@0 | 477 | + ASSERT_EQ(330903416631436410ULL, caller_registers.get(ustr__ZDcfa())); |
michael@0 | 478 | + ASSERT_EQ(5870666104170902211ULL, caller_registers.get(ustr__ZDra())); |
michael@0 | 479 | |
michael@0 | 480 | ASSERT_EQ(".cfa: 330903416631436410 .ra: 5870666104170902211", |
michael@0 | 481 | cfi.Serialize()); |
michael@0 | 482 | } |
michael@0 | 483 | |
michael@0 | 484 | TEST_F(Simple, SetManyRules) { |
michael@0 | 485 | ExpectNoMemoryReferences(); |
michael@0 | 486 | |
michael@0 | 487 | @@ -136,23 +135,22 @@ |
michael@0 | 488 | const UniqueString* reg4 = ToUniqueString("uncopyrightables"); |
michael@0 | 489 | |
michael@0 | 490 | cfi.SetRegisterRule(reg1, Module::Expr(".cfa 54370437 *")); |
michael@0 | 491 | cfi.SetRegisterRule(reg2, Module::Expr("24076308 .cfa +")); |
michael@0 | 492 | cfi.SetRegisterRule(reg3, Module::Expr(".cfa 29801007 -")); |
michael@0 | 493 | cfi.SetRegisterRule(reg4, Module::Expr("92642917 .cfa /")); |
michael@0 | 494 | ASSERT_TRUE(cfi.FindCallerRegs<uint64_t>(registers, memory, |
michael@0 | 495 | &caller_registers)); |
michael@0 | 496 | - ASSERT_EQ(6U, caller_registers.size()); |
michael@0 | 497 | - ASSERT_EQ(7664691U, caller_registers[ustr__ZDcfa()]); |
michael@0 | 498 | - ASSERT_EQ(107469446U, caller_registers[ustr__ZDra()]); |
michael@0 | 499 | - ASSERT_EQ(416732599139967ULL, caller_registers[reg1]); |
michael@0 | 500 | - ASSERT_EQ(31740999U, caller_registers[reg2]); |
michael@0 | 501 | - ASSERT_EQ(-22136316ULL, caller_registers[reg3]); |
michael@0 | 502 | - ASSERT_EQ(12U, caller_registers[reg4]); |
michael@0 | 503 | + ASSERT_EQ(7664691U, caller_registers.get(ustr__ZDcfa())); |
michael@0 | 504 | + ASSERT_EQ(107469446U, caller_registers.get(ustr__ZDra())); |
michael@0 | 505 | + ASSERT_EQ(416732599139967ULL, caller_registers.get(reg1)); |
michael@0 | 506 | + ASSERT_EQ(31740999U, caller_registers.get(reg2)); |
michael@0 | 507 | + ASSERT_EQ(-22136316ULL, caller_registers.get(reg3)); |
michael@0 | 508 | + ASSERT_EQ(12U, caller_registers.get(reg4)); |
michael@0 | 509 | ASSERT_EQ(".cfa: $temp1 68737028 = $temp2 61072337 = $temp1 $temp2 - " |
michael@0 | 510 | ".ra: .cfa 99804755 + " |
michael@0 | 511 | "pubvexingfjordschmaltzy: .cfa 29801007 - " |
michael@0 | 512 | "register1: .cfa 54370437 * " |
michael@0 | 513 | "uncopyrightables: 92642917 .cfa / " |
michael@0 | 514 | "vodkathumbscrewingly: 24076308 .cfa +", |
michael@0 | 515 | cfi.Serialize()); |
michael@0 | 516 | } |
michael@0 | 517 | @@ -160,19 +158,18 @@ |
michael@0 | 518 | TEST_F(Simple, RulesOverride) { |
michael@0 | 519 | ExpectNoMemoryReferences(); |
michael@0 | 520 | |
michael@0 | 521 | cfi.SetCFARule(Module::Expr("330903416631436410")); |
michael@0 | 522 | cfi.SetRARule(Module::Expr("5870666104170902211")); |
michael@0 | 523 | cfi.SetCFARule(Module::Expr("2828089117179001")); |
michael@0 | 524 | ASSERT_TRUE(cfi.FindCallerRegs<uint64_t>(registers, memory, |
michael@0 | 525 | &caller_registers)); |
michael@0 | 526 | - ASSERT_EQ(2U, caller_registers.size()); |
michael@0 | 527 | - ASSERT_EQ(2828089117179001ULL, caller_registers[ustr__ZDcfa()]); |
michael@0 | 528 | - ASSERT_EQ(5870666104170902211ULL, caller_registers[ustr__ZDra()]); |
michael@0 | 529 | + ASSERT_EQ(2828089117179001ULL, caller_registers.get(ustr__ZDcfa())); |
michael@0 | 530 | + ASSERT_EQ(5870666104170902211ULL, caller_registers.get(ustr__ZDra())); |
michael@0 | 531 | ASSERT_EQ(".cfa: 2828089117179001 .ra: 5870666104170902211", |
michael@0 | 532 | cfi.Serialize()); |
michael@0 | 533 | } |
michael@0 | 534 | |
michael@0 | 535 | class Scope: public CFIFixture, public Test { }; |
michael@0 | 536 | |
michael@0 | 537 | // There should be no value for .cfa in scope when evaluating the CFA rule. |
michael@0 | 538 | TEST_F(Scope, CFALacksCFA) { |
michael@0 | 539 | @@ -196,37 +193,35 @@ |
michael@0 | 540 | |
michael@0 | 541 | // The current frame's registers should be in scope when evaluating |
michael@0 | 542 | // the CFA rule. |
michael@0 | 543 | TEST_F(Scope, CFASeesCurrentRegs) { |
michael@0 | 544 | ExpectNoMemoryReferences(); |
michael@0 | 545 | |
michael@0 | 546 | const UniqueString* reg1 = ToUniqueString(".baraminology"); |
michael@0 | 547 | const UniqueString* reg2 = ToUniqueString(".ornithorhynchus"); |
michael@0 | 548 | - registers[reg1] = 0x06a7bc63e4f13893ULL; |
michael@0 | 549 | - registers[reg2] = 0x5e0bf850bafce9d2ULL; |
michael@0 | 550 | + registers.set(reg1, 0x06a7bc63e4f13893ULL); |
michael@0 | 551 | + registers.set(reg2, 0x5e0bf850bafce9d2ULL); |
michael@0 | 552 | cfi.SetCFARule(Module::Expr(".baraminology .ornithorhynchus +")); |
michael@0 | 553 | cfi.SetRARule(Module::Expr("0")); |
michael@0 | 554 | ASSERT_TRUE(cfi.FindCallerRegs<uint64_t>(registers, memory, |
michael@0 | 555 | &caller_registers)); |
michael@0 | 556 | - ASSERT_EQ(2U, caller_registers.size()); |
michael@0 | 557 | ASSERT_EQ(0x06a7bc63e4f13893ULL + 0x5e0bf850bafce9d2ULL, |
michael@0 | 558 | - caller_registers[ustr__ZDcfa()]); |
michael@0 | 559 | + caller_registers.get(ustr__ZDcfa())); |
michael@0 | 560 | } |
michael@0 | 561 | |
michael@0 | 562 | // .cfa should be in scope in the return address expression. |
michael@0 | 563 | TEST_F(Scope, RASeesCFA) { |
michael@0 | 564 | ExpectNoMemoryReferences(); |
michael@0 | 565 | |
michael@0 | 566 | cfi.SetCFARule(Module::Expr("48364076")); |
michael@0 | 567 | cfi.SetRARule(Module::Expr(".cfa")); |
michael@0 | 568 | ASSERT_TRUE(cfi.FindCallerRegs<uint64_t>(registers, memory, |
michael@0 | 569 | &caller_registers)); |
michael@0 | 570 | - ASSERT_EQ(2U, caller_registers.size()); |
michael@0 | 571 | - ASSERT_EQ(48364076U, caller_registers[ustr__ZDra()]); |
michael@0 | 572 | + ASSERT_EQ(48364076U, caller_registers.get(ustr__ZDra())); |
michael@0 | 573 | } |
michael@0 | 574 | |
michael@0 | 575 | // There should be no value for .ra in scope when evaluating the CFA rule. |
michael@0 | 576 | TEST_F(Scope, RALacksRA) { |
michael@0 | 577 | ExpectNoMemoryReferences(); |
michael@0 | 578 | |
michael@0 | 579 | cfi.SetCFARule(Module::Expr("0")); |
michael@0 | 580 | cfi.SetRARule(Module::Expr(".ra")); |
michael@0 | 581 | @@ -236,36 +231,34 @@ |
michael@0 | 582 | |
michael@0 | 583 | // The current frame's registers should be in scope in the return |
michael@0 | 584 | // address expression. |
michael@0 | 585 | TEST_F(Scope, RASeesCurrentRegs) { |
michael@0 | 586 | ExpectNoMemoryReferences(); |
michael@0 | 587 | |
michael@0 | 588 | cfi.SetCFARule(Module::Expr("10359370")); |
michael@0 | 589 | const UniqueString* reg1 = ToUniqueString("noachian"); |
michael@0 | 590 | - registers[reg1] = 0x54dc4a5d8e5eb503ULL; |
michael@0 | 591 | + registers.set(reg1, 0x54dc4a5d8e5eb503ULL); |
michael@0 | 592 | cfi.SetRARule(Module::Expr(reg1, 0, false)); |
michael@0 | 593 | ASSERT_TRUE(cfi.FindCallerRegs<uint64_t>(registers, memory, |
michael@0 | 594 | &caller_registers)); |
michael@0 | 595 | - ASSERT_EQ(2U, caller_registers.size()); |
michael@0 | 596 | - ASSERT_EQ(0x54dc4a5d8e5eb503ULL, caller_registers[ustr__ZDra()]); |
michael@0 | 597 | + ASSERT_EQ(0x54dc4a5d8e5eb503ULL, caller_registers.get(ustr__ZDra())); |
michael@0 | 598 | } |
michael@0 | 599 | |
michael@0 | 600 | // .cfa should be in scope for register rules. |
michael@0 | 601 | TEST_F(Scope, RegistersSeeCFA) { |
michael@0 | 602 | ExpectNoMemoryReferences(); |
michael@0 | 603 | |
michael@0 | 604 | cfi.SetCFARule(Module::Expr("6515179")); |
michael@0 | 605 | cfi.SetRARule(Module::Expr(".cfa")); |
michael@0 | 606 | const UniqueString* reg1 = ToUniqueString("rogerian"); |
michael@0 | 607 | cfi.SetRegisterRule(reg1, Module::Expr(".cfa")); |
michael@0 | 608 | ASSERT_TRUE(cfi.FindCallerRegs<uint64_t>(registers, memory, |
michael@0 | 609 | &caller_registers)); |
michael@0 | 610 | - ASSERT_EQ(3U, caller_registers.size()); |
michael@0 | 611 | - ASSERT_EQ(6515179U, caller_registers[reg1]); |
michael@0 | 612 | + ASSERT_EQ(6515179U, caller_registers.get(reg1)); |
michael@0 | 613 | } |
michael@0 | 614 | |
michael@0 | 615 | // The return address should not be in scope for register rules. |
michael@0 | 616 | TEST_F(Scope, RegsLackRA) { |
michael@0 | 617 | ExpectNoMemoryReferences(); |
michael@0 | 618 | |
michael@0 | 619 | cfi.SetCFARule(Module::Expr("42740329")); |
michael@0 | 620 | cfi.SetRARule(Module::Expr("27045204")); |
michael@0 | 621 | @@ -276,27 +269,26 @@ |
michael@0 | 622 | } |
michael@0 | 623 | |
michael@0 | 624 | // Register rules can see the current frame's register values. |
michael@0 | 625 | TEST_F(Scope, RegsSeeRegs) { |
michael@0 | 626 | ExpectNoMemoryReferences(); |
michael@0 | 627 | |
michael@0 | 628 | const UniqueString* reg1 = ToUniqueString("$r1"); |
michael@0 | 629 | const UniqueString* reg2 = ToUniqueString("$r2"); |
michael@0 | 630 | - registers[reg1] = 0x6ed3582c4bedb9adULL; |
michael@0 | 631 | - registers[reg2] = 0xd27d9e742b8df6d0ULL; |
michael@0 | 632 | + registers.set(reg1, 0x6ed3582c4bedb9adULL); |
michael@0 | 633 | + registers.set(reg2, 0xd27d9e742b8df6d0ULL); |
michael@0 | 634 | cfi.SetCFARule(Module::Expr("88239303")); |
michael@0 | 635 | cfi.SetRARule(Module::Expr("30503835")); |
michael@0 | 636 | cfi.SetRegisterRule(reg1, Module::Expr("$r1 42175211 = $r2")); |
michael@0 | 637 | cfi.SetRegisterRule(reg2, Module::Expr("$r2 21357221 = $r1")); |
michael@0 | 638 | ASSERT_TRUE(cfi.FindCallerRegs<uint64_t>(registers, memory, |
michael@0 | 639 | &caller_registers)); |
michael@0 | 640 | - ASSERT_EQ(4U, caller_registers.size()); |
michael@0 | 641 | - ASSERT_EQ(0xd27d9e742b8df6d0ULL, caller_registers[reg1]); |
michael@0 | 642 | - ASSERT_EQ(0x6ed3582c4bedb9adULL, caller_registers[reg2]); |
michael@0 | 643 | + ASSERT_EQ(0xd27d9e742b8df6d0ULL, caller_registers.get(reg1)); |
michael@0 | 644 | + ASSERT_EQ(0x6ed3582c4bedb9adULL, caller_registers.get(reg2)); |
michael@0 | 645 | } |
michael@0 | 646 | |
michael@0 | 647 | // Each rule's temporaries are separate. |
michael@0 | 648 | TEST_F(Scope, SeparateTempsRA) { |
michael@0 | 649 | ExpectNoMemoryReferences(); |
michael@0 | 650 | |
michael@0 | 651 | cfi.SetCFARule(Module::Expr("$temp1 76569129 = $temp1")); |
michael@0 | 652 | cfi.SetRARule(Module::Expr("0")); |
michael@0 | 653 | @@ -440,39 +432,39 @@ |
michael@0 | 654 | CFIFrameInfoParseHandler handler; |
michael@0 | 655 | }; |
michael@0 | 656 | |
michael@0 | 657 | class ParseHandler: public ParseHandlerFixture, public Test { }; |
michael@0 | 658 | |
michael@0 | 659 | TEST_F(ParseHandler, CFARARule) { |
michael@0 | 660 | handler.CFARule("reg-for-cfa"); |
michael@0 | 661 | handler.RARule("reg-for-ra"); |
michael@0 | 662 | - registers[ToUniqueString("reg-for-cfa")] = 0x268a9a4a3821a797ULL; |
michael@0 | 663 | - registers[ToUniqueString("reg-for-ra")] = 0x6301b475b8b91c02ULL; |
michael@0 | 664 | + registers.set(ToUniqueString("reg-for-cfa"), 0x268a9a4a3821a797ULL); |
michael@0 | 665 | + registers.set(ToUniqueString("reg-for-ra"), 0x6301b475b8b91c02ULL); |
michael@0 | 666 | ASSERT_TRUE(cfi.FindCallerRegs<uint64_t>(registers, memory, |
michael@0 | 667 | &caller_registers)); |
michael@0 | 668 | - ASSERT_EQ(0x268a9a4a3821a797ULL, caller_registers[ustr__ZDcfa()]); |
michael@0 | 669 | - ASSERT_EQ(0x6301b475b8b91c02ULL, caller_registers[ustr__ZDra()]); |
michael@0 | 670 | + ASSERT_EQ(0x268a9a4a3821a797ULL, caller_registers.get(ustr__ZDcfa())); |
michael@0 | 671 | + ASSERT_EQ(0x6301b475b8b91c02ULL, caller_registers.get(ustr__ZDra())); |
michael@0 | 672 | } |
michael@0 | 673 | |
michael@0 | 674 | TEST_F(ParseHandler, RegisterRules) { |
michael@0 | 675 | handler.CFARule("reg-for-cfa"); |
michael@0 | 676 | handler.RARule("reg-for-ra"); |
michael@0 | 677 | handler.RegisterRule(ToUniqueString("reg1"), "reg-for-reg1"); |
michael@0 | 678 | handler.RegisterRule(ToUniqueString("reg2"), "reg-for-reg2"); |
michael@0 | 679 | - registers[ToUniqueString("reg-for-cfa")] = 0x268a9a4a3821a797ULL; |
michael@0 | 680 | - registers[ToUniqueString("reg-for-ra")] = 0x6301b475b8b91c02ULL; |
michael@0 | 681 | - registers[ToUniqueString("reg-for-reg1")] = 0x06cde8e2ff062481ULL; |
michael@0 | 682 | - registers[ToUniqueString("reg-for-reg2")] = 0xff0c4f76403173e2ULL; |
michael@0 | 683 | + registers.set(ToUniqueString("reg-for-cfa"), 0x268a9a4a3821a797ULL); |
michael@0 | 684 | + registers.set(ToUniqueString("reg-for-ra"), 0x6301b475b8b91c02ULL); |
michael@0 | 685 | + registers.set(ToUniqueString("reg-for-reg1"), 0x06cde8e2ff062481ULL); |
michael@0 | 686 | + registers.set(ToUniqueString("reg-for-reg2"), 0xff0c4f76403173e2ULL); |
michael@0 | 687 | ASSERT_TRUE(cfi.FindCallerRegs<uint64_t>(registers, memory, |
michael@0 | 688 | &caller_registers)); |
michael@0 | 689 | - ASSERT_EQ(0x268a9a4a3821a797ULL, caller_registers[ustr__ZDcfa()]); |
michael@0 | 690 | - ASSERT_EQ(0x6301b475b8b91c02ULL, caller_registers[ustr__ZDra()]); |
michael@0 | 691 | - ASSERT_EQ(0x06cde8e2ff062481ULL, caller_registers[ToUniqueString("reg1")]); |
michael@0 | 692 | - ASSERT_EQ(0xff0c4f76403173e2ULL, caller_registers[ToUniqueString("reg2")]); |
michael@0 | 693 | + ASSERT_EQ(0x268a9a4a3821a797ULL, caller_registers.get(ustr__ZDcfa())); |
michael@0 | 694 | + ASSERT_EQ(0x6301b475b8b91c02ULL, caller_registers.get(ustr__ZDra())); |
michael@0 | 695 | + ASSERT_EQ(0x06cde8e2ff062481ULL, caller_registers.get(ToUniqueString("reg1"))); |
michael@0 | 696 | + ASSERT_EQ(0xff0c4f76403173e2ULL, caller_registers.get(ToUniqueString("reg2"))); |
michael@0 | 697 | } |
michael@0 | 698 | |
michael@0 | 699 | struct SimpleCFIWalkerFixture { |
michael@0 | 700 | struct RawContext { |
michael@0 | 701 | uint64_t r0, r1, r2, r3, r4, sp, pc; |
michael@0 | 702 | }; |
michael@0 | 703 | enum Validity { |
michael@0 | 704 | R0_VALID = 0x01, |
michael@0 | 705 | diff --git a/src/processor/fast_source_line_resolver_unittest.cc b/src/processor/fast_source_line_resolver_unittest.cc |
michael@0 | 706 | --- a/src/processor/fast_source_line_resolver_unittest.cc |
michael@0 | 707 | +++ b/src/processor/fast_source_line_resolver_unittest.cc |
michael@0 | 708 | @@ -59,16 +59,17 @@ |
michael@0 | 709 | using google_breakpad::FromUniqueString; |
michael@0 | 710 | using google_breakpad::ModuleSerializer; |
michael@0 | 711 | using google_breakpad::ModuleComparer; |
michael@0 | 712 | using google_breakpad::CFIFrameInfo; |
michael@0 | 713 | using google_breakpad::CodeModule; |
michael@0 | 714 | using google_breakpad::MemoryRegion; |
michael@0 | 715 | using google_breakpad::StackFrame; |
michael@0 | 716 | using google_breakpad::ToUniqueString; |
michael@0 | 717 | +using google_breakpad::UniqueString; |
michael@0 | 718 | using google_breakpad::WindowsFrameInfo; |
michael@0 | 719 | using google_breakpad::linked_ptr; |
michael@0 | 720 | using google_breakpad::scoped_ptr; |
michael@0 | 721 | using google_breakpad::ustr__ZDcfa; |
michael@0 | 722 | using google_breakpad::ustr__ZDra; |
michael@0 | 723 | using google_breakpad::ustr__ZSebx; |
michael@0 | 724 | using google_breakpad::ustr__ZSebp; |
michael@0 | 725 | using google_breakpad::ustr__ZSedi; |
michael@0 | 726 | @@ -125,27 +126,30 @@ |
michael@0 | 727 | }; |
michael@0 | 728 | |
michael@0 | 729 | // Verify that, for every association in ACTUAL, EXPECTED has the same |
michael@0 | 730 | // association. (That is, ACTUAL's associations should be a subset of |
michael@0 | 731 | // EXPECTED's.) Also verify that ACTUAL has associations for ".ra" and |
michael@0 | 732 | // ".cfa". |
michael@0 | 733 | static bool VerifyRegisters( |
michael@0 | 734 | const char *file, int line, |
michael@0 | 735 | - const CFIFrameInfo::RegisterValueMap<uint32_t> &expected, |
michael@0 | 736 | - const CFIFrameInfo::RegisterValueMap<uint32_t> &actual) { |
michael@0 | 737 | - CFIFrameInfo::RegisterValueMap<uint32_t>::const_iterator a; |
michael@0 | 738 | + const std::map<const UniqueString*, uint32_t> &expected, |
michael@0 | 739 | + const CFIFrameInfo::RegisterValueMap<uint32_t> &actual_regmap) { |
michael@0 | 740 | + std::map<const UniqueString*, uint32_t> actual; |
michael@0 | 741 | + actual_regmap.copy_to_map(&actual); |
michael@0 | 742 | + |
michael@0 | 743 | + std::map<const UniqueString*, uint32_t>::const_iterator a; |
michael@0 | 744 | a = actual.find(ustr__ZDcfa()); |
michael@0 | 745 | if (a == actual.end()) |
michael@0 | 746 | return false; |
michael@0 | 747 | a = actual.find(ustr__ZDra()); |
michael@0 | 748 | if (a == actual.end()) |
michael@0 | 749 | return false; |
michael@0 | 750 | for (a = actual.begin(); a != actual.end(); a++) { |
michael@0 | 751 | - CFIFrameInfo::RegisterValueMap<uint32_t>::const_iterator e = |
michael@0 | 752 | + std::map<const UniqueString*, uint32_t>::const_iterator e = |
michael@0 | 753 | expected.find(a->first); |
michael@0 | 754 | if (e == expected.end()) { |
michael@0 | 755 | fprintf(stderr, "%s:%d: unexpected register '%s' recovered, value 0x%x\n", |
michael@0 | 756 | file, line, FromUniqueString(a->first), a->second); |
michael@0 | 757 | return false; |
michael@0 | 758 | } |
michael@0 | 759 | if (e->second != a->second) { |
michael@0 | 760 | fprintf(stderr, |
michael@0 | 761 | @@ -286,86 +290,87 @@ |
michael@0 | 762 | |
michael@0 | 763 | frame.instruction = 0x3e9f; |
michael@0 | 764 | frame.module = &module1; |
michael@0 | 765 | cfi_frame_info.reset(fast_resolver.FindCFIFrameInfo(&frame)); |
michael@0 | 766 | ASSERT_FALSE(cfi_frame_info.get()); |
michael@0 | 767 | |
michael@0 | 768 | CFIFrameInfo::RegisterValueMap<uint32_t> current_registers; |
michael@0 | 769 | CFIFrameInfo::RegisterValueMap<uint32_t> caller_registers; |
michael@0 | 770 | - CFIFrameInfo::RegisterValueMap<uint32_t> expected_caller_registers; |
michael@0 | 771 | + std::map<const UniqueString*, uint32_t> expected_caller_registers; |
michael@0 | 772 | MockMemoryRegion memory; |
michael@0 | 773 | |
michael@0 | 774 | // Regardless of which instruction evaluation takes place at, it |
michael@0 | 775 | // should produce the same values for the caller's registers. |
michael@0 | 776 | + // should produce the same values for the caller's registers. |
michael@0 | 777 | expected_caller_registers[ustr__ZDcfa()] = 0x1001c; |
michael@0 | 778 | - expected_caller_registers[ustr__ZDra()] = 0xf6438648; |
michael@0 | 779 | + expected_caller_registers[ustr__ZDra()] = 0xf6438648; |
michael@0 | 780 | expected_caller_registers[ustr__ZSebp()] = 0x10038; |
michael@0 | 781 | expected_caller_registers[ustr__ZSebx()] = 0x98ecadc3; |
michael@0 | 782 | expected_caller_registers[ustr__ZSesi()] = 0x878f7524; |
michael@0 | 783 | expected_caller_registers[ustr__ZSedi()] = 0x6312f9a5; |
michael@0 | 784 | |
michael@0 | 785 | frame.instruction = 0x3d40; |
michael@0 | 786 | frame.module = &module1; |
michael@0 | 787 | current_registers.clear(); |
michael@0 | 788 | - current_registers[ustr__ZSesp()] = 0x10018; |
michael@0 | 789 | - current_registers[ustr__ZSebp()] = 0x10038; |
michael@0 | 790 | - current_registers[ustr__ZSebx()] = 0x98ecadc3; |
michael@0 | 791 | - current_registers[ustr__ZSesi()] = 0x878f7524; |
michael@0 | 792 | - current_registers[ustr__ZSedi()] = 0x6312f9a5; |
michael@0 | 793 | + current_registers.set(ustr__ZSesp(), 0x10018); |
michael@0 | 794 | + current_registers.set(ustr__ZSebp(), 0x10038); |
michael@0 | 795 | + current_registers.set(ustr__ZSebx(), 0x98ecadc3); |
michael@0 | 796 | + current_registers.set(ustr__ZSesi(), 0x878f7524); |
michael@0 | 797 | + current_registers.set(ustr__ZSedi(), 0x6312f9a5); |
michael@0 | 798 | cfi_frame_info.reset(fast_resolver.FindCFIFrameInfo(&frame)); |
michael@0 | 799 | ASSERT_TRUE(cfi_frame_info.get()); |
michael@0 | 800 | ASSERT_TRUE(cfi_frame_info.get() |
michael@0 | 801 | ->FindCallerRegs<uint32_t>(current_registers, memory, |
michael@0 | 802 | &caller_registers)); |
michael@0 | 803 | ASSERT_TRUE(VerifyRegisters(__FILE__, __LINE__, |
michael@0 | 804 | expected_caller_registers, caller_registers)); |
michael@0 | 805 | |
michael@0 | 806 | frame.instruction = 0x3d41; |
michael@0 | 807 | - current_registers[ustr__ZSesp()] = 0x10014; |
michael@0 | 808 | + current_registers.set(ustr__ZSesp(), 0x10014); |
michael@0 | 809 | cfi_frame_info.reset(fast_resolver.FindCFIFrameInfo(&frame)); |
michael@0 | 810 | ASSERT_TRUE(cfi_frame_info.get()); |
michael@0 | 811 | ASSERT_TRUE(cfi_frame_info.get() |
michael@0 | 812 | ->FindCallerRegs<uint32_t>(current_registers, memory, |
michael@0 | 813 | &caller_registers)); |
michael@0 | 814 | ASSERT_TRUE(VerifyRegisters(__FILE__, __LINE__, |
michael@0 | 815 | expected_caller_registers, caller_registers)); |
michael@0 | 816 | |
michael@0 | 817 | frame.instruction = 0x3d43; |
michael@0 | 818 | - current_registers[ustr__ZSebp()] = 0x10014; |
michael@0 | 819 | + current_registers.set(ustr__ZSebp(), 0x10014); |
michael@0 | 820 | cfi_frame_info.reset(fast_resolver.FindCFIFrameInfo(&frame)); |
michael@0 | 821 | ASSERT_TRUE(cfi_frame_info.get()); |
michael@0 | 822 | ASSERT_TRUE(cfi_frame_info.get() |
michael@0 | 823 | ->FindCallerRegs<uint32_t>(current_registers, memory, |
michael@0 | 824 | &caller_registers)); |
michael@0 | 825 | VerifyRegisters(__FILE__, __LINE__, |
michael@0 | 826 | expected_caller_registers, caller_registers); |
michael@0 | 827 | |
michael@0 | 828 | frame.instruction = 0x3d54; |
michael@0 | 829 | - current_registers[ustr__ZSebx()] = 0x6864f054U; |
michael@0 | 830 | + current_registers.set(ustr__ZSebx(), 0x6864f054U); |
michael@0 | 831 | cfi_frame_info.reset(fast_resolver.FindCFIFrameInfo(&frame)); |
michael@0 | 832 | ASSERT_TRUE(cfi_frame_info.get()); |
michael@0 | 833 | ASSERT_TRUE(cfi_frame_info.get() |
michael@0 | 834 | ->FindCallerRegs<uint32_t>(current_registers, memory, |
michael@0 | 835 | &caller_registers)); |
michael@0 | 836 | VerifyRegisters(__FILE__, __LINE__, |
michael@0 | 837 | expected_caller_registers, caller_registers); |
michael@0 | 838 | |
michael@0 | 839 | frame.instruction = 0x3d5a; |
michael@0 | 840 | - current_registers[ustr__ZSesi()] = 0x6285f79aU; |
michael@0 | 841 | + current_registers.set(ustr__ZSesi(), 0x6285f79aU); |
michael@0 | 842 | cfi_frame_info.reset(fast_resolver.FindCFIFrameInfo(&frame)); |
michael@0 | 843 | ASSERT_TRUE(cfi_frame_info.get()); |
michael@0 | 844 | ASSERT_TRUE(cfi_frame_info.get() |
michael@0 | 845 | ->FindCallerRegs<uint32_t>(current_registers, memory, |
michael@0 | 846 | &caller_registers)); |
michael@0 | 847 | VerifyRegisters(__FILE__, __LINE__, |
michael@0 | 848 | expected_caller_registers, caller_registers); |
michael@0 | 849 | |
michael@0 | 850 | frame.instruction = 0x3d84; |
michael@0 | 851 | - current_registers[ustr__ZSedi()] = 0x64061449U; |
michael@0 | 852 | + current_registers.set(ustr__ZSedi(), 0x64061449U); |
michael@0 | 853 | cfi_frame_info.reset(fast_resolver.FindCFIFrameInfo(&frame)); |
michael@0 | 854 | ASSERT_TRUE(cfi_frame_info.get()); |
michael@0 | 855 | ASSERT_TRUE(cfi_frame_info.get() |
michael@0 | 856 | ->FindCallerRegs<uint32_t>(current_registers, memory, |
michael@0 | 857 | &caller_registers)); |
michael@0 | 858 | VerifyRegisters(__FILE__, __LINE__, |
michael@0 | 859 | expected_caller_registers, caller_registers); |
michael@0 | 860 | |
michael@0 | 861 | diff --git a/src/processor/postfix_evaluator-inl.h b/src/processor/postfix_evaluator-inl.h |
michael@0 | 862 | --- a/src/processor/postfix_evaluator-inl.h |
michael@0 | 863 | +++ b/src/processor/postfix_evaluator-inl.h |
michael@0 | 864 | @@ -185,19 +185,19 @@ |
michael@0 | 865 | return false; |
michael@0 | 866 | } |
michael@0 | 867 | if (identifier == ustr__empty() || Index(identifier,0) != '$') { |
michael@0 | 868 | BPLOG(ERROR) << "Can't assign " << HexString(value) << " to " << |
michael@0 | 869 | identifier << ": " << expression; |
michael@0 | 870 | return false; |
michael@0 | 871 | } |
michael@0 | 872 | |
michael@0 | 873 | - (*dictionary_)[identifier] = value; |
michael@0 | 874 | + dictionary_->set(identifier, value); |
michael@0 | 875 | if (assigned) |
michael@0 | 876 | - (*assigned)[identifier] = true; |
michael@0 | 877 | + assigned->set(identifier, true); |
michael@0 | 878 | } else { |
michael@0 | 879 | // Push it onto the stack as-is, but first convert it either to a |
michael@0 | 880 | // ValueType (if a literal) or to a UniqueString* (if an identifier). |
michael@0 | 881 | // |
michael@0 | 882 | // First, try to treat the value as a literal. Literals may have leading |
michael@0 | 883 | // '-' sign, and the entire remaining string must be parseable as |
michael@0 | 884 | // ValueType. If this isn't possible, it can't be a literal, so treat it |
michael@0 | 885 | // as an identifier instead. |
michael@0 | 886 | @@ -300,28 +300,28 @@ |
michael@0 | 887 | |
michael@0 | 888 | return PopValue(result); |
michael@0 | 889 | } |
michael@0 | 890 | |
michael@0 | 891 | // Simple-form expressions |
michael@0 | 892 | case Module::kExprSimple: |
michael@0 | 893 | case Module::kExprSimpleMem: { |
michael@0 | 894 | // Look up the base value |
michael@0 | 895 | - typename DictionaryType::const_iterator iterator |
michael@0 | 896 | - = dictionary_->find(expr.ident_); |
michael@0 | 897 | - if (iterator == dictionary_->end()) { |
michael@0 | 898 | + bool found = false; |
michael@0 | 899 | + ValueType v = dictionary_->get(&found, expr.ident_); |
michael@0 | 900 | + if (!found) { |
michael@0 | 901 | // The identifier wasn't found in the dictionary. Don't imply any |
michael@0 | 902 | // default value, just fail. |
michael@0 | 903 | - BPLOG(INFO) << "Identifier " << expr.ident_ |
michael@0 | 904 | + BPLOG(INFO) << "Identifier " << FromUniqueString(expr.ident_) |
michael@0 | 905 | << " not in dictionary (kExprSimple{Mem})"; |
michael@0 | 906 | return false; |
michael@0 | 907 | } |
michael@0 | 908 | |
michael@0 | 909 | // Form the sum |
michael@0 | 910 | - ValueType sum = iterator->second + (int64_t)expr.offset_; |
michael@0 | 911 | + ValueType sum = v + (int64_t)expr.offset_; |
michael@0 | 912 | |
michael@0 | 913 | // and dereference if necessary |
michael@0 | 914 | if (expr.how_ == Module::kExprSimpleMem) { |
michael@0 | 915 | ValueType derefd; |
michael@0 | 916 | if (!memory_ || !memory_->GetMemoryAtAddress(sum, &derefd)) { |
michael@0 | 917 | return false; |
michael@0 | 918 | } |
michael@0 | 919 | *result = derefd; |
michael@0 | 920 | @@ -368,27 +368,27 @@ |
michael@0 | 921 | if ((result = PopValueOrIdentifier(&literal, &token)) == POP_RESULT_FAIL) { |
michael@0 | 922 | return false; |
michael@0 | 923 | } else if (result == POP_RESULT_VALUE) { |
michael@0 | 924 | // This is the easy case. |
michael@0 | 925 | *value = literal; |
michael@0 | 926 | } else { // result == POP_RESULT_IDENTIFIER |
michael@0 | 927 | // There was an identifier at the top of the stack. Resolve it to a |
michael@0 | 928 | // value by looking it up in the dictionary. |
michael@0 | 929 | - typename DictionaryType::const_iterator iterator = |
michael@0 | 930 | - dictionary_->find(token); |
michael@0 | 931 | - if (iterator == dictionary_->end()) { |
michael@0 | 932 | + bool found = false; |
michael@0 | 933 | + ValueType v = dictionary_->get(&found, token); |
michael@0 | 934 | + if (!found) { |
michael@0 | 935 | // The identifier wasn't found in the dictionary. Don't imply any |
michael@0 | 936 | // default value, just fail. |
michael@0 | 937 | BPLOG(INFO) << "Identifier " << FromUniqueString(token) |
michael@0 | 938 | << " not in dictionary"; |
michael@0 | 939 | return false; |
michael@0 | 940 | } |
michael@0 | 941 | |
michael@0 | 942 | - *value = iterator->second; |
michael@0 | 943 | + *value = v; |
michael@0 | 944 | } |
michael@0 | 945 | |
michael@0 | 946 | return true; |
michael@0 | 947 | } |
michael@0 | 948 | |
michael@0 | 949 | |
michael@0 | 950 | template<typename ValueType> |
michael@0 | 951 | bool PostfixEvaluator<ValueType>::PopValues(ValueType *value1, |
michael@0 | 952 | diff --git a/src/processor/postfix_evaluator.h b/src/processor/postfix_evaluator.h |
michael@0 | 953 | --- a/src/processor/postfix_evaluator.h |
michael@0 | 954 | +++ b/src/processor/postfix_evaluator.h |
michael@0 | 955 | @@ -93,18 +93,18 @@ |
michael@0 | 956 | StackElem(const UniqueString* ustr) { isValue = false; u.ustr = ustr; } |
michael@0 | 957 | bool isValue; |
michael@0 | 958 | union { ValueType val; const UniqueString* ustr; } u; |
michael@0 | 959 | }; |
michael@0 | 960 | |
michael@0 | 961 | template<typename ValueType> |
michael@0 | 962 | class PostfixEvaluator { |
michael@0 | 963 | public: |
michael@0 | 964 | - typedef map<const UniqueString*, ValueType> DictionaryType; |
michael@0 | 965 | - typedef map<const UniqueString*, bool> DictionaryValidityType; |
michael@0 | 966 | + typedef UniqueStringMap<ValueType> DictionaryType; |
michael@0 | 967 | + typedef UniqueStringMap<bool> DictionaryValidityType; |
michael@0 | 968 | |
michael@0 | 969 | // Create a PostfixEvaluator object that may be used (with Evaluate) on |
michael@0 | 970 | // one or more expressions. PostfixEvaluator does not take ownership of |
michael@0 | 971 | // either argument. |memory| may be NULL, in which case dereferencing |
michael@0 | 972 | // (^) will not be supported. |dictionary| may be NULL, but evaluation |
michael@0 | 973 | // will fail in that case unless set_dictionary is used before calling |
michael@0 | 974 | // Evaluate. |
michael@0 | 975 | PostfixEvaluator(DictionaryType *dictionary, const MemoryRegion *memory) |
michael@0 | 976 | diff --git a/src/processor/postfix_evaluator_unittest.cc b/src/processor/postfix_evaluator_unittest.cc |
michael@0 | 977 | --- a/src/processor/postfix_evaluator_unittest.cc |
michael@0 | 978 | +++ b/src/processor/postfix_evaluator_unittest.cc |
michael@0 | 979 | @@ -178,22 +178,22 @@ |
michael@0 | 980 | validate_data_0[ToUniqueString("$rAdd3")] = 4; |
michael@0 | 981 | validate_data_0[ToUniqueString("$rMul2")] = 54; |
michael@0 | 982 | |
michael@0 | 983 | // The second test set simulates a couple of MSVC program strings. |
michael@0 | 984 | // The data is fudged a little bit because the tests use FakeMemoryRegion |
michael@0 | 985 | // instead of a real stack snapshot, but the program strings are real and |
michael@0 | 986 | // the implementation doesn't know or care that the data is not real. |
michael@0 | 987 | PostfixEvaluator<unsigned int>::DictionaryType dictionary_1; |
michael@0 | 988 | - dictionary_1[ustr__ZSebp()] = 0xbfff0010; |
michael@0 | 989 | - dictionary_1[ustr__ZSeip()] = 0x10000000; |
michael@0 | 990 | - dictionary_1[ustr__ZSesp()] = 0xbfff0000; |
michael@0 | 991 | - dictionary_1[ustr__ZDcbSavedRegs()] = 4; |
michael@0 | 992 | - dictionary_1[ustr__ZDcbParams()] = 4; |
michael@0 | 993 | - dictionary_1[ustr__ZDraSearchStart()] = 0xbfff0020; |
michael@0 | 994 | + dictionary_1.set(ustr__ZSebp(), 0xbfff0010); |
michael@0 | 995 | + dictionary_1.set(ustr__ZSeip(), 0x10000000); |
michael@0 | 996 | + dictionary_1.set(ustr__ZSesp(), 0xbfff0000); |
michael@0 | 997 | + dictionary_1.set(ustr__ZDcbSavedRegs(), 4); |
michael@0 | 998 | + dictionary_1.set(ustr__ZDcbParams(), 4); |
michael@0 | 999 | + dictionary_1.set(ustr__ZDraSearchStart(), 0xbfff0020); |
michael@0 | 1000 | const EvaluateTest evaluate_tests_1[] = { |
michael@0 | 1001 | { "$T0 $ebp = $eip $T0 4 + ^ = $ebp $T0 ^ = $esp $T0 8 + = " |
michael@0 | 1002 | "$L $T0 .cbSavedRegs - = $P $T0 8 + .cbParams + =", true }, |
michael@0 | 1003 | // Intermediate state: $T0 = 0xbfff0010, $eip = 0xbfff0015, |
michael@0 | 1004 | // $ebp = 0xbfff0011, $esp = 0xbfff0018, |
michael@0 | 1005 | // $L = 0xbfff000c, $P = 0xbfff001c |
michael@0 | 1006 | { "$T0 $ebp = $eip $T0 4 + ^ = $ebp $T0 ^ = $esp $T0 8 + = " |
michael@0 | 1007 | "$L $T0 .cbSavedRegs - = $P $T0 8 + .cbParams + = $ebx $T0 28 - ^ =", |
michael@0 | 1008 | @@ -273,70 +273,65 @@ |
michael@0 | 1009 | for (map<const UniqueString*, unsigned int>::const_iterator |
michael@0 | 1010 | validate_iterator = |
michael@0 | 1011 | evaluate_test_set->validate_data->begin(); |
michael@0 | 1012 | validate_iterator != evaluate_test_set->validate_data->end(); |
michael@0 | 1013 | ++validate_iterator) { |
michael@0 | 1014 | const UniqueString* identifier = validate_iterator->first; |
michael@0 | 1015 | unsigned int expected_value = validate_iterator->second; |
michael@0 | 1016 | |
michael@0 | 1017 | - map<const UniqueString*, unsigned int>::const_iterator |
michael@0 | 1018 | - dictionary_iterator = |
michael@0 | 1019 | - evaluate_test_set->dictionary->find(identifier); |
michael@0 | 1020 | - |
michael@0 | 1021 | // The identifier must exist in the dictionary. |
michael@0 | 1022 | - if (dictionary_iterator == evaluate_test_set->dictionary->end()) { |
michael@0 | 1023 | + if (!evaluate_test_set->dictionary->have(identifier)) { |
michael@0 | 1024 | fprintf(stderr, "FAIL: evaluate test set %d/%d, " |
michael@0 | 1025 | "validate identifier \"%s\", " |
michael@0 | 1026 | "expected %d, observed not found\n", |
michael@0 | 1027 | evaluate_test_set_index, evaluate_test_set_count, |
michael@0 | 1028 | FromUniqueString(identifier), expected_value); |
michael@0 | 1029 | return false; |
michael@0 | 1030 | } |
michael@0 | 1031 | |
michael@0 | 1032 | // The value in the dictionary must be the same as the expected value. |
michael@0 | 1033 | - unsigned int observed_value = dictionary_iterator->second; |
michael@0 | 1034 | + unsigned int observed_value = |
michael@0 | 1035 | + evaluate_test_set->dictionary->get(identifier); |
michael@0 | 1036 | if (expected_value != observed_value) { |
michael@0 | 1037 | fprintf(stderr, "FAIL: evaluate test set %d/%d, " |
michael@0 | 1038 | "validate identifier \"%s\", " |
michael@0 | 1039 | "expected %d, observed %d\n", |
michael@0 | 1040 | evaluate_test_set_index, evaluate_test_set_count, |
michael@0 | 1041 | FromUniqueString(identifier), expected_value, observed_value); |
michael@0 | 1042 | return false; |
michael@0 | 1043 | } |
michael@0 | 1044 | |
michael@0 | 1045 | // The value must be set in the "assigned" dictionary if it was a |
michael@0 | 1046 | // variable. It must not have been assigned if it was a constant. |
michael@0 | 1047 | bool expected_assigned = FromUniqueString(identifier)[0] == '$'; |
michael@0 | 1048 | bool observed_assigned = false; |
michael@0 | 1049 | - PostfixEvaluator<unsigned int>::DictionaryValidityType::const_iterator |
michael@0 | 1050 | - iterator_assigned = assigned.find(identifier); |
michael@0 | 1051 | - if (iterator_assigned != assigned.end()) { |
michael@0 | 1052 | - observed_assigned = iterator_assigned->second; |
michael@0 | 1053 | + if (assigned.have(identifier)) { |
michael@0 | 1054 | + observed_assigned = assigned.get(identifier); |
michael@0 | 1055 | } |
michael@0 | 1056 | if (expected_assigned != observed_assigned) { |
michael@0 | 1057 | fprintf(stderr, "FAIL: evaluate test set %d/%d, " |
michael@0 | 1058 | "validate assignment of \"%s\", " |
michael@0 | 1059 | "expected %d, observed %d\n", |
michael@0 | 1060 | evaluate_test_set_index, evaluate_test_set_count, |
michael@0 | 1061 | FromUniqueString(identifier), expected_assigned, |
michael@0 | 1062 | observed_assigned); |
michael@0 | 1063 | return false; |
michael@0 | 1064 | } |
michael@0 | 1065 | } |
michael@0 | 1066 | } |
michael@0 | 1067 | |
michael@0 | 1068 | // EvaluateForValue tests. |
michael@0 | 1069 | PostfixEvaluator<unsigned int>::DictionaryType dictionary_2; |
michael@0 | 1070 | - dictionary_2[ustr__ZSebp()] = 0xbfff0010; |
michael@0 | 1071 | - dictionary_2[ustr__ZSeip()] = 0x10000000; |
michael@0 | 1072 | - dictionary_2[ustr__ZSesp()] = 0xbfff0000; |
michael@0 | 1073 | - dictionary_2[ustr__ZDcbSavedRegs()] = 4; |
michael@0 | 1074 | - dictionary_2[ustr__ZDcbParams()] = 4; |
michael@0 | 1075 | - dictionary_2[ustr__ZDraSearchStart()] = 0xbfff0020; |
michael@0 | 1076 | + dictionary_2.set(ustr__ZSebp(), 0xbfff0010); |
michael@0 | 1077 | + dictionary_2.set(ustr__ZSeip(), 0x10000000); |
michael@0 | 1078 | + dictionary_2.set(ustr__ZSesp(), 0xbfff0000); |
michael@0 | 1079 | + dictionary_2.set(ustr__ZDcbSavedRegs(), 4); |
michael@0 | 1080 | + dictionary_2.set(ustr__ZDcbParams(), 4); |
michael@0 | 1081 | + dictionary_2.set(ustr__ZDraSearchStart(), 0xbfff0020); |
michael@0 | 1082 | const EvaluateForValueTest evaluate_for_value_tests_2[] = { |
michael@0 | 1083 | { "28907223", true, 28907223 }, // simple constant |
michael@0 | 1084 | { "89854293 40010015 +", true, 89854293 + 40010015 }, // arithmetic |
michael@0 | 1085 | { "-870245 8769343 +", true, 7899098 }, // negative constants |
michael@0 | 1086 | { "$ebp $esp - $eip +", true, 0x10000010 }, // variable references |
michael@0 | 1087 | { "18929794 34015074", false, 0 }, // too many values |
michael@0 | 1088 | { "$ebp $ebp 4 - =", false, 0 }, // too few values |
michael@0 | 1089 | { "$new $eip = $new", true, 0x10000000 }, // make new variable |
michael@0 | 1090 | @@ -370,41 +365,43 @@ |
michael@0 | 1091 | if (test->evaluable && result != test->value) { |
michael@0 | 1092 | fprintf(stderr, "FAIL: evaluate for value test %d, " |
michael@0 | 1093 | "expected value to be 0x%x, but it was 0x%x\n", |
michael@0 | 1094 | i, test->value, result); |
michael@0 | 1095 | return false; |
michael@0 | 1096 | } |
michael@0 | 1097 | } |
michael@0 | 1098 | |
michael@0 | 1099 | + map<const UniqueString*, unsigned int> dictionary_2_map; |
michael@0 | 1100 | + dictionary_2.copy_to_map(&dictionary_2_map); |
michael@0 | 1101 | for (map<const UniqueString*, unsigned int>::iterator v = |
michael@0 | 1102 | validate_data_2.begin(); |
michael@0 | 1103 | v != validate_data_2.end(); v++) { |
michael@0 | 1104 | map<const UniqueString*, unsigned int>::iterator a = |
michael@0 | 1105 | - dictionary_2.find(v->first); |
michael@0 | 1106 | - if (a == dictionary_2.end()) { |
michael@0 | 1107 | + dictionary_2_map.find(v->first); |
michael@0 | 1108 | + if (a == dictionary_2_map.end()) { |
michael@0 | 1109 | fprintf(stderr, "FAIL: evaluate for value dictionary check: " |
michael@0 | 1110 | "expected dict[\"%s\"] to be 0x%x, but it was unset\n", |
michael@0 | 1111 | FromUniqueString(v->first), v->second); |
michael@0 | 1112 | return false; |
michael@0 | 1113 | } else if (a->second != v->second) { |
michael@0 | 1114 | fprintf(stderr, "FAIL: evaluate for value dictionary check: " |
michael@0 | 1115 | "expected dict[\"%s\"] to be 0x%x, but it was 0x%x\n", |
michael@0 | 1116 | FromUniqueString(v->first), v->second, a->second); |
michael@0 | 1117 | return false; |
michael@0 | 1118 | - } |
michael@0 | 1119 | - dictionary_2.erase(a); |
michael@0 | 1120 | + } |
michael@0 | 1121 | + dictionary_2_map.erase(a); |
michael@0 | 1122 | } |
michael@0 | 1123 | - |
michael@0 | 1124 | + |
michael@0 | 1125 | map<const UniqueString*, unsigned int>::iterator remaining = |
michael@0 | 1126 | - dictionary_2.begin(); |
michael@0 | 1127 | - if (remaining != dictionary_2.end()) { |
michael@0 | 1128 | + dictionary_2_map.begin(); |
michael@0 | 1129 | + if (remaining != dictionary_2_map.end()) { |
michael@0 | 1130 | fprintf(stderr, "FAIL: evaluation of test expressions put unexpected " |
michael@0 | 1131 | "values in dictionary:\n"); |
michael@0 | 1132 | - for (; remaining != dictionary_2.end(); remaining++) |
michael@0 | 1133 | + for (; remaining != dictionary_2_map.end(); remaining++) |
michael@0 | 1134 | fprintf(stderr, " dict[\"%s\"] == 0x%x\n", |
michael@0 | 1135 | FromUniqueString(remaining->first), remaining->second); |
michael@0 | 1136 | return false; |
michael@0 | 1137 | } |
michael@0 | 1138 | |
michael@0 | 1139 | return true; |
michael@0 | 1140 | } |
michael@0 | 1141 | |
michael@0 | 1142 | diff --git a/src/processor/stackwalker_arm.cc b/src/processor/stackwalker_arm.cc |
michael@0 | 1143 | --- a/src/processor/stackwalker_arm.cc |
michael@0 | 1144 | +++ b/src/processor/stackwalker_arm.cc |
michael@0 | 1145 | @@ -97,70 +97,70 @@ |
michael@0 | 1146 | ToUniqueString("fps"), ToUniqueString("cpsr"), |
michael@0 | 1147 | NULL |
michael@0 | 1148 | }; |
michael@0 | 1149 | |
michael@0 | 1150 | // Populate a dictionary with the valid register values in last_frame. |
michael@0 | 1151 | CFIFrameInfo::RegisterValueMap<uint32_t> callee_registers; |
michael@0 | 1152 | for (int i = 0; register_names[i]; i++) |
michael@0 | 1153 | if (last_frame->context_validity & StackFrameARM::RegisterValidFlag(i)) |
michael@0 | 1154 | - callee_registers[register_names[i]] = last_frame->context.iregs[i]; |
michael@0 | 1155 | + callee_registers.set(register_names[i], last_frame->context.iregs[i]); |
michael@0 | 1156 | |
michael@0 | 1157 | // Use the STACK CFI data to recover the caller's register values. |
michael@0 | 1158 | CFIFrameInfo::RegisterValueMap<uint32_t> caller_registers; |
michael@0 | 1159 | if (!cfi_frame_info->FindCallerRegs(callee_registers, *memory_, |
michael@0 | 1160 | &caller_registers)) |
michael@0 | 1161 | return NULL; |
michael@0 | 1162 | |
michael@0 | 1163 | // Construct a new stack frame given the values the CFI recovered. |
michael@0 | 1164 | scoped_ptr<StackFrameARM> frame(new StackFrameARM()); |
michael@0 | 1165 | for (int i = 0; register_names[i]; i++) { |
michael@0 | 1166 | - CFIFrameInfo::RegisterValueMap<uint32_t>::iterator entry = |
michael@0 | 1167 | - caller_registers.find(register_names[i]); |
michael@0 | 1168 | - if (entry != caller_registers.end()) { |
michael@0 | 1169 | + bool found = false; |
michael@0 | 1170 | + uint32_t v = caller_registers.get(&found, register_names[i]); |
michael@0 | 1171 | + if (found) { |
michael@0 | 1172 | // We recovered the value of this register; fill the context with the |
michael@0 | 1173 | // value from caller_registers. |
michael@0 | 1174 | frame->context_validity |= StackFrameARM::RegisterValidFlag(i); |
michael@0 | 1175 | - frame->context.iregs[i] = entry->second; |
michael@0 | 1176 | + frame->context.iregs[i] = v; |
michael@0 | 1177 | } else if (4 <= i && i <= 11 && (last_frame->context_validity & |
michael@0 | 1178 | StackFrameARM::RegisterValidFlag(i))) { |
michael@0 | 1179 | // If the STACK CFI data doesn't mention some callee-saves register, and |
michael@0 | 1180 | // it is valid in the callee, assume the callee has not yet changed it. |
michael@0 | 1181 | // Registers r4 through r11 are callee-saves, according to the Procedure |
michael@0 | 1182 | // Call Standard for the ARM Architecture, which the Linux ABI follows. |
michael@0 | 1183 | frame->context_validity |= StackFrameARM::RegisterValidFlag(i); |
michael@0 | 1184 | frame->context.iregs[i] = last_frame->context.iregs[i]; |
michael@0 | 1185 | } |
michael@0 | 1186 | } |
michael@0 | 1187 | // If the CFI doesn't recover the PC explicitly, then use .ra. |
michael@0 | 1188 | if (!(frame->context_validity & StackFrameARM::CONTEXT_VALID_PC)) { |
michael@0 | 1189 | - CFIFrameInfo::RegisterValueMap<uint32_t>::iterator entry = |
michael@0 | 1190 | - caller_registers.find(ustr__ZDra()); |
michael@0 | 1191 | - if (entry != caller_registers.end()) { |
michael@0 | 1192 | + bool found = false; |
michael@0 | 1193 | + uint32_t v = caller_registers.get(&found, ustr__ZDra()); |
michael@0 | 1194 | + if (found) { |
michael@0 | 1195 | if (fp_register_ == -1) { |
michael@0 | 1196 | frame->context_validity |= StackFrameARM::CONTEXT_VALID_PC; |
michael@0 | 1197 | - frame->context.iregs[MD_CONTEXT_ARM_REG_PC] = entry->second; |
michael@0 | 1198 | + frame->context.iregs[MD_CONTEXT_ARM_REG_PC] = v; |
michael@0 | 1199 | } else { |
michael@0 | 1200 | // The CFI updated the link register and not the program counter. |
michael@0 | 1201 | // Handle getting the program counter from the link register. |
michael@0 | 1202 | frame->context_validity |= StackFrameARM::CONTEXT_VALID_PC; |
michael@0 | 1203 | frame->context_validity |= StackFrameARM::CONTEXT_VALID_LR; |
michael@0 | 1204 | - frame->context.iregs[MD_CONTEXT_ARM_REG_LR] = entry->second; |
michael@0 | 1205 | + frame->context.iregs[MD_CONTEXT_ARM_REG_LR] = v; |
michael@0 | 1206 | frame->context.iregs[MD_CONTEXT_ARM_REG_PC] = |
michael@0 | 1207 | last_frame->context.iregs[MD_CONTEXT_ARM_REG_LR]; |
michael@0 | 1208 | } |
michael@0 | 1209 | } |
michael@0 | 1210 | } |
michael@0 | 1211 | // If the CFI doesn't recover the SP explicitly, then use .cfa. |
michael@0 | 1212 | if (!(frame->context_validity & StackFrameARM::CONTEXT_VALID_SP)) { |
michael@0 | 1213 | - CFIFrameInfo::RegisterValueMap<uint32_t>::iterator entry = |
michael@0 | 1214 | - caller_registers.find(ustr__ZDcfa()); |
michael@0 | 1215 | - if (entry != caller_registers.end()) { |
michael@0 | 1216 | + bool found = false; |
michael@0 | 1217 | + uint32_t v = caller_registers.get(&found, ustr__ZDcfa()); |
michael@0 | 1218 | + if (found) { |
michael@0 | 1219 | frame->context_validity |= StackFrameARM::CONTEXT_VALID_SP; |
michael@0 | 1220 | - frame->context.iregs[MD_CONTEXT_ARM_REG_SP] = entry->second; |
michael@0 | 1221 | + frame->context.iregs[MD_CONTEXT_ARM_REG_SP] = v; |
michael@0 | 1222 | } |
michael@0 | 1223 | } |
michael@0 | 1224 | |
michael@0 | 1225 | // If we didn't recover the PC and the SP, then the frame isn't very useful. |
michael@0 | 1226 | static const int essentials = (StackFrameARM::CONTEXT_VALID_SP |
michael@0 | 1227 | | StackFrameARM::CONTEXT_VALID_PC); |
michael@0 | 1228 | if ((frame->context_validity & essentials) != essentials) |
michael@0 | 1229 | return NULL; |
michael@0 | 1230 | diff --git a/src/processor/stackwalker_x86.cc b/src/processor/stackwalker_x86.cc |
michael@0 | 1231 | --- a/src/processor/stackwalker_x86.cc |
michael@0 | 1232 | +++ b/src/processor/stackwalker_x86.cc |
michael@0 | 1233 | @@ -194,26 +194,26 @@ |
michael@0 | 1234 | } |
michael@0 | 1235 | } |
michael@0 | 1236 | |
michael@0 | 1237 | // Set up the dictionary for the PostfixEvaluator. %ebp and %esp are used |
michael@0 | 1238 | // in each program string, and their previous values are known, so set them |
michael@0 | 1239 | // here. |
michael@0 | 1240 | PostfixEvaluator<uint32_t>::DictionaryType dictionary; |
michael@0 | 1241 | // Provide the current register values. |
michael@0 | 1242 | - dictionary[ustr__ZSebp()] = last_frame->context.ebp; |
michael@0 | 1243 | - dictionary[ustr__ZSesp()] = last_frame->context.esp; |
michael@0 | 1244 | + dictionary.set(ustr__ZSebp(), last_frame->context.ebp); |
michael@0 | 1245 | + dictionary.set(ustr__ZSesp(), last_frame->context.esp); |
michael@0 | 1246 | // Provide constants from the debug info for last_frame and its callee. |
michael@0 | 1247 | // .cbCalleeParams is a Breakpad extension that allows us to use the |
michael@0 | 1248 | // PostfixEvaluator engine when certain types of debugging information |
michael@0 | 1249 | // are present without having to write the constants into the program |
michael@0 | 1250 | // string as literals. |
michael@0 | 1251 | - dictionary[ustr__ZDcbCalleeParams()] = last_frame_callee_parameter_size; |
michael@0 | 1252 | - dictionary[ustr__ZDcbSavedRegs()] = last_frame_info->saved_register_size; |
michael@0 | 1253 | - dictionary[ustr__ZDcbLocals()] = last_frame_info->local_size; |
michael@0 | 1254 | + dictionary.set(ustr__ZDcbCalleeParams(), last_frame_callee_parameter_size); |
michael@0 | 1255 | + dictionary.set(ustr__ZDcbSavedRegs(), last_frame_info->saved_register_size); |
michael@0 | 1256 | + dictionary.set(ustr__ZDcbLocals(), last_frame_info->local_size); |
michael@0 | 1257 | |
michael@0 | 1258 | uint32_t raSearchStart = last_frame->context.esp + |
michael@0 | 1259 | last_frame_callee_parameter_size + |
michael@0 | 1260 | last_frame_info->local_size + |
michael@0 | 1261 | last_frame_info->saved_register_size; |
michael@0 | 1262 | |
michael@0 | 1263 | uint32_t raSearchStartOld = raSearchStart; |
michael@0 | 1264 | uint32_t found = 0; // dummy value |
michael@0 | 1265 | @@ -232,20 +232,20 @@ |
michael@0 | 1266 | // Skip one slot from the stack and do another scan in order to get the |
michael@0 | 1267 | // actual return address. |
michael@0 | 1268 | raSearchStart += 4; |
michael@0 | 1269 | ScanForReturnAddress(raSearchStart, &raSearchStart, &found, 3); |
michael@0 | 1270 | } |
michael@0 | 1271 | |
michael@0 | 1272 | // The difference between raSearch and raSearchStart is unknown, |
michael@0 | 1273 | // but making them the same seems to work well in practice. |
michael@0 | 1274 | - dictionary[ustr__ZDraSearchStart()] = raSearchStart; |
michael@0 | 1275 | - dictionary[ustr__ZDraSearch()] = raSearchStart; |
michael@0 | 1276 | + dictionary.set(ustr__ZDraSearchStart(), raSearchStart); |
michael@0 | 1277 | + dictionary.set(ustr__ZDraSearch(), raSearchStart); |
michael@0 | 1278 | |
michael@0 | 1279 | - dictionary[ustr__ZDcbParams()] = last_frame_info->parameter_size; |
michael@0 | 1280 | + dictionary.set(ustr__ZDcbParams(), last_frame_info->parameter_size); |
michael@0 | 1281 | |
michael@0 | 1282 | // Decide what type of program string to use. The program string is in |
michael@0 | 1283 | // postfix notation and will be passed to PostfixEvaluator::Evaluate. |
michael@0 | 1284 | // Given the dictionary and the program string, it is possible to compute |
michael@0 | 1285 | // the return address and the values of other registers in the calling |
michael@0 | 1286 | // function. Because of bugs described below, the stack may need to be |
michael@0 | 1287 | // scanned for these values. The results of program string evaluation |
michael@0 | 1288 | // will be used to determine whether to scan for better values. |
michael@0 | 1289 | @@ -325,18 +325,18 @@ |
michael@0 | 1290 | } |
michael@0 | 1291 | |
michael@0 | 1292 | // Now crank it out, making sure that the program string set at least the |
michael@0 | 1293 | // two required variables. |
michael@0 | 1294 | PostfixEvaluator<uint32_t> evaluator = |
michael@0 | 1295 | PostfixEvaluator<uint32_t>(&dictionary, memory_); |
michael@0 | 1296 | PostfixEvaluator<uint32_t>::DictionaryValidityType dictionary_validity; |
michael@0 | 1297 | if (!evaluator.Evaluate(program_string, &dictionary_validity) || |
michael@0 | 1298 | - dictionary_validity.find(ustr__ZSeip()) == dictionary_validity.end() || |
michael@0 | 1299 | - dictionary_validity.find(ustr__ZSesp()) == dictionary_validity.end()) { |
michael@0 | 1300 | + !dictionary_validity.have(ustr__ZSeip()) || |
michael@0 | 1301 | + !dictionary_validity.have(ustr__ZSesp())) { |
michael@0 | 1302 | // Program string evaluation failed. It may be that %eip is not somewhere |
michael@0 | 1303 | // with stack frame info, and %ebp is pointing to non-stack memory, so |
michael@0 | 1304 | // our evaluation couldn't succeed. We'll scan the stack for a return |
michael@0 | 1305 | // address. This can happen if the stack is in a module for which |
michael@0 | 1306 | // we don't have symbols, and that module is compiled without a |
michael@0 | 1307 | // frame pointer. |
michael@0 | 1308 | uint32_t location_start = last_frame->context.esp; |
michael@0 | 1309 | uint32_t location, eip; |
michael@0 | 1310 | @@ -344,69 +344,70 @@ |
michael@0 | 1311 | // if we can't find an instruction pointer even with stack scanning, |
michael@0 | 1312 | // give up. |
michael@0 | 1313 | return NULL; |
michael@0 | 1314 | } |
michael@0 | 1315 | |
michael@0 | 1316 | // This seems like a reasonable return address. Since program string |
michael@0 | 1317 | // evaluation failed, use it and set %esp to the location above the |
michael@0 | 1318 | // one where the return address was found. |
michael@0 | 1319 | - dictionary[ustr__ZSeip()] = eip; |
michael@0 | 1320 | - dictionary[ustr__ZSesp()] = location + 4; |
michael@0 | 1321 | + dictionary.set(ustr__ZSeip(), eip); |
michael@0 | 1322 | + dictionary.set(ustr__ZSesp(), location + 4); |
michael@0 | 1323 | trust = StackFrame::FRAME_TRUST_SCAN; |
michael@0 | 1324 | } |
michael@0 | 1325 | |
michael@0 | 1326 | // Since this stack frame did not use %ebp in a traditional way, |
michael@0 | 1327 | // locating the return address isn't entirely deterministic. In that |
michael@0 | 1328 | // case, the stack can be scanned to locate the return address. |
michael@0 | 1329 | // |
michael@0 | 1330 | // However, if program string evaluation resulted in both %eip and |
michael@0 | 1331 | // %ebp values of 0, trust that the end of the stack has been |
michael@0 | 1332 | // reached and don't scan for anything else. |
michael@0 | 1333 | - if (dictionary[ustr__ZSeip()] != 0 || dictionary[ustr__ZSebp()] != 0) { |
michael@0 | 1334 | + if (dictionary.get(ustr__ZSeip()) != 0 || |
michael@0 | 1335 | + dictionary.get(ustr__ZSebp()) != 0) { |
michael@0 | 1336 | int offset = 0; |
michael@0 | 1337 | |
michael@0 | 1338 | // This scan can only be done if a CodeModules object is available, to |
michael@0 | 1339 | // check that candidate return addresses are in fact inside a module. |
michael@0 | 1340 | // |
michael@0 | 1341 | // TODO(mmentovai): This ignores dynamically-generated code. One possible |
michael@0 | 1342 | // solution is to check the minidump's memory map to see if the candidate |
michael@0 | 1343 | // %eip value comes from a mapped executable page, although this would |
michael@0 | 1344 | // require dumps that contain MINIDUMP_MEMORY_INFO, which the Breakpad |
michael@0 | 1345 | // client doesn't currently write (it would need to call MiniDumpWriteDump |
michael@0 | 1346 | // with the MiniDumpWithFullMemoryInfo type bit set). Even given this |
michael@0 | 1347 | // ability, older OSes (pre-XP SP2) and CPUs (pre-P4) don't enforce |
michael@0 | 1348 | // an independent execute privilege on memory pages. |
michael@0 | 1349 | |
michael@0 | 1350 | - uint32_t eip = dictionary[ustr__ZSeip()]; |
michael@0 | 1351 | + uint32_t eip = dictionary.get(ustr__ZSeip()); |
michael@0 | 1352 | if (modules_ && !modules_->GetModuleForAddress(eip)) { |
michael@0 | 1353 | // The instruction pointer at .raSearchStart was invalid, so start |
michael@0 | 1354 | // looking one 32-bit word above that location. |
michael@0 | 1355 | - uint32_t location_start = dictionary[ustr__ZDraSearchStart()] + 4; |
michael@0 | 1356 | + uint32_t location_start = dictionary.get(ustr__ZDraSearchStart()) + 4; |
michael@0 | 1357 | uint32_t location; |
michael@0 | 1358 | if (ScanForReturnAddress(location_start, &location, &eip)) { |
michael@0 | 1359 | // This is a better return address that what program string |
michael@0 | 1360 | // evaluation found. Use it, and set %esp to the location above the |
michael@0 | 1361 | // one where the return address was found. |
michael@0 | 1362 | - dictionary[ustr__ZSeip()] = eip; |
michael@0 | 1363 | - dictionary[ustr__ZSesp()] = location + 4; |
michael@0 | 1364 | + dictionary.set(ustr__ZSeip(), eip); |
michael@0 | 1365 | + dictionary.set(ustr__ZSesp(), location + 4); |
michael@0 | 1366 | offset = location - location_start; |
michael@0 | 1367 | trust = StackFrame::FRAME_TRUST_CFI_SCAN; |
michael@0 | 1368 | } |
michael@0 | 1369 | } |
michael@0 | 1370 | |
michael@0 | 1371 | if (recover_ebp) { |
michael@0 | 1372 | // When trying to recover the previous value of the frame pointer (%ebp), |
michael@0 | 1373 | // start looking at the lowest possible address in the saved-register |
michael@0 | 1374 | // area, and look at the entire saved register area, increased by the |
michael@0 | 1375 | // size of |offset| to account for additional data that may be on the |
michael@0 | 1376 | // stack. The scan is performed from the highest possible address to |
michael@0 | 1377 | // the lowest, because the expectation is that the function's prolog |
michael@0 | 1378 | // would have saved %ebp early. |
michael@0 | 1379 | - uint32_t ebp = dictionary[ustr__ZSebp()]; |
michael@0 | 1380 | + uint32_t ebp = dictionary.get(ustr__ZSebp()); |
michael@0 | 1381 | |
michael@0 | 1382 | // When a scan for return address is used, it is possible to skip one or |
michael@0 | 1383 | // more frames (when return address is not in a known module). One |
michael@0 | 1384 | // indication for skipped frames is when the value of %ebp is lower than |
michael@0 | 1385 | // the location of the return address on the stack |
michael@0 | 1386 | bool has_skipped_frames = |
michael@0 | 1387 | (trust != StackFrame::FRAME_TRUST_CFI && ebp <= raSearchStart + offset); |
michael@0 | 1388 | |
michael@0 | 1389 | @@ -420,49 +421,49 @@ |
michael@0 | 1390 | location >= location_end; |
michael@0 | 1391 | location -= 4) { |
michael@0 | 1392 | if (!memory_->GetMemoryAtAddress(location, &ebp)) |
michael@0 | 1393 | break; |
michael@0 | 1394 | |
michael@0 | 1395 | if (memory_->GetMemoryAtAddress(ebp, &value)) { |
michael@0 | 1396 | // The candidate value is a pointer to the same memory region |
michael@0 | 1397 | // (the stack). Prefer it as a recovered %ebp result. |
michael@0 | 1398 | - dictionary[ustr__ZSebp()] = ebp; |
michael@0 | 1399 | + dictionary.set(ustr__ZSebp(), ebp); |
michael@0 | 1400 | break; |
michael@0 | 1401 | } |
michael@0 | 1402 | } |
michael@0 | 1403 | } |
michael@0 | 1404 | } |
michael@0 | 1405 | } |
michael@0 | 1406 | |
michael@0 | 1407 | // Create a new stack frame (ownership will be transferred to the caller) |
michael@0 | 1408 | // and fill it in. |
michael@0 | 1409 | StackFrameX86* frame = new StackFrameX86(); |
michael@0 | 1410 | |
michael@0 | 1411 | frame->trust = trust; |
michael@0 | 1412 | frame->context = last_frame->context; |
michael@0 | 1413 | - frame->context.eip = dictionary[ustr__ZSeip()]; |
michael@0 | 1414 | - frame->context.esp = dictionary[ustr__ZSesp()]; |
michael@0 | 1415 | - frame->context.ebp = dictionary[ustr__ZSebp()]; |
michael@0 | 1416 | + frame->context.eip = dictionary.get(ustr__ZSeip()); |
michael@0 | 1417 | + frame->context.esp = dictionary.get(ustr__ZSesp()); |
michael@0 | 1418 | + frame->context.ebp = dictionary.get(ustr__ZSebp()); |
michael@0 | 1419 | frame->context_validity = StackFrameX86::CONTEXT_VALID_EIP | |
michael@0 | 1420 | StackFrameX86::CONTEXT_VALID_ESP | |
michael@0 | 1421 | StackFrameX86::CONTEXT_VALID_EBP; |
michael@0 | 1422 | |
michael@0 | 1423 | // These are nonvolatile (callee-save) registers, and the program string |
michael@0 | 1424 | // may have filled them in. |
michael@0 | 1425 | - if (dictionary_validity.find(ustr__ZSebx()) != dictionary_validity.end()) { |
michael@0 | 1426 | - frame->context.ebx = dictionary[ustr__ZSebx()]; |
michael@0 | 1427 | + if (dictionary_validity.have(ustr__ZSebx())) { |
michael@0 | 1428 | + frame->context.ebx = dictionary.get(ustr__ZSebx()); |
michael@0 | 1429 | frame->context_validity |= StackFrameX86::CONTEXT_VALID_EBX; |
michael@0 | 1430 | } |
michael@0 | 1431 | - if (dictionary_validity.find(ustr__ZSesi()) != dictionary_validity.end()) { |
michael@0 | 1432 | - frame->context.esi = dictionary[ustr__ZSesi()]; |
michael@0 | 1433 | + if (dictionary_validity.have(ustr__ZSesi())) { |
michael@0 | 1434 | + frame->context.esi = dictionary.get(ustr__ZSesi()); |
michael@0 | 1435 | frame->context_validity |= StackFrameX86::CONTEXT_VALID_ESI; |
michael@0 | 1436 | } |
michael@0 | 1437 | - if (dictionary_validity.find(ustr__ZSedi()) != dictionary_validity.end()) { |
michael@0 | 1438 | - frame->context.edi = dictionary[ustr__ZSedi()]; |
michael@0 | 1439 | + if (dictionary_validity.have(ustr__ZSedi())) { |
michael@0 | 1440 | + frame->context.edi = dictionary.get(ustr__ZSedi()); |
michael@0 | 1441 | frame->context_validity |= StackFrameX86::CONTEXT_VALID_EDI; |
michael@0 | 1442 | } |
michael@0 | 1443 | |
michael@0 | 1444 | return frame; |
michael@0 | 1445 | } |
michael@0 | 1446 | |
michael@0 | 1447 | StackFrameX86* StackwalkerX86::GetCallerByCFIFrameInfo( |
michael@0 | 1448 | const vector<StackFrame*> &frames, |