in src/processor/stackwalker_x86_unittest.cc [1810:2056]
void GetCallerFrame::IPAddressIsNotInKnownModuleTestImpl(
bool has_corrupt_symbols) {
MockCodeModule remoting_core_dll(0x54080000, 0x501000, "remoting_core.dll",
"version1");
string symbols_func_section =
"FUNC 137214 17d 10 PK11_Verify\n"
"FUNC 15c834 37 14 nsc_ECDSAVerifyStub\n"
"FUNC 1611d3 91 14 NSC_Verify\n"
"FUNC 162ff7 60 4 sftk_SessionFromHandle\n";
string symbols_stack_section =
"STACK WIN 4 137214 17d 9 0 10 0 10 0 1 $T0 $ebp = "
"$eip $T0 4 + ^ = $ebp $T0 ^ = $esp $T0 8 + =\n"
"STACK WIN 4 15c834 37 6 0 14 0 18 0 1 $T0 $ebp = "
"$eip $T0 4 + ^ = $ebp $T0 ^ = $esp $T0 8 + =\n"
"STACK WIN 4 1611d3 91 7 0 14 0 8 0 1 $T0 $ebp = "
"$eip $T0 4 + ^ = $ebp $T0 ^ = $esp $T0 8 + =\n"
"STACK WIN 4 162ff7 60 5 0 4 0 0 0 1 $T0 $ebp = "
"$eip $T0 4 + ^ = $ebp $T0 ^ = $esp $T0 8 + =\n";
string symbols = symbols_func_section;
if (has_corrupt_symbols) {
symbols.append(string(1, '\0')); // null terminator in the middle
symbols.append("\n");
symbols.append("FUNC 1234\n" // invalid FUNC records
"FUNNC 1234\n"
"STACK WIN 4 1234 234 23 " // invalid STACK record
"23423423 234 23 234 234 "
"234 23 234 23 234 234 "
"234 234 234\n");
}
symbols.append(symbols_stack_section);
SetModuleSymbols(&remoting_core_dll, symbols);
// Create some modules with some stock debugging information.
MockCodeModules local_modules;
local_modules.Add(&remoting_core_dll);
Label frame0_esp;
Label frame0_ebp;
Label frame1_ebp;
Label frame1_esp;
Label frame2_ebp;
Label frame2_esp;
Label frame3_ebp;
Label frame3_esp;
Label bogus_stack_location_1;
Label bogus_stack_location_2;
Label bogus_stack_location_3;
stack_section.start() = 0x01a3ea28;
stack_section
.Mark(&frame0_esp)
.D32(bogus_stack_location_2)
.D32(bogus_stack_location_1)
.D32(0x042478e4)
.D32(bogus_stack_location_2)
.D32(0x00000000)
.D32(0x041f0420)
.D32(0x00000000)
.D32(0x00000000)
.D32(0x00000040)
.D32(0x00000001)
.D32(0x00b7e0d0)
.D32(0x00000000)
.D32(0x00000040)
.D32(0x00000001)
.D32(0x00b7f570)
.Mark(&bogus_stack_location_1)
.D32(0x00000000)
.D32(0x00000040)
.D32(0x00000008)
.D32(0x04289530)
.D32(0x00000000)
.D32(0x00000040)
.D32(0x00000008)
.D32(0x00b7e910)
.D32(0x00000000)
.D32(0x00000040)
.D32(0x00000008)
.D32(0x00b7d998)
.D32(0x00000000)
.D32(0x00000040)
.D32(0x00000008)
.D32(0x00b7dec0)
.Mark(&bogus_stack_location_2)
.D32(0x00000000)
.D32(0x00000040)
.D32(0x00000008)
.D32(0x04289428)
.D32(0x00000000)
.D32(0x00000040)
.D32(0x00000008)
.D32(0x00b7f258)
.Mark(&bogus_stack_location_3)
.D32(0x00000000)
.D32(0x041f3560)
.D32(0x00000041)
.D32(0x00000020)
.D32(0xffffffff)
.Mark(&frame0_ebp)
.D32(frame1_ebp) // Child %ebp
.D32(0x541dc866) // return address of frame 0
// inside remoting_core!nsc_ECDSAVerifyStub+0x32
.Mark(&frame1_esp)
.D32(0x04247860)
.D32(0x01a3eaec)
.D32(0x01a3eaf8)
.D32(0x541e304f) // remoting_core!sftk_SessionFromHandle+0x58
.D32(0x0404c620)
.D32(0x00000040)
.D32(0x01a3eb2c)
.D32(0x01a3ec08)
.D32(0x00000014)
.Mark(&frame1_ebp)
.D32(frame2_ebp) // Child %ebp
.D32(0x541e1234) // return address of frame 1
// inside remoting_core!NSC_Verify+0x61
.Mark(&frame2_esp)
.D32(0x04247858)
.D32(0x0404c620)
.D32(0x00000040)
.D32(0x01a3ec08)
.D32(0x00000014)
.D32(0x01000005)
.D32(0x00b2f7a0)
.D32(0x041f0420)
.D32(0x041f3650)
.Mark(&frame2_ebp)
.D32(frame3_ebp) // Child %ebp
.D32(0x541b734d) // return address of frame 1
// inside remoting_core!PK11_Verify+0x139
.Mark(&frame3_esp)
.D32(0x01000005)
.D32(0x01a3ec08)
.D32(0x00000014)
.D32(0x0404c620)
.D32(0x00000040)
.D32(0x04073e00)
.D32(0x04073e00)
.D32(0x04247050)
.D32(0x00001041)
.D32(0x00000000)
.D32(0x00000000)
.D32(0x00000000)
.Mark(&frame3_ebp)
.D32(0) // saved %ebp (stack end)
.D32(0); // saved %eip (stack end)
RegionFromSection();
raw_context.eip = 0x4247860; // IP address not in known module
raw_context.ebp = 0x5420362d; // bogus
raw_context.esp = frame0_esp.Value();
// sanity
ASSERT_TRUE(raw_context.esp == stack_section.start().Value());
StackFrameSymbolizer frame_symbolizer(&supplier, &resolver);
StackwalkerX86 walker(&system_info, &raw_context, &stack_region,
&local_modules, &frame_symbolizer);
vector<const CodeModule*> modules_without_symbols;
vector<const CodeModule*> modules_with_corrupt_symbols;
ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols,
&modules_with_corrupt_symbols));
ASSERT_EQ(0U, modules_without_symbols.size());
if (has_corrupt_symbols) {
ASSERT_EQ(1U, modules_with_corrupt_symbols.size());
ASSERT_EQ("remoting_core.dll",
modules_with_corrupt_symbols[0]->debug_file());
} else {
ASSERT_EQ(0U, modules_with_corrupt_symbols.size());
}
frames = call_stack.frames();
ASSERT_EQ(4U, frames->size());
{ // To avoid reusing locals by mistake
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(raw_context.eip, frame0->context.eip);
EXPECT_EQ(raw_context.ebp, frame0->context.ebp);
EXPECT_EQ(raw_context.esp, frame0->context.esp);
EXPECT_EQ(NULL, frame0->module); // IP not in known module
EXPECT_EQ("", frame0->function_name);
ASSERT_EQ(NULL, frame0->windows_frame_info);
}
{ // To avoid reusing locals by mistake
StackFrameX86 *frame1 = static_cast<StackFrameX86 *>(frames->at(1));
EXPECT_EQ(StackFrame::FRAME_TRUST_SCAN, frame1->trust);
ASSERT_EQ((StackFrameX86::CONTEXT_VALID_EIP |
StackFrameX86::CONTEXT_VALID_ESP |
StackFrameX86::CONTEXT_VALID_EBP),
frame1->context_validity);
EXPECT_EQ(frame1_ebp.Value(), frame1->context.ebp);
EXPECT_EQ(frame1_esp.Value(), frame1->context.esp);
EXPECT_EQ(&remoting_core_dll, frame1->module);
EXPECT_EQ("nsc_ECDSAVerifyStub", frame1->function_name);
ASSERT_TRUE(frame1->windows_frame_info != NULL);
EXPECT_EQ(WindowsFrameInfo::VALID_ALL, frame1->windows_frame_info->valid);
EXPECT_EQ(WindowsFrameInfo::STACK_INFO_FRAME_DATA,
frame1->windows_frame_info->type_);
EXPECT_EQ("$T0 $ebp = $eip $T0 4 + ^ = $ebp $T0 ^ = $esp $T0 8 + =",
frame1->windows_frame_info->program_string);
EXPECT_FALSE(frame1->windows_frame_info->allocates_base_pointer);
}
{ // To avoid reusing locals by mistake
StackFrameX86 *frame2 = static_cast<StackFrameX86 *>(frames->at(2));
EXPECT_EQ(StackFrame::FRAME_TRUST_CFI, frame2->trust);
ASSERT_EQ((StackFrameX86::CONTEXT_VALID_EIP |
StackFrameX86::CONTEXT_VALID_ESP |
StackFrameX86::CONTEXT_VALID_EBP),
frame2->context_validity);
EXPECT_EQ(frame2_ebp.Value(), frame2->context.ebp);
EXPECT_EQ(frame2_esp.Value(), frame2->context.esp);
EXPECT_EQ(&remoting_core_dll, frame2->module);
EXPECT_EQ("NSC_Verify", frame2->function_name);
ASSERT_TRUE(frame2->windows_frame_info != NULL);
EXPECT_EQ(WindowsFrameInfo::VALID_ALL, frame2->windows_frame_info->valid);
EXPECT_EQ(WindowsFrameInfo::STACK_INFO_FRAME_DATA,
frame2->windows_frame_info->type_);
EXPECT_EQ("$T0 $ebp = $eip $T0 4 + ^ = $ebp $T0 ^ = $esp $T0 8 + =",
frame2->windows_frame_info->program_string);
EXPECT_FALSE(frame2->windows_frame_info->allocates_base_pointer);
}
{ // To avoid reusing locals by mistake
StackFrameX86 *frame3 = static_cast<StackFrameX86 *>(frames->at(3));
EXPECT_EQ(StackFrame::FRAME_TRUST_CFI, frame3->trust);
ASSERT_EQ((StackFrameX86::CONTEXT_VALID_EIP |
StackFrameX86::CONTEXT_VALID_ESP |
StackFrameX86::CONTEXT_VALID_EBP),
frame3->context_validity);
EXPECT_EQ(frame3_ebp.Value(), frame3->context.ebp);
EXPECT_EQ(frame3_esp.Value(), frame3->context.esp);
EXPECT_EQ(&remoting_core_dll, frame3->module);
EXPECT_EQ("PK11_Verify", frame3->function_name);
ASSERT_TRUE(frame3->windows_frame_info != NULL);
EXPECT_EQ(WindowsFrameInfo::VALID_ALL, frame3->windows_frame_info->valid);
EXPECT_EQ(WindowsFrameInfo::STACK_INFO_FRAME_DATA,
frame3->windows_frame_info->type_);
EXPECT_EQ("$T0 $ebp = $eip $T0 4 + ^ = $ebp $T0 ^ = $esp $T0 8 + =",
frame3->windows_frame_info->program_string);
EXPECT_FALSE(frame3->windows_frame_info->allocates_base_pointer);
}
}