aboutsummaryrefslogtreecommitdiff
path: root/src/processor/stackwalker_x86.cc
diff options
context:
space:
mode:
authorivan.penkov@gmail.com <ivan.penkov@gmail.com@4c0a9323-5329-0410-9bdc-e9ce6186880e>2012-11-02 21:43:58 +0000
committerivan.penkov@gmail.com <ivan.penkov@gmail.com@4c0a9323-5329-0410-9bdc-e9ce6186880e>2012-11-02 21:43:58 +0000
commit66a21aad61b57553b933bb6c0f9c8efa96df5612 (patch)
tree05f68eef6a20a53761b0e29149c6f7b91fb5c514 /src/processor/stackwalker_x86.cc
parent6b91f41a7c22410db9ebc81a369f5fd84cd31f8e (diff)
downloadgoogle-breakpad-66a21aad61b57553b933bb6c0f9c8efa96df5612.tar.gz
Wrong %ebp after skipping a frame for which the instruction pointer is not in a known module.
http://breakpad.appspot.com/494002/ git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@1076 4c0a9323-5329-0410-9bdc-e9ce6186880e
Diffstat (limited to 'src/processor/stackwalker_x86.cc')
-rw-r--r--src/processor/stackwalker_x86.cc60
1 files changed, 35 insertions, 25 deletions
diff --git a/src/processor/stackwalker_x86.cc b/src/processor/stackwalker_x86.cc
index 4ee5beed..6a4569a2 100644
--- a/src/processor/stackwalker_x86.cc
+++ b/src/processor/stackwalker_x86.cc
@@ -386,31 +386,41 @@ StackFrameX86* StackwalkerX86::GetCallerByWindowsFrameInfo(
}
}
- // When trying to recover the previous value of the frame pointer (%ebp),
- // start looking at the lowest possible address in the saved-register
- // area, and look at the entire saved register area, increased by the
- // size of |offset| to account for additional data that may be on the
- // stack. The scan is performed from the highest possible address to
- // the lowest, because we expect that the function's prolog would have
- // saved %ebp early.
- u_int32_t ebp = dictionary["$ebp"];
- u_int32_t value; // throwaway variable to check pointer validity
- if (recover_ebp && !memory_->GetMemoryAtAddress(ebp, &value)) {
- int fp_search_bytes = last_frame_info->saved_register_size + offset;
- u_int32_t location_end = last_frame->context.esp +
- last_frame_callee_parameter_size;
-
- for (u_int32_t location = location_end + fp_search_bytes;
- location >= location_end;
- location -= 4) {
- if (!memory_->GetMemoryAtAddress(location, &ebp))
- break;
-
- if (memory_->GetMemoryAtAddress(ebp, &value)) {
- // The candidate value is a pointer to the same memory region
- // (the stack). Prefer it as a recovered %ebp result.
- dictionary["$ebp"] = ebp;
- break;
+ if (recover_ebp) {
+ // When trying to recover the previous value of the frame pointer (%ebp),
+ // start looking at the lowest possible address in the saved-register
+ // area, and look at the entire saved register area, increased by the
+ // size of |offset| to account for additional data that may be on the
+ // stack. The scan is performed from the highest possible address to
+ // the lowest, because the expectation is that the function's prolog
+ // would have saved %ebp early.
+ u_int32_t ebp = dictionary["$ebp"];
+
+ // When a scan for return address is used, it is possible to skip one or
+ // more frames (when return address is not in a known module). One
+ // indication for skipped frames is when the value of %ebp is lower than
+ // the location of the return address on the stack
+ bool has_skipped_frames =
+ (trust != StackFrame::FRAME_TRUST_CFI && ebp <= raSearchStart + offset);
+
+ u_int32_t value; // throwaway variable to check pointer validity
+ if (has_skipped_frames || !memory_->GetMemoryAtAddress(ebp, &value)) {
+ int fp_search_bytes = last_frame_info->saved_register_size + offset;
+ u_int32_t location_end = last_frame->context.esp +
+ last_frame_callee_parameter_size;
+
+ for (u_int32_t location = location_end + fp_search_bytes;
+ location >= location_end;
+ location -= 4) {
+ if (!memory_->GetMemoryAtAddress(location, &ebp))
+ break;
+
+ if (memory_->GetMemoryAtAddress(ebp, &value)) {
+ // The candidate value is a pointer to the same memory region
+ // (the stack). Prefer it as a recovered %ebp result.
+ dictionary["$ebp"] = ebp;
+ break;
+ }
}
}
}