void GetCallerFrame::IPAddressIsNotInKnownModuleTestImpl()

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);
  }
}