Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
michael@0 | 1 | // Copyright (c) 2010 Google Inc. |
michael@0 | 2 | // All rights reserved. |
michael@0 | 3 | // |
michael@0 | 4 | // Redistribution and use in source and binary forms, with or without |
michael@0 | 5 | // modification, are permitted provided that the following conditions are |
michael@0 | 6 | // met: |
michael@0 | 7 | // |
michael@0 | 8 | // * Redistributions of source code must retain the above copyright |
michael@0 | 9 | // notice, this list of conditions and the following disclaimer. |
michael@0 | 10 | // * Redistributions in binary form must reproduce the above |
michael@0 | 11 | // copyright notice, this list of conditions and the following disclaimer |
michael@0 | 12 | // in the documentation and/or other materials provided with the |
michael@0 | 13 | // distribution. |
michael@0 | 14 | // * Neither the name of Google Inc. nor the names of its |
michael@0 | 15 | // contributors may be used to endorse or promote products derived from |
michael@0 | 16 | // this software without specific prior written permission. |
michael@0 | 17 | // |
michael@0 | 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
michael@0 | 19 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
michael@0 | 20 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
michael@0 | 21 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
michael@0 | 22 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
michael@0 | 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
michael@0 | 24 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
michael@0 | 25 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
michael@0 | 26 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
michael@0 | 27 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
michael@0 | 28 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
michael@0 | 29 | |
michael@0 | 30 | // stackwalker_arm.cc: arm-specific stackwalker. |
michael@0 | 31 | // |
michael@0 | 32 | // See stackwalker_arm.h for documentation. |
michael@0 | 33 | // |
michael@0 | 34 | // Author: Mark Mentovai, Ted Mielczarek, Jim Blandy |
michael@0 | 35 | |
michael@0 | 36 | #include <vector> |
michael@0 | 37 | |
michael@0 | 38 | #include "common/scoped_ptr.h" |
michael@0 | 39 | #include "google_breakpad/processor/call_stack.h" |
michael@0 | 40 | #include "google_breakpad/processor/memory_region.h" |
michael@0 | 41 | #include "google_breakpad/processor/source_line_resolver_interface.h" |
michael@0 | 42 | #include "google_breakpad/processor/stack_frame_cpu.h" |
michael@0 | 43 | #include "processor/cfi_frame_info.h" |
michael@0 | 44 | #include "common/logging.h" |
michael@0 | 45 | #include "processor/stackwalker_arm.h" |
michael@0 | 46 | |
michael@0 | 47 | namespace google_breakpad { |
michael@0 | 48 | |
michael@0 | 49 | |
michael@0 | 50 | StackwalkerARM::StackwalkerARM(const SystemInfo* system_info, |
michael@0 | 51 | const MDRawContextARM* context, |
michael@0 | 52 | int fp_register, |
michael@0 | 53 | MemoryRegion* memory, |
michael@0 | 54 | const CodeModules* modules, |
michael@0 | 55 | StackFrameSymbolizer* resolver_helper) |
michael@0 | 56 | : Stackwalker(system_info, memory, modules, resolver_helper), |
michael@0 | 57 | context_(context), fp_register_(fp_register), |
michael@0 | 58 | context_frame_validity_(StackFrameARM::CONTEXT_VALID_ALL) { } |
michael@0 | 59 | |
michael@0 | 60 | |
michael@0 | 61 | StackFrame* StackwalkerARM::GetContextFrame() { |
michael@0 | 62 | if (!context_) { |
michael@0 | 63 | BPLOG(ERROR) << "Can't get context frame without context"; |
michael@0 | 64 | return NULL; |
michael@0 | 65 | } |
michael@0 | 66 | |
michael@0 | 67 | StackFrameARM* frame = new StackFrameARM(); |
michael@0 | 68 | |
michael@0 | 69 | // The instruction pointer is stored directly in a register (r15), so pull it |
michael@0 | 70 | // straight out of the CPU context structure. |
michael@0 | 71 | frame->context = *context_; |
michael@0 | 72 | frame->context_validity = context_frame_validity_; |
michael@0 | 73 | frame->trust = StackFrame::FRAME_TRUST_CONTEXT; |
michael@0 | 74 | frame->instruction = frame->context.iregs[MD_CONTEXT_ARM_REG_PC]; |
michael@0 | 75 | |
michael@0 | 76 | return frame; |
michael@0 | 77 | } |
michael@0 | 78 | |
michael@0 | 79 | StackFrameARM* StackwalkerARM::GetCallerByCFIFrameInfo( |
michael@0 | 80 | const vector<StackFrame*> &frames, |
michael@0 | 81 | CFIFrameInfo* cfi_frame_info) { |
michael@0 | 82 | StackFrameARM* last_frame = static_cast<StackFrameARM*>(frames.back()); |
michael@0 | 83 | |
michael@0 | 84 | static const UniqueString *register_names[] = { |
michael@0 | 85 | ToUniqueString("r0"), ToUniqueString("r1"), |
michael@0 | 86 | ToUniqueString("r2"), ToUniqueString("r3"), |
michael@0 | 87 | ToUniqueString("r4"), ToUniqueString("r5"), |
michael@0 | 88 | ToUniqueString("r6"), ToUniqueString("r7"), |
michael@0 | 89 | ToUniqueString("r8"), ToUniqueString("r9"), |
michael@0 | 90 | ToUniqueString("r10"), ToUniqueString("r11"), |
michael@0 | 91 | ToUniqueString("r12"), ToUniqueString("sp"), |
michael@0 | 92 | ToUniqueString("lr"), ToUniqueString("pc"), |
michael@0 | 93 | ToUniqueString("f0"), ToUniqueString("f1"), |
michael@0 | 94 | ToUniqueString("f2"), ToUniqueString("f3"), |
michael@0 | 95 | ToUniqueString("f4"), ToUniqueString("f5"), |
michael@0 | 96 | ToUniqueString("f6"), ToUniqueString("f7"), |
michael@0 | 97 | ToUniqueString("fps"), ToUniqueString("cpsr"), |
michael@0 | 98 | NULL |
michael@0 | 99 | }; |
michael@0 | 100 | |
michael@0 | 101 | // Populate a dictionary with the valid register values in last_frame. |
michael@0 | 102 | CFIFrameInfo::RegisterValueMap<uint32_t> callee_registers; |
michael@0 | 103 | for (int i = 0; register_names[i]; i++) |
michael@0 | 104 | if (last_frame->context_validity & StackFrameARM::RegisterValidFlag(i)) |
michael@0 | 105 | callee_registers.set(register_names[i], last_frame->context.iregs[i]); |
michael@0 | 106 | |
michael@0 | 107 | // Use the STACK CFI data to recover the caller's register values. |
michael@0 | 108 | CFIFrameInfo::RegisterValueMap<uint32_t> caller_registers; |
michael@0 | 109 | if (!cfi_frame_info->FindCallerRegs(callee_registers, *memory_, |
michael@0 | 110 | &caller_registers)) |
michael@0 | 111 | return NULL; |
michael@0 | 112 | |
michael@0 | 113 | // Construct a new stack frame given the values the CFI recovered. |
michael@0 | 114 | scoped_ptr<StackFrameARM> frame(new StackFrameARM()); |
michael@0 | 115 | for (int i = 0; register_names[i]; i++) { |
michael@0 | 116 | bool found = false; |
michael@0 | 117 | uint32_t v = caller_registers.get(&found, register_names[i]); |
michael@0 | 118 | if (found) { |
michael@0 | 119 | // We recovered the value of this register; fill the context with the |
michael@0 | 120 | // value from caller_registers. |
michael@0 | 121 | frame->context_validity |= StackFrameARM::RegisterValidFlag(i); |
michael@0 | 122 | frame->context.iregs[i] = v; |
michael@0 | 123 | } else if (4 <= i && i <= 11 && (last_frame->context_validity & |
michael@0 | 124 | StackFrameARM::RegisterValidFlag(i))) { |
michael@0 | 125 | // If the STACK CFI data doesn't mention some callee-saves register, and |
michael@0 | 126 | // it is valid in the callee, assume the callee has not yet changed it. |
michael@0 | 127 | // Registers r4 through r11 are callee-saves, according to the Procedure |
michael@0 | 128 | // Call Standard for the ARM Architecture, which the Linux ABI follows. |
michael@0 | 129 | frame->context_validity |= StackFrameARM::RegisterValidFlag(i); |
michael@0 | 130 | frame->context.iregs[i] = last_frame->context.iregs[i]; |
michael@0 | 131 | } |
michael@0 | 132 | } |
michael@0 | 133 | // If the CFI doesn't recover the PC explicitly, then use .ra. |
michael@0 | 134 | if (!(frame->context_validity & StackFrameARM::CONTEXT_VALID_PC)) { |
michael@0 | 135 | bool found = false; |
michael@0 | 136 | uint32_t v = caller_registers.get(&found, ustr__ZDra()); |
michael@0 | 137 | if (found) { |
michael@0 | 138 | if (fp_register_ == -1) { |
michael@0 | 139 | frame->context_validity |= StackFrameARM::CONTEXT_VALID_PC; |
michael@0 | 140 | frame->context.iregs[MD_CONTEXT_ARM_REG_PC] = v; |
michael@0 | 141 | } else { |
michael@0 | 142 | // The CFI updated the link register and not the program counter. |
michael@0 | 143 | // Handle getting the program counter from the link register. |
michael@0 | 144 | frame->context_validity |= StackFrameARM::CONTEXT_VALID_PC; |
michael@0 | 145 | frame->context_validity |= StackFrameARM::CONTEXT_VALID_LR; |
michael@0 | 146 | frame->context.iregs[MD_CONTEXT_ARM_REG_LR] = v; |
michael@0 | 147 | frame->context.iregs[MD_CONTEXT_ARM_REG_PC] = |
michael@0 | 148 | last_frame->context.iregs[MD_CONTEXT_ARM_REG_LR]; |
michael@0 | 149 | } |
michael@0 | 150 | } |
michael@0 | 151 | } |
michael@0 | 152 | // If the CFI doesn't recover the SP explicitly, then use .cfa. |
michael@0 | 153 | if (!(frame->context_validity & StackFrameARM::CONTEXT_VALID_SP)) { |
michael@0 | 154 | bool found = false; |
michael@0 | 155 | uint32_t v = caller_registers.get(&found, ustr__ZDcfa()); |
michael@0 | 156 | if (found) { |
michael@0 | 157 | frame->context_validity |= StackFrameARM::CONTEXT_VALID_SP; |
michael@0 | 158 | frame->context.iregs[MD_CONTEXT_ARM_REG_SP] = v; |
michael@0 | 159 | } |
michael@0 | 160 | } |
michael@0 | 161 | |
michael@0 | 162 | // If we didn't recover the PC and the SP, then the frame isn't very useful. |
michael@0 | 163 | static const int essentials = (StackFrameARM::CONTEXT_VALID_SP |
michael@0 | 164 | | StackFrameARM::CONTEXT_VALID_PC); |
michael@0 | 165 | if ((frame->context_validity & essentials) != essentials) |
michael@0 | 166 | return NULL; |
michael@0 | 167 | |
michael@0 | 168 | frame->trust = StackFrame::FRAME_TRUST_CFI; |
michael@0 | 169 | return frame.release(); |
michael@0 | 170 | } |
michael@0 | 171 | |
michael@0 | 172 | StackFrameARM* StackwalkerARM::GetCallerByStackScan( |
michael@0 | 173 | const vector<StackFrame*> &frames) { |
michael@0 | 174 | StackFrameARM* last_frame = static_cast<StackFrameARM*>(frames.back()); |
michael@0 | 175 | uint32_t last_sp = last_frame->context.iregs[MD_CONTEXT_ARM_REG_SP]; |
michael@0 | 176 | uint32_t caller_sp, caller_pc; |
michael@0 | 177 | |
michael@0 | 178 | // When searching for the caller of the context frame, |
michael@0 | 179 | // allow the scanner to look farther down the stack. |
michael@0 | 180 | const int kRASearchWords = frames.size() == 1 ? |
michael@0 | 181 | Stackwalker::kRASearchWords * 4 : |
michael@0 | 182 | Stackwalker::kRASearchWords; |
michael@0 | 183 | |
michael@0 | 184 | if (!ScanForReturnAddress(last_sp, &caller_sp, &caller_pc, |
michael@0 | 185 | kRASearchWords)) { |
michael@0 | 186 | // No plausible return address was found. |
michael@0 | 187 | return NULL; |
michael@0 | 188 | } |
michael@0 | 189 | |
michael@0 | 190 | // ScanForReturnAddress found a reasonable return address. Advance |
michael@0 | 191 | // %sp to the location above the one where the return address was |
michael@0 | 192 | // found. |
michael@0 | 193 | caller_sp += 4; |
michael@0 | 194 | |
michael@0 | 195 | // Create a new stack frame (ownership will be transferred to the caller) |
michael@0 | 196 | // and fill it in. |
michael@0 | 197 | StackFrameARM* frame = new StackFrameARM(); |
michael@0 | 198 | |
michael@0 | 199 | frame->trust = StackFrame::FRAME_TRUST_SCAN; |
michael@0 | 200 | frame->context = last_frame->context; |
michael@0 | 201 | frame->context.iregs[MD_CONTEXT_ARM_REG_PC] = caller_pc; |
michael@0 | 202 | frame->context.iregs[MD_CONTEXT_ARM_REG_SP] = caller_sp; |
michael@0 | 203 | frame->context_validity = StackFrameARM::CONTEXT_VALID_PC | |
michael@0 | 204 | StackFrameARM::CONTEXT_VALID_SP; |
michael@0 | 205 | |
michael@0 | 206 | return frame; |
michael@0 | 207 | } |
michael@0 | 208 | |
michael@0 | 209 | StackFrameARM* StackwalkerARM::GetCallerByFramePointer( |
michael@0 | 210 | const vector<StackFrame*> &frames) { |
michael@0 | 211 | StackFrameARM* last_frame = static_cast<StackFrameARM*>(frames.back()); |
michael@0 | 212 | |
michael@0 | 213 | if (!(last_frame->context_validity & |
michael@0 | 214 | StackFrameARM::RegisterValidFlag(fp_register_))) { |
michael@0 | 215 | return NULL; |
michael@0 | 216 | } |
michael@0 | 217 | |
michael@0 | 218 | uint32_t last_fp = last_frame->context.iregs[fp_register_]; |
michael@0 | 219 | |
michael@0 | 220 | uint32_t caller_fp = 0; |
michael@0 | 221 | if (last_fp && !memory_->GetMemoryAtAddress(last_fp, &caller_fp)) { |
michael@0 | 222 | BPLOG(ERROR) << "Unable to read caller_fp from last_fp: 0x" |
michael@0 | 223 | << std::hex << last_fp; |
michael@0 | 224 | return NULL; |
michael@0 | 225 | } |
michael@0 | 226 | |
michael@0 | 227 | uint32_t caller_lr = 0; |
michael@0 | 228 | if (last_fp && !memory_->GetMemoryAtAddress(last_fp + 4, &caller_lr)) { |
michael@0 | 229 | BPLOG(ERROR) << "Unable to read caller_lr from last_fp + 4: 0x" |
michael@0 | 230 | << std::hex << (last_fp + 4); |
michael@0 | 231 | return NULL; |
michael@0 | 232 | } |
michael@0 | 233 | |
michael@0 | 234 | uint32_t caller_sp = last_fp ? last_fp + 8 : |
michael@0 | 235 | last_frame->context.iregs[MD_CONTEXT_ARM_REG_SP]; |
michael@0 | 236 | |
michael@0 | 237 | // Create a new stack frame (ownership will be transferred to the caller) |
michael@0 | 238 | // and fill it in. |
michael@0 | 239 | StackFrameARM* frame = new StackFrameARM(); |
michael@0 | 240 | |
michael@0 | 241 | frame->trust = StackFrame::FRAME_TRUST_FP; |
michael@0 | 242 | frame->context = last_frame->context; |
michael@0 | 243 | frame->context.iregs[fp_register_] = caller_fp; |
michael@0 | 244 | frame->context.iregs[MD_CONTEXT_ARM_REG_SP] = caller_sp; |
michael@0 | 245 | frame->context.iregs[MD_CONTEXT_ARM_REG_PC] = |
michael@0 | 246 | last_frame->context.iregs[MD_CONTEXT_ARM_REG_LR]; |
michael@0 | 247 | frame->context.iregs[MD_CONTEXT_ARM_REG_LR] = caller_lr; |
michael@0 | 248 | frame->context_validity = StackFrameARM::CONTEXT_VALID_PC | |
michael@0 | 249 | StackFrameARM::CONTEXT_VALID_LR | |
michael@0 | 250 | StackFrameARM::RegisterValidFlag(fp_register_) | |
michael@0 | 251 | StackFrameARM::CONTEXT_VALID_SP; |
michael@0 | 252 | return frame; |
michael@0 | 253 | } |
michael@0 | 254 | |
michael@0 | 255 | StackFrame* StackwalkerARM::GetCallerFrame(const CallStack* stack, |
michael@0 | 256 | bool stack_scan_allowed) { |
michael@0 | 257 | if (!memory_ || !stack) { |
michael@0 | 258 | BPLOG(ERROR) << "Can't get caller frame without memory or stack"; |
michael@0 | 259 | return NULL; |
michael@0 | 260 | } |
michael@0 | 261 | |
michael@0 | 262 | const vector<StackFrame*> &frames = *stack->frames(); |
michael@0 | 263 | StackFrameARM* last_frame = static_cast<StackFrameARM*>(frames.back()); |
michael@0 | 264 | scoped_ptr<StackFrameARM> frame; |
michael@0 | 265 | |
michael@0 | 266 | // See if there is DWARF call frame information covering this address. |
michael@0 | 267 | scoped_ptr<CFIFrameInfo> cfi_frame_info( |
michael@0 | 268 | frame_symbolizer_->FindCFIFrameInfo(last_frame)); |
michael@0 | 269 | if (cfi_frame_info.get()) |
michael@0 | 270 | frame.reset(GetCallerByCFIFrameInfo(frames, cfi_frame_info.get())); |
michael@0 | 271 | |
michael@0 | 272 | // If CFI failed, or there wasn't CFI available, fall back |
michael@0 | 273 | // to frame pointer, if this is configured. |
michael@0 | 274 | if (fp_register_ >= 0 && !frame.get()) |
michael@0 | 275 | frame.reset(GetCallerByFramePointer(frames)); |
michael@0 | 276 | |
michael@0 | 277 | // If everuthing failed, fall back to stack scanning. |
michael@0 | 278 | if (stack_scan_allowed && !frame.get()) |
michael@0 | 279 | frame.reset(GetCallerByStackScan(frames)); |
michael@0 | 280 | |
michael@0 | 281 | // If nothing worked, tell the caller. |
michael@0 | 282 | if (!frame.get()) |
michael@0 | 283 | return NULL; |
michael@0 | 284 | |
michael@0 | 285 | |
michael@0 | 286 | // An instruction address of zero marks the end of the stack. |
michael@0 | 287 | if (frame->context.iregs[MD_CONTEXT_ARM_REG_PC] == 0) |
michael@0 | 288 | return NULL; |
michael@0 | 289 | |
michael@0 | 290 | // If the new stack pointer is at a lower address than the old, then |
michael@0 | 291 | // that's clearly incorrect. Treat this as end-of-stack to enforce |
michael@0 | 292 | // progress and avoid infinite loops. |
michael@0 | 293 | if (frame->context.iregs[MD_CONTEXT_ARM_REG_SP] |
michael@0 | 294 | < last_frame->context.iregs[MD_CONTEXT_ARM_REG_SP]) |
michael@0 | 295 | return NULL; |
michael@0 | 296 | |
michael@0 | 297 | // The new frame's context's PC is the return address, which is one |
michael@0 | 298 | // instruction past the instruction that caused us to arrive at the |
michael@0 | 299 | // callee. Set new_frame->instruction to one less than the PC. This won't |
michael@0 | 300 | // reference the beginning of the call instruction, but it's at least |
michael@0 | 301 | // within it, which is sufficient to get the source line information to |
michael@0 | 302 | // match up with the line that contains the function call. Callers that |
michael@0 | 303 | // require the exact return address value may access |
michael@0 | 304 | // frame->context.iregs[MD_CONTEXT_ARM_REG_PC]. |
michael@0 | 305 | frame->instruction = frame->context.iregs[MD_CONTEXT_ARM_REG_PC] - 2; |
michael@0 | 306 | |
michael@0 | 307 | return frame.release(); |
michael@0 | 308 | } |
michael@0 | 309 | |
michael@0 | 310 | |
michael@0 | 311 | } // namespace google_breakpad |