mirror of
https://github.com/yuzu-emu/breakpad.git
synced 2024-12-23 15:45:39 +00:00
Fix some apparently longstanding crash bugs in Stackwalker implementations when resolver is NULL.
R=mark at http://breakpad.appspot.com/257001 git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@761 4c0a9323-5329-0410-9bdc-e9ce6186880e
This commit is contained in:
parent
b904343e14
commit
281d52d944
|
@ -120,7 +120,8 @@ bool Stackwalker::Walk(CallStack *stack) {
|
||||||
if (resolver_->ShouldDeleteMemoryBufferAfterLoadModule())
|
if (resolver_->ShouldDeleteMemoryBufferAfterLoadModule())
|
||||||
supplier_->FreeSymbolData(module);
|
supplier_->FreeSymbolData(module);
|
||||||
}
|
}
|
||||||
resolver_->FillSourceLineInfo(frame.get());
|
if (resolver_)
|
||||||
|
resolver_->FillSourceLineInfo(frame.get());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -184,7 +184,7 @@ StackFrame* StackwalkerAMD64::GetCallerFrame(const CallStack *stack) {
|
||||||
|
|
||||||
// If we have DWARF CFI information, use it.
|
// If we have DWARF CFI information, use it.
|
||||||
scoped_ptr<CFIFrameInfo> cfi_frame_info(
|
scoped_ptr<CFIFrameInfo> cfi_frame_info(
|
||||||
resolver_->FindCFIFrameInfo(last_frame));
|
resolver_ ? resolver_->FindCFIFrameInfo(last_frame) : NULL);
|
||||||
if (cfi_frame_info.get())
|
if (cfi_frame_info.get())
|
||||||
new_frame.reset(GetCallerByCFIFrameInfo(frames, cfi_frame_info.get()));
|
new_frame.reset(GetCallerByCFIFrameInfo(frames, cfi_frame_info.get()));
|
||||||
|
|
||||||
|
|
|
@ -130,6 +130,28 @@ class StackwalkerAMD64Fixture {
|
||||||
|
|
||||||
class GetContextFrame: public StackwalkerAMD64Fixture, public Test { };
|
class GetContextFrame: public StackwalkerAMD64Fixture, public Test { };
|
||||||
|
|
||||||
|
class SanityCheck: public StackwalkerAMD64Fixture, public Test { };
|
||||||
|
|
||||||
|
TEST_F(SanityCheck, NoResolver) {
|
||||||
|
// There should be no references to the stack in this walk: we don't
|
||||||
|
// provide any call frame information, so trying to reconstruct the
|
||||||
|
// context frame's caller should fail. So there's no need for us to
|
||||||
|
// provide stack contents.
|
||||||
|
raw_context.rip = 0x40000000c0000200ULL;
|
||||||
|
raw_context.rbp = 0x8000000080000000ULL;
|
||||||
|
|
||||||
|
StackwalkerAMD64 walker(&system_info, &raw_context, &stack_region, &modules,
|
||||||
|
NULL, NULL);
|
||||||
|
// This should succeed even without a resolver or supplier.
|
||||||
|
ASSERT_TRUE(walker.Walk(&call_stack));
|
||||||
|
frames = call_stack.frames();
|
||||||
|
ASSERT_GE(1U, frames->size());
|
||||||
|
StackFrameAMD64 *frame = static_cast<StackFrameAMD64 *>(frames->at(0));
|
||||||
|
// Check that the values from the original raw context made it
|
||||||
|
// through to the context in the stack frame.
|
||||||
|
EXPECT_EQ(0, memcmp(&raw_context, &frame->context, sizeof(raw_context)));
|
||||||
|
}
|
||||||
|
|
||||||
TEST_F(GetContextFrame, Simple) {
|
TEST_F(GetContextFrame, Simple) {
|
||||||
// There should be no references to the stack in this walk: we don't
|
// There should be no references to the stack in this walk: we don't
|
||||||
// provide any call frame information, so trying to reconstruct the
|
// provide any call frame information, so trying to reconstruct the
|
||||||
|
@ -139,14 +161,14 @@ TEST_F(GetContextFrame, Simple) {
|
||||||
raw_context.rbp = 0x8000000080000000ULL;
|
raw_context.rbp = 0x8000000080000000ULL;
|
||||||
|
|
||||||
StackwalkerAMD64 walker(&system_info, &raw_context, &stack_region, &modules,
|
StackwalkerAMD64 walker(&system_info, &raw_context, &stack_region, &modules,
|
||||||
&supplier, &resolver);
|
&supplier, &resolver);
|
||||||
ASSERT_TRUE(walker.Walk(&call_stack));
|
ASSERT_TRUE(walker.Walk(&call_stack));
|
||||||
frames = call_stack.frames();
|
frames = call_stack.frames();
|
||||||
ASSERT_GE(1U, frames->size());
|
ASSERT_GE(1U, frames->size());
|
||||||
StackFrameAMD64 *frame = static_cast<StackFrameAMD64 *>(frames->at(0));
|
StackFrameAMD64 *frame = static_cast<StackFrameAMD64 *>(frames->at(0));
|
||||||
// Check that the values from the original raw context made it
|
// Check that the values from the original raw context made it
|
||||||
// through to the context in the stack frame.
|
// through to the context in the stack frame.
|
||||||
EXPECT_TRUE(memcmp(&raw_context, &frame->context, sizeof(raw_context)) == 0);
|
EXPECT_EQ(0, memcmp(&raw_context, &frame->context, sizeof(raw_context)));
|
||||||
}
|
}
|
||||||
|
|
||||||
class GetCallerFrame: public StackwalkerAMD64Fixture, public Test { };
|
class GetCallerFrame: public StackwalkerAMD64Fixture, public Test { };
|
||||||
|
@ -195,7 +217,7 @@ TEST_F(GetCallerFrame, ScanWithoutSymbols) {
|
||||||
StackFrameAMD64 *frame0 = static_cast<StackFrameAMD64 *>(frames->at(0));
|
StackFrameAMD64 *frame0 = static_cast<StackFrameAMD64 *>(frames->at(0));
|
||||||
EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust);
|
EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust);
|
||||||
ASSERT_EQ(StackFrameAMD64::CONTEXT_VALID_ALL, frame0->context_validity);
|
ASSERT_EQ(StackFrameAMD64::CONTEXT_VALID_ALL, frame0->context_validity);
|
||||||
EXPECT_TRUE(memcmp(&raw_context, &frame0->context, sizeof(raw_context)) == 0);
|
EXPECT_EQ(0, memcmp(&raw_context, &frame0->context, sizeof(raw_context)));
|
||||||
|
|
||||||
StackFrameAMD64 *frame1 = static_cast<StackFrameAMD64 *>(frames->at(1));
|
StackFrameAMD64 *frame1 = static_cast<StackFrameAMD64 *>(frames->at(1));
|
||||||
EXPECT_EQ(StackFrame::FRAME_TRUST_SCAN, frame1->trust);
|
EXPECT_EQ(StackFrame::FRAME_TRUST_SCAN, frame1->trust);
|
||||||
|
|
|
@ -190,8 +190,8 @@ StackFrame* StackwalkerARM::GetCallerFrame(const CallStack *stack) {
|
||||||
scoped_ptr<StackFrameARM> frame;
|
scoped_ptr<StackFrameARM> frame;
|
||||||
|
|
||||||
// See if there is DWARF call frame information covering this address.
|
// See if there is DWARF call frame information covering this address.
|
||||||
scoped_ptr<CFIFrameInfo> cfi_frame_info(resolver_
|
scoped_ptr<CFIFrameInfo> cfi_frame_info(
|
||||||
->FindCFIFrameInfo(last_frame));
|
resolver_ ? resolver_->FindCFIFrameInfo(last_frame) : NULL);
|
||||||
if (cfi_frame_info.get())
|
if (cfi_frame_info.get())
|
||||||
frame.reset(GetCallerByCFIFrameInfo(frames, cfi_frame_info.get()));
|
frame.reset(GetCallerByCFIFrameInfo(frames, cfi_frame_info.get()));
|
||||||
|
|
||||||
|
|
|
@ -130,6 +130,24 @@ class StackwalkerARMFixture {
|
||||||
const vector<StackFrame *> *frames;
|
const vector<StackFrame *> *frames;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class SanityCheck: public StackwalkerARMFixture, public Test { };
|
||||||
|
|
||||||
|
TEST_F(SanityCheck, NoResolver) {
|
||||||
|
// Since we have no call frame information, and all unwinding
|
||||||
|
// requires call frame information, the stack walk will end after
|
||||||
|
// the first frame.
|
||||||
|
StackwalkerARM walker(&system_info, &raw_context, &stack_region, &modules,
|
||||||
|
NULL, NULL);
|
||||||
|
// This should succeed even without a resolver or supplier.
|
||||||
|
ASSERT_TRUE(walker.Walk(&call_stack));
|
||||||
|
frames = call_stack.frames();
|
||||||
|
ASSERT_EQ(1U, frames->size());
|
||||||
|
StackFrameARM *frame = static_cast<StackFrameARM *>(frames->at(0));
|
||||||
|
// Check that the values from the original raw context made it
|
||||||
|
// through to the context in the stack frame.
|
||||||
|
EXPECT_EQ(0, memcmp(&raw_context, &frame->context, sizeof(raw_context)));
|
||||||
|
}
|
||||||
|
|
||||||
class GetContextFrame: public StackwalkerARMFixture, public Test { };
|
class GetContextFrame: public StackwalkerARMFixture, public Test { };
|
||||||
|
|
||||||
TEST_F(GetContextFrame, Simple) {
|
TEST_F(GetContextFrame, Simple) {
|
||||||
|
@ -144,7 +162,7 @@ TEST_F(GetContextFrame, Simple) {
|
||||||
StackFrameARM *frame = static_cast<StackFrameARM *>(frames->at(0));
|
StackFrameARM *frame = static_cast<StackFrameARM *>(frames->at(0));
|
||||||
// Check that the values from the original raw context made it
|
// Check that the values from the original raw context made it
|
||||||
// through to the context in the stack frame.
|
// through to the context in the stack frame.
|
||||||
EXPECT_TRUE(memcmp(&raw_context, &frame->context, sizeof(raw_context)) == 0);
|
EXPECT_EQ(0, memcmp(&raw_context, &frame->context, sizeof(raw_context)));
|
||||||
}
|
}
|
||||||
|
|
||||||
class GetCallerFrame: public StackwalkerARMFixture, public Test { };
|
class GetCallerFrame: public StackwalkerARMFixture, public Test { };
|
||||||
|
@ -192,7 +210,7 @@ TEST_F(GetCallerFrame, ScanWithoutSymbols) {
|
||||||
StackFrameARM *frame0 = static_cast<StackFrameARM *>(frames->at(0));
|
StackFrameARM *frame0 = static_cast<StackFrameARM *>(frames->at(0));
|
||||||
EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust);
|
EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust);
|
||||||
ASSERT_EQ(StackFrameARM::CONTEXT_VALID_ALL, frame0->context_validity);
|
ASSERT_EQ(StackFrameARM::CONTEXT_VALID_ALL, frame0->context_validity);
|
||||||
EXPECT_TRUE(memcmp(&raw_context, &frame0->context, sizeof(raw_context)) == 0);
|
EXPECT_EQ(0, memcmp(&raw_context, &frame0->context, sizeof(raw_context)));
|
||||||
|
|
||||||
StackFrameARM *frame1 = static_cast<StackFrameARM *>(frames->at(1));
|
StackFrameARM *frame1 = static_cast<StackFrameARM *>(frames->at(1));
|
||||||
EXPECT_EQ(StackFrame::FRAME_TRUST_SCAN, frame1->trust);
|
EXPECT_EQ(StackFrame::FRAME_TRUST_SCAN, frame1->trust);
|
||||||
|
@ -255,7 +273,7 @@ TEST_F(GetCallerFrame, ScanWithFunctionSymbols) {
|
||||||
StackFrameARM *frame0 = static_cast<StackFrameARM *>(frames->at(0));
|
StackFrameARM *frame0 = static_cast<StackFrameARM *>(frames->at(0));
|
||||||
EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust);
|
EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust);
|
||||||
ASSERT_EQ(StackFrameARM::CONTEXT_VALID_ALL, frame0->context_validity);
|
ASSERT_EQ(StackFrameARM::CONTEXT_VALID_ALL, frame0->context_validity);
|
||||||
EXPECT_TRUE(memcmp(&raw_context, &frame0->context, sizeof(raw_context)) == 0);
|
EXPECT_EQ(0, memcmp(&raw_context, &frame0->context, sizeof(raw_context)));
|
||||||
EXPECT_EQ("monotreme", frame0->function_name);
|
EXPECT_EQ("monotreme", frame0->function_name);
|
||||||
EXPECT_EQ(0x40000100, frame0->function_base);
|
EXPECT_EQ(0x40000100, frame0->function_base);
|
||||||
|
|
||||||
|
|
|
@ -531,13 +531,14 @@ StackFrame *StackwalkerX86::GetCallerFrame(const CallStack *stack) {
|
||||||
|
|
||||||
// If the resolver has Windows stack walking information, use that.
|
// If the resolver has Windows stack walking information, use that.
|
||||||
WindowsFrameInfo *windows_frame_info
|
WindowsFrameInfo *windows_frame_info
|
||||||
= resolver_->FindWindowsFrameInfo(last_frame);
|
= resolver_ ? resolver_->FindWindowsFrameInfo(last_frame) : NULL;
|
||||||
if (windows_frame_info)
|
if (windows_frame_info)
|
||||||
new_frame.reset(GetCallerByWindowsFrameInfo(frames, windows_frame_info));
|
new_frame.reset(GetCallerByWindowsFrameInfo(frames, windows_frame_info));
|
||||||
|
|
||||||
// If the resolver has DWARF CFI information, use that.
|
// If the resolver has DWARF CFI information, use that.
|
||||||
if (!new_frame.get()) {
|
if (!new_frame.get()) {
|
||||||
CFIFrameInfo *cfi_frame_info = resolver_->FindCFIFrameInfo(last_frame);
|
CFIFrameInfo *cfi_frame_info =
|
||||||
|
resolver_ ? resolver_->FindCFIFrameInfo(last_frame) : NULL;
|
||||||
if (cfi_frame_info)
|
if (cfi_frame_info)
|
||||||
new_frame.reset(GetCallerByCFIFrameInfo(frames, cfi_frame_info));
|
new_frame.reset(GetCallerByCFIFrameInfo(frames, cfi_frame_info));
|
||||||
}
|
}
|
||||||
|
|
|
@ -129,6 +129,26 @@ class StackwalkerX86Fixture {
|
||||||
const vector<StackFrame *> *frames;
|
const vector<StackFrame *> *frames;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class SanityCheck: public StackwalkerX86Fixture, public Test { };
|
||||||
|
|
||||||
|
TEST_F(SanityCheck, NoResolver) {
|
||||||
|
stack_section.start() = 0x80000000;
|
||||||
|
stack_section.D32(0).D32(0); // end-of-stack marker
|
||||||
|
RegionFromSection();
|
||||||
|
raw_context.eip = 0x40000200;
|
||||||
|
raw_context.ebp = 0x80000000;
|
||||||
|
|
||||||
|
StackwalkerX86 walker(&system_info, &raw_context, &stack_region, &modules,
|
||||||
|
NULL, NULL);
|
||||||
|
// This should succeed, even without a resolver or supplier.
|
||||||
|
ASSERT_TRUE(walker.Walk(&call_stack));
|
||||||
|
frames = call_stack.frames();
|
||||||
|
StackFrameX86 *frame = static_cast<StackFrameX86 *>(frames->at(0));
|
||||||
|
// Check that the values from the original raw context made it
|
||||||
|
// through to the context in the stack frame.
|
||||||
|
EXPECT_EQ(0, memcmp(&raw_context, &frame->context, sizeof(raw_context)));
|
||||||
|
}
|
||||||
|
|
||||||
class GetContextFrame: public StackwalkerX86Fixture, public Test { };
|
class GetContextFrame: public StackwalkerX86Fixture, public Test { };
|
||||||
|
|
||||||
TEST_F(GetContextFrame, Simple) {
|
TEST_F(GetContextFrame, Simple) {
|
||||||
|
@ -145,7 +165,7 @@ TEST_F(GetContextFrame, Simple) {
|
||||||
StackFrameX86 *frame = static_cast<StackFrameX86 *>(frames->at(0));
|
StackFrameX86 *frame = static_cast<StackFrameX86 *>(frames->at(0));
|
||||||
// Check that the values from the original raw context made it
|
// Check that the values from the original raw context made it
|
||||||
// through to the context in the stack frame.
|
// through to the context in the stack frame.
|
||||||
EXPECT_TRUE(memcmp(&raw_context, &frame->context, sizeof(raw_context)) == 0);
|
EXPECT_EQ(0, memcmp(&raw_context, &frame->context, sizeof(raw_context)));
|
||||||
}
|
}
|
||||||
|
|
||||||
class GetCallerFrame: public StackwalkerX86Fixture, public Test { };
|
class GetCallerFrame: public StackwalkerX86Fixture, public Test { };
|
||||||
|
|
Loading…
Reference in a new issue