PageRenderTime 27ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 1ms

/thirdparty/breakpad/processor/stackwalker_amd64.cc

http://github.com/tomahawk-player/tomahawk
C++ | 243 lines | 141 code | 32 blank | 70 comment | 20 complexity | 1b9dec87bfb5a34e3160c65d7905d7ad MD5 | raw file
Possible License(s): LGPL-2.1, BSD-3-Clause, GPL-3.0, GPL-2.0
  1. // Copyright (c) 2010 Google Inc.
  2. // All rights reserved.
  3. //
  4. // Redistribution and use in source and binary forms, with or without
  5. // modification, are permitted provided that the following conditions are
  6. // met:
  7. //
  8. // * Redistributions of source code must retain the above copyright
  9. // notice, this list of conditions and the following disclaimer.
  10. // * Redistributions in binary form must reproduce the above
  11. // copyright notice, this list of conditions and the following disclaimer
  12. // in the documentation and/or other materials provided with the
  13. // distribution.
  14. // * Neither the name of Google Inc. nor the names of its
  15. // contributors may be used to endorse or promote products derived from
  16. // this software without specific prior written permission.
  17. //
  18. // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  19. // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  20. // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  21. // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  22. // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  23. // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  24. // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  25. // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  26. // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  27. // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  28. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  29. // stackwalker_amd64.cc: amd64-specific stackwalker.
  30. //
  31. // See stackwalker_amd64.h for documentation.
  32. //
  33. // Author: Mark Mentovai, Ted Mielczarek
  34. #include "google_breakpad/processor/call_stack.h"
  35. #include "google_breakpad/processor/memory_region.h"
  36. #include "google_breakpad/processor/source_line_resolver_interface.h"
  37. #include "google_breakpad/processor/stack_frame_cpu.h"
  38. #include "processor/cfi_frame_info.h"
  39. #include "processor/logging.h"
  40. #include "processor/scoped_ptr.h"
  41. #include "processor/stackwalker_amd64.h"
  42. namespace google_breakpad {
  43. const StackwalkerAMD64::CFIWalker::RegisterSet
  44. StackwalkerAMD64::cfi_register_map_[] = {
  45. // It may seem like $rip and $rsp are callee-saves, because the callee is
  46. // responsible for having them restored upon return. But the callee_saves
  47. // flags here really means that the walker should assume they're
  48. // unchanged if the CFI doesn't mention them --- clearly wrong for $rip
  49. // and $rsp.
  50. { "$rax", NULL, false,
  51. StackFrameAMD64::CONTEXT_VALID_RAX, &MDRawContextAMD64::rax },
  52. { "$rdx", NULL, false,
  53. StackFrameAMD64::CONTEXT_VALID_RDX, &MDRawContextAMD64::rdx },
  54. { "$rcx", NULL, false,
  55. StackFrameAMD64::CONTEXT_VALID_RCX, &MDRawContextAMD64::rcx },
  56. { "$rbx", NULL, true,
  57. StackFrameAMD64::CONTEXT_VALID_RBX, &MDRawContextAMD64::rbx },
  58. { "$rsi", NULL, false,
  59. StackFrameAMD64::CONTEXT_VALID_RSI, &MDRawContextAMD64::rsi },
  60. { "$rdi", NULL, false,
  61. StackFrameAMD64::CONTEXT_VALID_RDI, &MDRawContextAMD64::rdi },
  62. { "$rbp", NULL, true,
  63. StackFrameAMD64::CONTEXT_VALID_RBP, &MDRawContextAMD64::rbp },
  64. { "$rsp", ".cfa", false,
  65. StackFrameAMD64::CONTEXT_VALID_RSP, &MDRawContextAMD64::rsp },
  66. { "$r8", NULL, false,
  67. StackFrameAMD64::CONTEXT_VALID_R8, &MDRawContextAMD64::r8 },
  68. { "$r9", NULL, false,
  69. StackFrameAMD64::CONTEXT_VALID_R9, &MDRawContextAMD64::r9 },
  70. { "$r10", NULL, false,
  71. StackFrameAMD64::CONTEXT_VALID_R10, &MDRawContextAMD64::r10 },
  72. { "$r11", NULL, false,
  73. StackFrameAMD64::CONTEXT_VALID_R11, &MDRawContextAMD64::r11 },
  74. { "$r12", NULL, true,
  75. StackFrameAMD64::CONTEXT_VALID_R12, &MDRawContextAMD64::r12 },
  76. { "$r13", NULL, true,
  77. StackFrameAMD64::CONTEXT_VALID_R13, &MDRawContextAMD64::r13 },
  78. { "$r14", NULL, true,
  79. StackFrameAMD64::CONTEXT_VALID_R14, &MDRawContextAMD64::r14 },
  80. { "$r15", NULL, true,
  81. StackFrameAMD64::CONTEXT_VALID_R15, &MDRawContextAMD64::r15 },
  82. { "$rip", ".ra", false,
  83. StackFrameAMD64::CONTEXT_VALID_RIP, &MDRawContextAMD64::rip },
  84. };
  85. StackwalkerAMD64::StackwalkerAMD64(const SystemInfo *system_info,
  86. const MDRawContextAMD64 *context,
  87. MemoryRegion *memory,
  88. const CodeModules *modules,
  89. SymbolSupplier *supplier,
  90. SourceLineResolverInterface *resolver)
  91. : Stackwalker(system_info, memory, modules, supplier, resolver),
  92. context_(context),
  93. cfi_walker_(cfi_register_map_,
  94. (sizeof(cfi_register_map_) / sizeof(cfi_register_map_[0]))) {
  95. }
  96. StackFrame* StackwalkerAMD64::GetContextFrame() {
  97. if (!context_ || !memory_) {
  98. BPLOG(ERROR) << "Can't get context frame without context or memory";
  99. return NULL;
  100. }
  101. StackFrameAMD64 *frame = new StackFrameAMD64();
  102. // The instruction pointer is stored directly in a register, so pull it
  103. // straight out of the CPU context structure.
  104. frame->context = *context_;
  105. frame->context_validity = StackFrameAMD64::CONTEXT_VALID_ALL;
  106. frame->trust = StackFrame::FRAME_TRUST_CONTEXT;
  107. frame->instruction = frame->context.rip;
  108. return frame;
  109. }
  110. StackFrameAMD64 *StackwalkerAMD64::GetCallerByCFIFrameInfo(
  111. const vector<StackFrame *> &frames,
  112. CFIFrameInfo *cfi_frame_info) {
  113. StackFrameAMD64 *last_frame = static_cast<StackFrameAMD64*>(frames.back());
  114. scoped_ptr<StackFrameAMD64> frame(new StackFrameAMD64());
  115. if (!cfi_walker_
  116. .FindCallerRegisters(*memory_, *cfi_frame_info,
  117. last_frame->context, last_frame->context_validity,
  118. &frame->context, &frame->context_validity))
  119. return NULL;
  120. // Make sure we recovered all the essentials.
  121. static const int essentials = (StackFrameAMD64::CONTEXT_VALID_RIP
  122. | StackFrameAMD64::CONTEXT_VALID_RSP);
  123. if ((frame->context_validity & essentials) != essentials)
  124. return NULL;
  125. frame->trust = StackFrame::FRAME_TRUST_CFI;
  126. return frame.release();
  127. }
  128. StackFrameAMD64 *StackwalkerAMD64::GetCallerByStackScan(
  129. const vector<StackFrame *> &frames) {
  130. StackFrameAMD64 *last_frame = static_cast<StackFrameAMD64 *>(frames.back());
  131. u_int64_t last_rsp = last_frame->context.rsp;
  132. u_int64_t caller_rip_address, caller_rip;
  133. if (!ScanForReturnAddress(last_rsp, &caller_rip_address, &caller_rip)) {
  134. // No plausible return address was found.
  135. return NULL;
  136. }
  137. // Create a new stack frame (ownership will be transferred to the caller)
  138. // and fill it in.
  139. StackFrameAMD64 *frame = new StackFrameAMD64();
  140. frame->trust = StackFrame::FRAME_TRUST_SCAN;
  141. frame->context = last_frame->context;
  142. frame->context.rip = caller_rip;
  143. // The caller's %rsp is directly underneath the return address pushed by
  144. // the call.
  145. frame->context.rsp = caller_rip_address + 8;
  146. frame->context_validity = StackFrameAMD64::CONTEXT_VALID_RIP |
  147. StackFrameAMD64::CONTEXT_VALID_RSP;
  148. // Other unwinders give up if they don't have an %rbp value, so see if we
  149. // can pass some plausible value on.
  150. if (last_frame->context_validity & StackFrameAMD64::CONTEXT_VALID_RBP) {
  151. // Functions typically push their caller's %rbp immediately upon entry,
  152. // and then set %rbp to point to that. So if the callee's %rbp is
  153. // pointing to the first word below the alleged return address, presume
  154. // that the caller's %rbp is saved there.
  155. if (caller_rip_address - 8 == last_frame->context.rbp) {
  156. u_int64_t caller_rbp = 0;
  157. if (memory_->GetMemoryAtAddress(last_frame->context.rbp, &caller_rbp) &&
  158. caller_rbp > caller_rip_address) {
  159. frame->context.rbp = caller_rbp;
  160. frame->context_validity |= StackFrameAMD64::CONTEXT_VALID_RBP;
  161. }
  162. } else if (last_frame->context.rbp >= caller_rip_address + 8) {
  163. // If the callee's %rbp is plausible as a value for the caller's
  164. // %rbp, presume that the callee left it unchanged.
  165. frame->context.rbp = last_frame->context.rbp;
  166. frame->context_validity |= StackFrameAMD64::CONTEXT_VALID_RBP;
  167. }
  168. }
  169. return frame;
  170. }
  171. StackFrame* StackwalkerAMD64::GetCallerFrame(const CallStack *stack) {
  172. if (!memory_ || !stack) {
  173. BPLOG(ERROR) << "Can't get caller frame without memory or stack";
  174. return NULL;
  175. }
  176. const vector<StackFrame *> &frames = *stack->frames();
  177. StackFrameAMD64 *last_frame = static_cast<StackFrameAMD64 *>(frames.back());
  178. scoped_ptr<StackFrameAMD64> new_frame;
  179. // If we have DWARF CFI information, use it.
  180. scoped_ptr<CFIFrameInfo> cfi_frame_info(
  181. resolver_ ? resolver_->FindCFIFrameInfo(last_frame) : NULL);
  182. if (cfi_frame_info.get())
  183. new_frame.reset(GetCallerByCFIFrameInfo(frames, cfi_frame_info.get()));
  184. // If CFI failed, or there wasn't CFI available, fall back
  185. // to stack scanning.
  186. if (!new_frame.get()) {
  187. new_frame.reset(GetCallerByStackScan(frames));
  188. }
  189. // If nothing worked, tell the caller.
  190. if (!new_frame.get())
  191. return NULL;
  192. // Treat an instruction address of 0 as end-of-stack.
  193. if (new_frame->context.rip == 0)
  194. return NULL;
  195. // If the new stack pointer is at a lower address than the old, then
  196. // that's clearly incorrect. Treat this as end-of-stack to enforce
  197. // progress and avoid infinite loops.
  198. if (new_frame->context.rsp <= last_frame->context.rsp)
  199. return NULL;
  200. // new_frame->context.rip is the return address, which is one instruction
  201. // past the CALL that caused us to arrive at the callee. Set
  202. // new_frame->instruction to one less than that. This won't reference the
  203. // beginning of the CALL instruction, but it's guaranteed to be within
  204. // the CALL, which is sufficient to get the source line information to
  205. // match up with the line that contains a function call. Callers that
  206. // require the exact return address value may access the context.rip
  207. // field of StackFrameAMD64.
  208. new_frame->instruction = new_frame->context.rip - 1;
  209. return new_frame.release();
  210. }
  211. } // namespace google_breakpad