mirror of
https://github.com/yuzu-emu/breakpad.git
synced 2024-11-28 05:14:14 +01:00
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
This commit is contained in:
parent
26c31918f7
commit
84a55c5a72
@ -108,6 +108,15 @@ class Stackwalker {
|
|||||||
// Returns false otherwise.
|
// Returns false otherwise.
|
||||||
bool InstructionAddressSeemsValid(u_int64_t address);
|
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
|
// Scan the stack starting at location_start, looking for an address
|
||||||
// that looks like a valid instruction pointer. Addresses must
|
// that looks like a valid instruction pointer. Addresses must
|
||||||
// 1) be contained in the current stack memory
|
// 1) be contained in the current stack memory
|
||||||
@ -120,10 +129,10 @@ class Stackwalker {
|
|||||||
template<typename InstructionType>
|
template<typename InstructionType>
|
||||||
bool ScanForReturnAddress(InstructionType location_start,
|
bool ScanForReturnAddress(InstructionType location_start,
|
||||||
InstructionType *location_found,
|
InstructionType *location_found,
|
||||||
InstructionType *ip_found) {
|
InstructionType *ip_found,
|
||||||
const int kRASearchWords = 30;
|
int searchwords) {
|
||||||
for (InstructionType location = location_start;
|
for (InstructionType location = location_start;
|
||||||
location <= location_start + kRASearchWords * sizeof(InstructionType);
|
location <= location_start + searchwords * sizeof(InstructionType);
|
||||||
location += sizeof(InstructionType)) {
|
location += sizeof(InstructionType)) {
|
||||||
InstructionType ip;
|
InstructionType ip;
|
||||||
if (!memory_->GetMemoryAtAddress(location, &ip))
|
if (!memory_->GetMemoryAtAddress(location, &ip))
|
||||||
|
@ -203,10 +203,21 @@ StackFrameX86 *StackwalkerX86::GetCallerByWindowsFrameInfo(
|
|||||||
dictionary[".cbCalleeParams"] = last_frame_callee_parameter_size;
|
dictionary[".cbCalleeParams"] = last_frame_callee_parameter_size;
|
||||||
dictionary[".cbSavedRegs"] = last_frame_info->saved_register_size;
|
dictionary[".cbSavedRegs"] = last_frame_info->saved_register_size;
|
||||||
dictionary[".cbLocals"] = last_frame_info->local_size;
|
dictionary[".cbLocals"] = last_frame_info->local_size;
|
||||||
dictionary[".raSearchStart"] = last_frame->context.esp +
|
|
||||||
last_frame_callee_parameter_size +
|
u_int32_t raSearchStart = last_frame->context.esp +
|
||||||
last_frame_info->local_size +
|
last_frame_callee_parameter_size +
|
||||||
last_frame_info->saved_register_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;
|
dictionary[".cbParams"] = last_frame_info->parameter_size;
|
||||||
|
|
||||||
// Decide what type of program string to use. The program string is in
|
// Decide what type of program string to use. The program string is in
|
||||||
|
@ -399,6 +399,67 @@ TEST_F(GetCallerFrame, WindowsFrameData) {
|
|||||||
EXPECT_EQ(NULL, frame1->windows_frame_info);
|
EXPECT_EQ(NULL, frame1->windows_frame_info);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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
|
// Use Windows frame data (a "STACK WIN 4" record, from a
|
||||||
// FrameTypeFrameData DIA record) to walk a frame, and depend on the
|
// FrameTypeFrameData DIA record) to walk a frame, and depend on the
|
||||||
// parameter size from the callee as well.
|
// parameter size from the callee as well.
|
||||||
|
Loading…
Reference in New Issue
Block a user