mirror of
https://github.com/yuzu-emu/breakpad
synced 2024-11-23 02:33:39 +00:00
arm: Allow the first function to use linked register as return pc
For a crash at the function entry with corrupted PC, the caller's PC could be lying in the link register. Using the PC from link register would be more effective than blindly scanning the stack immediately. Change-Id: I51673b7298e70faeeab2bfa97075e3c4793f94bc Reviewed-on: https://chromium-review.googlesource.com/c/breakpad/breakpad/+/2678992 Reviewed-by: Mike Frysinger <vapier@chromium.org> Reviewed-by: Joshua Peraza <jperaza@chromium.org>
This commit is contained in:
parent
2d3e030fdb
commit
f2b3ab5e0a
3 changed files with 33 additions and 1 deletions
|
@ -232,7 +232,7 @@ TEST_F(MicrodumpProcessorTest, TestProcessMultiple) {
|
||||||
ASSERT_EQ("arm", state.system_info()->cpu);
|
ASSERT_EQ("arm", state.system_info()->cpu);
|
||||||
ASSERT_EQ("lge/p1_tmo_us/p1:6.0/MRA58K/1603210524c8d:user/release-keys",
|
ASSERT_EQ("lge/p1_tmo_us/p1:6.0/MRA58K/1603210524c8d:user/release-keys",
|
||||||
state.system_info()->os_version);
|
state.system_info()->os_version);
|
||||||
ASSERT_EQ(5U, state.threads()->at(0)->frames()->size());
|
ASSERT_EQ(6U, state.threads()->at(0)->frames()->size());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(MicrodumpProcessorTest, TestProcessMips) {
|
TEST_F(MicrodumpProcessorTest, TestProcessMips) {
|
||||||
|
|
|
@ -238,6 +238,27 @@ StackFrameARM* StackwalkerARM::GetCallerByFramePointer(
|
||||||
return frame;
|
return frame;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
StackFrameARM* StackwalkerARM::GetCallerByLinkRegister(
|
||||||
|
const vector<StackFrame*>& frames) {
|
||||||
|
StackFrameARM* last_frame = static_cast<StackFrameARM*>(frames.back());
|
||||||
|
uint32_t last_lr = last_frame->context.iregs[MD_CONTEXT_ARM_REG_LR];
|
||||||
|
|
||||||
|
if (!(last_frame->context_validity & StackFrameARM::CONTEXT_VALID_LR) ||
|
||||||
|
!InstructionAddressSeemsValid(last_lr)) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
StackFrameARM* frame = new StackFrameARM();
|
||||||
|
|
||||||
|
frame->trust = StackFrame::FRAME_TRUST_SCAN;
|
||||||
|
frame->context = last_frame->context;
|
||||||
|
frame->context.iregs[MD_CONTEXT_ARM_REG_PC] = last_lr;
|
||||||
|
frame->context_validity =
|
||||||
|
context_frame_validity_ & (~StackFrameARM::CONTEXT_VALID_LR);
|
||||||
|
|
||||||
|
return frame;
|
||||||
|
}
|
||||||
|
|
||||||
StackFrame* StackwalkerARM::GetCallerFrame(const CallStack* stack,
|
StackFrame* StackwalkerARM::GetCallerFrame(const CallStack* stack,
|
||||||
bool stack_scan_allowed) {
|
bool stack_scan_allowed) {
|
||||||
if (!memory_ || !stack) {
|
if (!memory_ || !stack) {
|
||||||
|
@ -264,6 +285,12 @@ StackFrame* StackwalkerARM::GetCallerFrame(const CallStack* stack,
|
||||||
if (fp_register_ >= 0 && !frame.get())
|
if (fp_register_ >= 0 && !frame.get())
|
||||||
frame.reset(GetCallerByFramePointer(frames));
|
frame.reset(GetCallerByFramePointer(frames));
|
||||||
|
|
||||||
|
// For the first frame, return address may still be in the LR register at
|
||||||
|
// entry. Prefer to use LR register than scanning stack if LR register value
|
||||||
|
// points to a function range.
|
||||||
|
if (frames.size() == 1 && !frame.get())
|
||||||
|
frame.reset(GetCallerByLinkRegister(frames));
|
||||||
|
|
||||||
// If everuthing failed, fall back to stack scanning.
|
// If everuthing failed, fall back to stack scanning.
|
||||||
if (stack_scan_allowed && !frame.get())
|
if (stack_scan_allowed && !frame.get())
|
||||||
frame.reset(GetCallerByStackScan(frames));
|
frame.reset(GetCallerByStackScan(frames));
|
||||||
|
|
|
@ -82,6 +82,11 @@ class StackwalkerARM : public Stackwalker {
|
||||||
// Return NULL on failure.
|
// Return NULL on failure.
|
||||||
StackFrameARM* GetCallerByFramePointer(const vector<StackFrame*>& frames);
|
StackFrameARM* GetCallerByFramePointer(const vector<StackFrame*>& frames);
|
||||||
|
|
||||||
|
// Use the link register if it seems to be a valid function adderss.
|
||||||
|
// The caller takes ownership of the returned frame. Return NULL on failure.
|
||||||
|
// This is useful when PC register is corrupted.
|
||||||
|
StackFrameARM* GetCallerByLinkRegister(const vector<StackFrame*>& frames);
|
||||||
|
|
||||||
// Scan the stack for plausible return addresses. The caller takes ownership
|
// Scan the stack for plausible return addresses. The caller takes ownership
|
||||||
// of the returned frame. Return NULL on failure.
|
// of the returned frame. Return NULL on failure.
|
||||||
StackFrameARM* GetCallerByStackScan(const vector<StackFrame*>& frames);
|
StackFrameARM* GetCallerByStackScan(const vector<StackFrame*>& frames);
|
||||||
|
|
Loading…
Reference in a new issue