aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authormark@chromium.org <mark@chromium.org@4c0a9323-5329-0410-9bdc-e9ce6186880e>2012-02-23 22:56:53 +0000
committermark@chromium.org <mark@chromium.org@4c0a9323-5329-0410-9bdc-e9ce6186880e>2012-02-23 22:56:53 +0000
commit84a55c5a722c26304498b3fc2546a98cbc30a2e0 (patch)
treefa1591b068b31d17ed9b69d7196b5ce3be4f1acf /src
parentHandle program strings with the assignment operator smashed against the next (diff)
downloadbreakpad-84a55c5a722c26304498b3fc2546a98cbc30a2e0.tar.xz
Support for .raSearch in the x86 stackwalker
Patch by Benjamin Smedberg <bsmedberg@gmail.com> git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@927 4c0a9323-5329-0410-9bdc-e9ce6186880e
Diffstat (limited to 'src')
-rw-r--r--src/google_breakpad/processor/stackwalker.h15
-rw-r--r--src/processor/stackwalker_x86.cc19
-rw-r--r--src/processor/stackwalker_x86_unittest.cc61
3 files changed, 88 insertions, 7 deletions
diff --git a/src/google_breakpad/processor/stackwalker.h b/src/google_breakpad/processor/stackwalker.h
index 6822f16a..614e31b5 100644
--- a/src/google_breakpad/processor/stackwalker.h
+++ b/src/google_breakpad/processor/stackwalker.h
@@ -108,6 +108,15 @@ class Stackwalker {
// Returns false otherwise.
bool InstructionAddressSeemsValid(u_int64_t address);
+ template<typename InstructionType>
+ bool ScanForReturnAddress(InstructionType location_start,
+ InstructionType *location_found,
+ InstructionType *ip_found) {
+ const int kRASearchWords = 30;
+ return ScanForReturnAddress(location_start, location_found, ip_found,
+ kRASearchWords);
+ }
+
// Scan the stack starting at location_start, looking for an address
// that looks like a valid instruction pointer. Addresses must
// 1) be contained in the current stack memory
@@ -120,10 +129,10 @@ class Stackwalker {
template<typename InstructionType>
bool ScanForReturnAddress(InstructionType location_start,
InstructionType *location_found,
- InstructionType *ip_found) {
- const int kRASearchWords = 30;
+ InstructionType *ip_found,
+ int searchwords) {
for (InstructionType location = location_start;
- location <= location_start + kRASearchWords * sizeof(InstructionType);
+ location <= location_start + searchwords * sizeof(InstructionType);
location += sizeof(InstructionType)) {
InstructionType ip;
if (!memory_->GetMemoryAtAddress(location, &ip))
diff --git a/src/processor/stackwalker_x86.cc b/src/processor/stackwalker_x86.cc
index 2ee37bfb..3c35b082 100644
--- a/src/processor/stackwalker_x86.cc
+++ b/src/processor/stackwalker_x86.cc
@@ -203,10 +203,21 @@ StackFrameX86 *StackwalkerX86::GetCallerByWindowsFrameInfo(
dictionary[".cbCalleeParams"] = last_frame_callee_parameter_size;
dictionary[".cbSavedRegs"] = last_frame_info->saved_register_size;
dictionary[".cbLocals"] = last_frame_info->local_size;
- dictionary[".raSearchStart"] = last_frame->context.esp +
- last_frame_callee_parameter_size +
- last_frame_info->local_size +
- last_frame_info->saved_register_size;
+
+ u_int32_t raSearchStart = last_frame->context.esp +
+ last_frame_callee_parameter_size +
+ last_frame_info->local_size +
+ last_frame_info->saved_register_size;
+ u_int32_t found; // dummy value
+ // Scan up to three words above the calculated search value, in case
+ // the stack was aligned to a quadword boundary.
+ ScanForReturnAddress(raSearchStart, &raSearchStart, &found, 3);
+
+ // The difference between raSearch and raSearchStart is unknown,
+ // but making them the same seems to work well in practice.
+ dictionary[".raSearchStart"] = raSearchStart;
+ dictionary[".raSearch"] = raSearchStart;
+
dictionary[".cbParams"] = last_frame_info->parameter_size;
// Decide what type of program string to use. The program string is in
diff --git a/src/processor/stackwalker_x86_unittest.cc b/src/processor/stackwalker_x86_unittest.cc
index aa6b6310..04d264bd 100644
--- a/src/processor/stackwalker_x86_unittest.cc
+++ b/src/processor/stackwalker_x86_unittest.cc
@@ -400,6 +400,67 @@ TEST_F(GetCallerFrame, WindowsFrameData) {
}
// Use Windows frame data (a "STACK WIN 4" record, from a
+// FrameTypeFrameData DIA record) to walk a stack frame where the stack
+// is aligned and we must search
+TEST_F(GetCallerFrame, WindowsFrameDataAligned) {
+ SetModuleSymbols(&module1,
+ "STACK WIN 4 aa85 176 0 0 4 4 8 0 1"
+ " $T1 .raSearch ="
+ " $T0 $T1 4 - 8 @ ="
+ " $ebp $T1 4 - ^ ="
+ " $eip $T1 ^ ="
+ " $esp $T1 4 + =");
+ Label frame1_esp, frame1_ebp;
+ stack_section.start() = 0x80000000;
+ stack_section
+ // frame 0
+ .D32(0x0ffa0ffa) // unused saved register
+ .D32(0xdeaddead) // locals
+ .D32(0xbeefbeef)
+ .D32(0) // 8-byte alignment
+ .D32(frame1_ebp)
+ .D32(0x5000129d) // return address
+ // frame 1
+ .Mark(&frame1_esp)
+ .D32(0x1) // parameter
+ .Mark(&frame1_ebp)
+ .D32(0) // saved %ebp (stack end)
+ .D32(0); // saved %eip (stack end)
+
+ RegionFromSection();
+ raw_context.eip = 0x4000aa85;
+ raw_context.esp = stack_section.start().Value();
+ raw_context.ebp = 0xf052c1de; // should not be needed to walk frame
+
+ StackwalkerX86 walker(&system_info, &raw_context, &stack_region, &modules,
+ &supplier, &resolver);
+ ASSERT_TRUE(walker.Walk(&call_stack));
+ frames = call_stack.frames();
+ ASSERT_EQ(2U, frames->size());
+
+ StackFrameX86 *frame0 = static_cast<StackFrameX86 *>(frames->at(0));
+ EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust);
+ ASSERT_EQ(StackFrameX86::CONTEXT_VALID_ALL, frame0->context_validity);
+ EXPECT_EQ(0x4000aa85U, frame0->instruction);
+ EXPECT_EQ(0x4000aa85U, frame0->context.eip);
+ EXPECT_EQ(stack_section.start().Value(), frame0->context.esp);
+ EXPECT_EQ(0xf052c1deU, frame0->context.ebp);
+ EXPECT_TRUE(frame0->windows_frame_info != NULL);
+
+ StackFrameX86 *frame1 = static_cast<StackFrameX86 *>(frames->at(1));
+ EXPECT_EQ(StackFrame::FRAME_TRUST_CFI, frame1->trust);
+ ASSERT_EQ((StackFrameX86::CONTEXT_VALID_EIP
+ | StackFrameX86::CONTEXT_VALID_ESP
+ | StackFrameX86::CONTEXT_VALID_EBP),
+ frame1->context_validity);
+ EXPECT_EQ(0x5000129dU, frame1->instruction + 1);
+ EXPECT_EQ(0x5000129dU, frame1->context.eip);
+ EXPECT_EQ(frame1_esp.Value(), frame1->context.esp);
+ EXPECT_EQ(frame1_ebp.Value(), frame1->context.ebp);
+ EXPECT_EQ(NULL, frame1->windows_frame_info);
+}
+
+// Use Windows frame data (a "STACK WIN 4" record, from a
// FrameTypeFrameData DIA record) to walk a frame, and depend on the
// parameter size from the callee as well.
TEST_F(GetCallerFrame, WindowsFrameDataParameterSize) {