| OLD | NEW |
| 1 // Copyright (c) 2010 Google Inc. | 1 // Copyright (c) 2010 Google Inc. |
| 2 // All rights reserved. | 2 // All rights reserved. |
| 3 // | 3 // |
| 4 // Redistribution and use in source and binary forms, with or without | 4 // Redistribution and use in source and binary forms, with or without |
| 5 // modification, are permitted provided that the following conditions are | 5 // modification, are permitted provided that the following conditions are |
| 6 // met: | 6 // met: |
| 7 // | 7 // |
| 8 // * Redistributions of source code must retain the above copyright | 8 // * Redistributions of source code must retain the above copyright |
| 9 // notice, this list of conditions and the following disclaimer. | 9 // notice, this list of conditions and the following disclaimer. |
| 10 // * Redistributions in binary form must reproduce the above | 10 // * Redistributions in binary form must reproduce the above |
| (...skipping 146 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 157 // If the new stack pointer is at a lower address than the old, then | 157 // If the new stack pointer is at a lower address than the old, then |
| 158 // that's clearly incorrect. Treat this as end-of-stack to enforce | 158 // that's clearly incorrect. Treat this as end-of-stack to enforce |
| 159 // progress and avoid infinite loops. | 159 // progress and avoid infinite loops. |
| 160 if (caller_rsp < callee_rsp) { | 160 if (caller_rsp < callee_rsp) { |
| 161 return true; | 161 return true; |
| 162 } | 162 } |
| 163 | 163 |
| 164 return false; | 164 return false; |
| 165 } | 165 } |
| 166 | 166 |
| 167 // Returns true if `ptr` is not in x86-64 canonical form. |
| 168 // https://en.wikipedia.org/wiki/X86-64#Virtual_address_space_details |
| 169 static bool is_non_canonical(uint64_t ptr) { |
| 170 return ptr > 0x7FFFFFFFFFFF && ptr < 0xFFFF800000000000; |
| 171 } |
| 172 |
| 167 StackFrameAMD64* StackwalkerAMD64::GetCallerByFramePointerRecovery( | 173 StackFrameAMD64* StackwalkerAMD64::GetCallerByFramePointerRecovery( |
| 168 const vector<StackFrame*>& frames) { | 174 const vector<StackFrame*>& frames) { |
| 169 StackFrameAMD64* last_frame = static_cast<StackFrameAMD64*>(frames.back()); | 175 StackFrameAMD64* last_frame = static_cast<StackFrameAMD64*>(frames.back()); |
| 170 uint64_t last_rsp = last_frame->context.rsp; | 176 uint64_t last_rsp = last_frame->context.rsp; |
| 171 uint64_t last_rbp = last_frame->context.rbp; | 177 uint64_t last_rbp = last_frame->context.rbp; |
| 172 | 178 |
| 173 // Assume the presence of a frame pointer. This is not mandated by the | 179 // Assume the presence of a frame pointer. This is not mandated by the |
| 174 // AMD64 ABI, c.f. section 3.2.2 footnote 7, though it is typical for | 180 // AMD64 ABI, c.f. section 3.2.2 footnote 7, though it is typical for |
| 175 // compilers to still preserve the frame pointer and not treat %rbp as a | 181 // compilers to still preserve the frame pointer and not treat %rbp as a |
| 176 // general purpose register. | 182 // general purpose register. |
| 177 // | 183 // |
| 178 // With this assumption, the CALL instruction pushes the return address | 184 // With this assumption, the CALL instruction pushes the return address |
| 179 // onto the stack and sets %rip to the procedure to enter. The procedure | 185 // onto the stack and sets %rip to the procedure to enter. The procedure |
| 180 // then establishes the stack frame with a prologue that PUSHes the current | 186 // then establishes the stack frame with a prologue that PUSHes the current |
| 181 // %rbp onto the stack, MOVes the current %rsp to %rbp, and then allocates | 187 // %rbp onto the stack, MOVes the current %rsp to %rbp, and then allocates |
| 182 // space for any local variables. Using this procedure linking information, | 188 // space for any local variables. Using this procedure linking information, |
| 183 // it is possible to locate frame information for the callee: | 189 // it is possible to locate frame information for the callee: |
| 184 // | 190 // |
| 185 // %caller_rsp = *(%callee_rbp + 16) | 191 // %caller_rsp = *(%callee_rbp + 16) |
| 186 // %caller_rip = *(%callee_rbp + 8) | 192 // %caller_rip = *(%callee_rbp + 8) |
| 187 // %caller_rbp = *(%callee_rbp) | 193 // %caller_rbp = *(%callee_rbp) |
| 188 | 194 |
| 195 // If rbp is not 8-byte aligned it can't be a frame pointer. |
| 196 if (last_rbp % 8 != 0) { |
| 197 return NULL; |
| 198 } |
| 199 |
| 189 uint64_t caller_rip, caller_rbp; | 200 uint64_t caller_rip, caller_rbp; |
| 190 if (memory_->GetMemoryAtAddress(last_rbp + 8, &caller_rip) && | 201 if (memory_->GetMemoryAtAddress(last_rbp + 8, &caller_rip) && |
| 191 memory_->GetMemoryAtAddress(last_rbp, &caller_rbp)) { | 202 memory_->GetMemoryAtAddress(last_rbp, &caller_rbp)) { |
| 192 uint64_t caller_rsp = last_rbp + 16; | 203 uint64_t caller_rsp = last_rbp + 16; |
| 193 | 204 |
| 205 // If the recovered rip is not a canonical address it can't be |
| 206 // the return address, so rbp must not have been a frame pointer. |
| 207 if (is_non_canonical(caller_rip)) { |
| 208 return NULL; |
| 209 } |
| 210 |
| 194 // Simple sanity check that the stack is growing downwards as expected. | 211 // Simple sanity check that the stack is growing downwards as expected. |
| 195 if (IsEndOfStack(caller_rip, caller_rsp, last_rsp) || | 212 if (IsEndOfStack(caller_rip, caller_rsp, last_rsp) || |
| 196 caller_rbp < last_rbp) { | 213 caller_rbp < last_rbp) { |
| 197 // Reached end-of-stack or stack is not growing downwards. | 214 // Reached end-of-stack or stack is not growing downwards. |
| 198 return NULL; | 215 return NULL; |
| 199 } | 216 } |
| 200 | 217 |
| 201 StackFrameAMD64* frame = new StackFrameAMD64(); | 218 StackFrameAMD64* frame = new StackFrameAMD64(); |
| 202 frame->trust = StackFrame::FRAME_TRUST_FP; | 219 frame->trust = StackFrame::FRAME_TRUST_FP; |
| 203 frame->context = last_frame->context; | 220 frame->context = last_frame->context; |
| (...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 314 // after the CALL that caused us to arrive at the callee. Set | 331 // after the CALL that caused us to arrive at the callee. Set |
| 315 // new_frame->instruction to one less than that, so it points within the | 332 // new_frame->instruction to one less than that, so it points within the |
| 316 // CALL instruction. See StackFrame::instruction for details, and | 333 // CALL instruction. See StackFrame::instruction for details, and |
| 317 // StackFrameAMD64::ReturnAddress. | 334 // StackFrameAMD64::ReturnAddress. |
| 318 new_frame->instruction = new_frame->context.rip - 1; | 335 new_frame->instruction = new_frame->context.rip - 1; |
| 319 | 336 |
| 320 return new_frame.release(); | 337 return new_frame.release(); |
| 321 } | 338 } |
| 322 | 339 |
| 323 } // namespace google_breakpad | 340 } // namespace google_breakpad |
| OLD | NEW |