mirror of
https://github.com/yuzu-emu/breakpad.git
synced 2024-12-23 00:45:35 +00:00
Better identification of context frames.
Since the introduction of inlined frames, it is not sufficient to check the stack trace length (== 1) in order to identify context frames. Updating all location that were depending on this assumption to check for frame trust level instead. Change-Id: I98f966889367c2270c268b8e78b67418c89c50f1 Reviewed-on: https://chromium-review.googlesource.com/c/breakpad/breakpad/+/3499020 Reviewed-by: Mark Mentovai <mark@chromium.org>
This commit is contained in:
parent
42d2475617
commit
c685fe1153
|
@ -223,7 +223,7 @@ StackFrameAMD64* StackwalkerAMD64::GetCallerByFramePointerRecovery(
|
||||||
|
|
||||||
StackFrameAMD64* StackwalkerAMD64::GetCallerBySimulatingReturn(
|
StackFrameAMD64* StackwalkerAMD64::GetCallerBySimulatingReturn(
|
||||||
const vector<StackFrame*>& frames) {
|
const vector<StackFrame*>& frames) {
|
||||||
assert(frames.size() == 1);
|
assert(frames.back()->trust == StackFrame::FRAME_TRUST_CONTEXT);
|
||||||
StackFrameAMD64* last_frame = static_cast<StackFrameAMD64*>(frames.back());
|
StackFrameAMD64* last_frame = static_cast<StackFrameAMD64*>(frames.back());
|
||||||
uint64_t last_rsp = last_frame->context.rsp;
|
uint64_t last_rsp = last_frame->context.rsp;
|
||||||
uint64_t caller_rip_address, caller_rip;
|
uint64_t caller_rip_address, caller_rip;
|
||||||
|
@ -257,7 +257,8 @@ StackFrameAMD64* StackwalkerAMD64::GetCallerByStackScan(
|
||||||
uint64_t caller_rip_address, caller_rip;
|
uint64_t caller_rip_address, caller_rip;
|
||||||
|
|
||||||
if (!ScanForReturnAddress(last_rsp, &caller_rip_address, &caller_rip,
|
if (!ScanForReturnAddress(last_rsp, &caller_rip_address, &caller_rip,
|
||||||
frames.size() == 1 /* is_context_frame */)) {
|
/*is_context_frame=*/last_frame->trust ==
|
||||||
|
StackFrame::FRAME_TRUST_CONTEXT)) {
|
||||||
// No plausible return address was found.
|
// No plausible return address was found.
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -322,7 +323,8 @@ StackFrame* StackwalkerAMD64::GetCallerFrame(const CallStack* stack,
|
||||||
// According to https://reviews.llvm.org/D24748, LLVM doesn't generate unwind
|
// According to https://reviews.llvm.org/D24748, LLVM doesn't generate unwind
|
||||||
// info for such functions. According to MSDN, leaf functions can be unwound
|
// info for such functions. According to MSDN, leaf functions can be unwound
|
||||||
// simply by simulating a return.
|
// simply by simulating a return.
|
||||||
if (!new_frame.get() && stack->frames()->size() == 1 &&
|
if (!new_frame.get() &&
|
||||||
|
last_frame->trust == StackFrame::FRAME_TRUST_CONTEXT &&
|
||||||
system_info_->os_short == "windows") {
|
system_info_->os_short == "windows") {
|
||||||
new_frame.reset(GetCallerBySimulatingReturn(frames));
|
new_frame.reset(GetCallerBySimulatingReturn(frames));
|
||||||
}
|
}
|
||||||
|
@ -356,7 +358,9 @@ StackFrame* StackwalkerAMD64::GetCallerFrame(const CallStack* stack,
|
||||||
|
|
||||||
// Should we terminate the stack walk? (end-of-stack or broken invariant)
|
// Should we terminate the stack walk? (end-of-stack or broken invariant)
|
||||||
if (TerminateWalk(new_frame->context.rip, new_frame->context.rsp,
|
if (TerminateWalk(new_frame->context.rip, new_frame->context.rsp,
|
||||||
last_frame->context.rsp, frames.size() == 1)) {
|
last_frame->context.rsp,
|
||||||
|
/*first_unwind=*/last_frame->trust ==
|
||||||
|
StackFrame::FRAME_TRUST_CONTEXT)) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -168,7 +168,8 @@ StackFrameARM* StackwalkerARM::GetCallerByStackScan(
|
||||||
uint32_t caller_sp, caller_pc;
|
uint32_t caller_sp, caller_pc;
|
||||||
|
|
||||||
if (!ScanForReturnAddress(last_sp, &caller_sp, &caller_pc,
|
if (!ScanForReturnAddress(last_sp, &caller_sp, &caller_pc,
|
||||||
frames.size() == 1 /* is_context_frame */)) {
|
/*is_context_frame=*/last_frame->trust ==
|
||||||
|
StackFrame::FRAME_TRUST_CONTEXT)) {
|
||||||
// No plausible return address was found.
|
// No plausible return address was found.
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -276,7 +277,8 @@ StackFrame* StackwalkerARM::GetCallerFrame(const CallStack* stack,
|
||||||
if (TerminateWalk(frame->context.iregs[MD_CONTEXT_ARM_REG_PC],
|
if (TerminateWalk(frame->context.iregs[MD_CONTEXT_ARM_REG_PC],
|
||||||
frame->context.iregs[MD_CONTEXT_ARM_REG_SP],
|
frame->context.iregs[MD_CONTEXT_ARM_REG_SP],
|
||||||
last_frame->context.iregs[MD_CONTEXT_ARM_REG_SP],
|
last_frame->context.iregs[MD_CONTEXT_ARM_REG_SP],
|
||||||
frames.size() == 1)) {
|
/*first_unwind=*/last_frame->trust ==
|
||||||
|
StackFrame::FRAME_TRUST_CONTEXT)) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -181,7 +181,8 @@ StackFrameARM64* StackwalkerARM64::GetCallerByStackScan(
|
||||||
uint64_t caller_sp, caller_pc;
|
uint64_t caller_sp, caller_pc;
|
||||||
|
|
||||||
if (!ScanForReturnAddress(last_sp, &caller_sp, &caller_pc,
|
if (!ScanForReturnAddress(last_sp, &caller_sp, &caller_pc,
|
||||||
frames.size() == 1 /* is_context_frame */)) {
|
/*is_context_frame=*/last_frame->trust ==
|
||||||
|
StackFrame::FRAME_TRUST_CONTEXT)) {
|
||||||
// No plausible return address was found.
|
// No plausible return address was found.
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -320,7 +321,8 @@ StackFrame* StackwalkerARM64::GetCallerFrame(const CallStack* stack,
|
||||||
if (TerminateWalk(frame->context.iregs[MD_CONTEXT_ARM64_REG_PC],
|
if (TerminateWalk(frame->context.iregs[MD_CONTEXT_ARM64_REG_PC],
|
||||||
frame->context.iregs[MD_CONTEXT_ARM64_REG_SP],
|
frame->context.iregs[MD_CONTEXT_ARM64_REG_SP],
|
||||||
last_frame->context.iregs[MD_CONTEXT_ARM64_REG_SP],
|
last_frame->context.iregs[MD_CONTEXT_ARM64_REG_SP],
|
||||||
frames.size() == 1)) {
|
/*first_unwind=*/last_frame->trust ==
|
||||||
|
StackFrame::FRAME_TRUST_CONTEXT)) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -276,7 +276,8 @@ StackFrame* StackwalkerMIPS::GetCallerFrame(const CallStack* stack,
|
||||||
if (TerminateWalk(new_frame->context.epc,
|
if (TerminateWalk(new_frame->context.epc,
|
||||||
new_frame->context.iregs[MD_CONTEXT_MIPS_REG_SP],
|
new_frame->context.iregs[MD_CONTEXT_MIPS_REG_SP],
|
||||||
last_frame->context.iregs[MD_CONTEXT_MIPS_REG_SP],
|
last_frame->context.iregs[MD_CONTEXT_MIPS_REG_SP],
|
||||||
frames.size() == 1)) {
|
/*first_unwind=*/last_frame->trust ==
|
||||||
|
StackFrame::FRAME_TRUST_CONTEXT)) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -132,10 +132,9 @@ StackFrame* StackwalkerPPC::GetCallerFrame(const CallStack* stack,
|
||||||
frame->trust = StackFrame::FRAME_TRUST_FP;
|
frame->trust = StackFrame::FRAME_TRUST_FP;
|
||||||
|
|
||||||
// Should we terminate the stack walk? (end-of-stack or broken invariant)
|
// Should we terminate the stack walk? (end-of-stack or broken invariant)
|
||||||
if (TerminateWalk(instruction,
|
if (TerminateWalk(instruction, stack_pointer, last_frame->context.gpr[1],
|
||||||
stack_pointer,
|
/*first_unwind=*/last_frame->trust ==
|
||||||
last_frame->context.gpr[1],
|
StackFrame::FRAME_TRUST_CONTEXT)) {
|
||||||
stack->frames()->size() == 1)) {
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -123,10 +123,9 @@ StackFrame* StackwalkerPPC64::GetCallerFrame(const CallStack* stack,
|
||||||
frame->trust = StackFrame::FRAME_TRUST_FP;
|
frame->trust = StackFrame::FRAME_TRUST_FP;
|
||||||
|
|
||||||
// Should we terminate the stack walk? (end-of-stack or broken invariant)
|
// Should we terminate the stack walk? (end-of-stack or broken invariant)
|
||||||
if (TerminateWalk(instruction,
|
if (TerminateWalk(instruction, stack_pointer, last_frame->context.gpr[1],
|
||||||
stack_pointer,
|
/*is_context_frame=*/last_frame->trust ==
|
||||||
last_frame->context.gpr[1],
|
StackFrame::FRAME_TRUST_CONTEXT)) {
|
||||||
stack->frames()->size() == 1)) {
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -112,10 +112,9 @@ StackFrame* StackwalkerSPARC::GetCallerFrame(const CallStack* stack,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Should we terminate the stack walk? (end-of-stack or broken invariant)
|
// Should we terminate the stack walk? (end-of-stack or broken invariant)
|
||||||
if (TerminateWalk(instruction,
|
if (TerminateWalk(instruction, stack_pointer, last_frame->context.g_r[14],
|
||||||
stack_pointer,
|
/*is_context_frame=*/last_frame->trust ==
|
||||||
last_frame->context.g_r[14],
|
StackFrame::FRAME_TRUST_CONTEXT)) {
|
||||||
stack->frames()->size() == 1)) {
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -394,9 +394,10 @@ StackFrameX86* StackwalkerX86::GetCallerByWindowsFrameInfo(
|
||||||
// frame pointer.
|
// frame pointer.
|
||||||
uint32_t location_start = last_frame->context.esp;
|
uint32_t location_start = last_frame->context.esp;
|
||||||
uint32_t location, eip;
|
uint32_t location, eip;
|
||||||
if (!stack_scan_allowed
|
if (!stack_scan_allowed ||
|
||||||
|| !ScanForReturnAddress(location_start, &location, &eip,
|
!ScanForReturnAddress(location_start, &location, &eip,
|
||||||
frames.size() == 1 /* is_context_frame */)) {
|
/*is_context_frame=*/last_frame->trust ==
|
||||||
|
StackFrame::FRAME_TRUST_CONTEXT)) {
|
||||||
// if we can't find an instruction pointer even with stack scanning,
|
// if we can't find an instruction pointer even with stack scanning,
|
||||||
// give up.
|
// give up.
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -438,9 +439,10 @@ StackFrameX86* StackwalkerX86::GetCallerByWindowsFrameInfo(
|
||||||
// looking one 32-bit word above that location.
|
// looking one 32-bit word above that location.
|
||||||
uint32_t location_start = dictionary[".raSearchStart"] + 4;
|
uint32_t location_start = dictionary[".raSearchStart"] + 4;
|
||||||
uint32_t location;
|
uint32_t location;
|
||||||
if (stack_scan_allowed
|
if (stack_scan_allowed &&
|
||||||
&& ScanForReturnAddress(location_start, &location, &eip,
|
ScanForReturnAddress(location_start, &location, &eip,
|
||||||
frames.size() == 1 /* is_context_frame */)) {
|
/*is_context_frame=*/last_frame->trust ==
|
||||||
|
StackFrame::FRAME_TRUST_CONTEXT)) {
|
||||||
// This is a better return address that what program string
|
// This is a better return address that what program string
|
||||||
// evaluation found. Use it, and set %esp to the location above the
|
// evaluation found. Use it, and set %esp to the location above the
|
||||||
// one where the return address was found.
|
// one where the return address was found.
|
||||||
|
@ -596,9 +598,10 @@ StackFrameX86* StackwalkerX86::GetCallerByEBPAtBase(
|
||||||
// return address. This can happen if last_frame is executing code
|
// return address. This can happen if last_frame is executing code
|
||||||
// for a module for which we don't have symbols, and that module
|
// for a module for which we don't have symbols, and that module
|
||||||
// is compiled without a frame pointer.
|
// is compiled without a frame pointer.
|
||||||
if (!stack_scan_allowed
|
if (!stack_scan_allowed ||
|
||||||
|| !ScanForReturnAddress(last_esp, &caller_esp, &caller_eip,
|
!ScanForReturnAddress(last_esp, &caller_esp, &caller_eip,
|
||||||
frames.size() == 1 /* is_context_frame */)) {
|
/*is_context_frame=*/last_frame->trust ==
|
||||||
|
StackFrame::FRAME_TRUST_CONTEXT)) {
|
||||||
// if we can't find an instruction pointer even with stack scanning,
|
// if we can't find an instruction pointer even with stack scanning,
|
||||||
// give up.
|
// give up.
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -678,10 +681,10 @@ StackFrame* StackwalkerX86::GetCallerFrame(const CallStack* stack,
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
// Should we terminate the stack walk? (end-of-stack or broken invariant)
|
// Should we terminate the stack walk? (end-of-stack or broken invariant)
|
||||||
if (TerminateWalk(new_frame->context.eip,
|
if (TerminateWalk(new_frame->context.eip, new_frame->context.esp,
|
||||||
new_frame->context.esp,
|
|
||||||
last_frame->context.esp,
|
last_frame->context.esp,
|
||||||
frames.size() == 1)) {
|
/*first_unwind=*/last_frame->trust ==
|
||||||
|
StackFrame::FRAME_TRUST_CONTEXT)) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue