diff --git a/src/processor/stackwalker.cc b/src/processor/stackwalker.cc index b0f0c4b2..9ddb60ae 100644 --- a/src/processor/stackwalker.cc +++ b/src/processor/stackwalker.cc @@ -120,7 +120,8 @@ bool Stackwalker::Walk(CallStack *stack) { if (resolver_->ShouldDeleteMemoryBufferAfterLoadModule()) supplier_->FreeSymbolData(module); } - resolver_->FillSourceLineInfo(frame.get()); + if (resolver_) + resolver_->FillSourceLineInfo(frame.get()); } } diff --git a/src/processor/stackwalker_amd64.cc b/src/processor/stackwalker_amd64.cc index c142e2a3..fd9ccdf3 100644 --- a/src/processor/stackwalker_amd64.cc +++ b/src/processor/stackwalker_amd64.cc @@ -184,7 +184,7 @@ StackFrame* StackwalkerAMD64::GetCallerFrame(const CallStack *stack) { // If we have DWARF CFI information, use it. scoped_ptr cfi_frame_info( - resolver_->FindCFIFrameInfo(last_frame)); + resolver_ ? resolver_->FindCFIFrameInfo(last_frame) : NULL); if (cfi_frame_info.get()) new_frame.reset(GetCallerByCFIFrameInfo(frames, cfi_frame_info.get())); diff --git a/src/processor/stackwalker_amd64_unittest.cc b/src/processor/stackwalker_amd64_unittest.cc index 758c06db..0cb5fd57 100644 --- a/src/processor/stackwalker_amd64_unittest.cc +++ b/src/processor/stackwalker_amd64_unittest.cc @@ -130,6 +130,28 @@ class StackwalkerAMD64Fixture { 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(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) { // There should be no references to the stack in this walk: we don't // provide any call frame information, so trying to reconstruct the @@ -139,14 +161,14 @@ TEST_F(GetContextFrame, Simple) { raw_context.rbp = 0x8000000080000000ULL; StackwalkerAMD64 walker(&system_info, &raw_context, &stack_region, &modules, - &supplier, &resolver); + &supplier, &resolver); ASSERT_TRUE(walker.Walk(&call_stack)); frames = call_stack.frames(); ASSERT_GE(1U, frames->size()); StackFrameAMD64 *frame = static_cast(frames->at(0)); // Check that the values from the original raw context made it // 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 { }; @@ -195,7 +217,7 @@ TEST_F(GetCallerFrame, ScanWithoutSymbols) { StackFrameAMD64 *frame0 = static_cast(frames->at(0)); EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust); 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(frames->at(1)); EXPECT_EQ(StackFrame::FRAME_TRUST_SCAN, frame1->trust); diff --git a/src/processor/stackwalker_arm.cc b/src/processor/stackwalker_arm.cc index 239f89d0..3b91caff 100644 --- a/src/processor/stackwalker_arm.cc +++ b/src/processor/stackwalker_arm.cc @@ -190,8 +190,8 @@ StackFrame* StackwalkerARM::GetCallerFrame(const CallStack *stack) { scoped_ptr frame; // See if there is DWARF call frame information covering this address. - scoped_ptr cfi_frame_info(resolver_ - ->FindCFIFrameInfo(last_frame)); + scoped_ptr cfi_frame_info( + resolver_ ? resolver_->FindCFIFrameInfo(last_frame) : NULL); if (cfi_frame_info.get()) frame.reset(GetCallerByCFIFrameInfo(frames, cfi_frame_info.get())); diff --git a/src/processor/stackwalker_arm_unittest.cc b/src/processor/stackwalker_arm_unittest.cc index 637435b1..cb7ce631 100644 --- a/src/processor/stackwalker_arm_unittest.cc +++ b/src/processor/stackwalker_arm_unittest.cc @@ -130,6 +130,24 @@ class StackwalkerARMFixture { const vector *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(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 { }; TEST_F(GetContextFrame, Simple) { @@ -144,7 +162,7 @@ TEST_F(GetContextFrame, Simple) { StackFrameARM *frame = static_cast(frames->at(0)); // Check that the values from the original raw context made it // 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 { }; @@ -192,7 +210,7 @@ TEST_F(GetCallerFrame, ScanWithoutSymbols) { StackFrameARM *frame0 = static_cast(frames->at(0)); EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust); 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(frames->at(1)); EXPECT_EQ(StackFrame::FRAME_TRUST_SCAN, frame1->trust); @@ -255,7 +273,7 @@ TEST_F(GetCallerFrame, ScanWithFunctionSymbols) { StackFrameARM *frame0 = static_cast(frames->at(0)); EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust); 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(0x40000100, frame0->function_base); diff --git a/src/processor/stackwalker_x86.cc b/src/processor/stackwalker_x86.cc index 9440f1d5..2ee37bfb 100644 --- a/src/processor/stackwalker_x86.cc +++ b/src/processor/stackwalker_x86.cc @@ -531,13 +531,14 @@ StackFrame *StackwalkerX86::GetCallerFrame(const CallStack *stack) { // If the resolver has Windows stack walking information, use that. WindowsFrameInfo *windows_frame_info - = resolver_->FindWindowsFrameInfo(last_frame); + = resolver_ ? resolver_->FindWindowsFrameInfo(last_frame) : NULL; if (windows_frame_info) new_frame.reset(GetCallerByWindowsFrameInfo(frames, windows_frame_info)); // If the resolver has DWARF CFI information, use that. 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) new_frame.reset(GetCallerByCFIFrameInfo(frames, cfi_frame_info)); } diff --git a/src/processor/stackwalker_x86_unittest.cc b/src/processor/stackwalker_x86_unittest.cc index aece4891..aa6b6310 100644 --- a/src/processor/stackwalker_x86_unittest.cc +++ b/src/processor/stackwalker_x86_unittest.cc @@ -129,6 +129,26 @@ class StackwalkerX86Fixture { const vector *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(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 { }; TEST_F(GetContextFrame, Simple) { @@ -145,7 +165,7 @@ TEST_F(GetContextFrame, Simple) { StackFrameX86 *frame = static_cast(frames->at(0)); // Check that the values from the original raw context made it // 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 { };