toolkit/crashreporter/google-breakpad/src/processor/stackwalker_x86_unittest.cc

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 // Copyright (c) 2010, Google Inc.
michael@0 2 // All rights reserved.
michael@0 3 //
michael@0 4 // Redistribution and use in source and binary forms, with or without
michael@0 5 // modification, are permitted provided that the following conditions are
michael@0 6 // met:
michael@0 7 //
michael@0 8 // * Redistributions of source code must retain the above copyright
michael@0 9 // notice, this list of conditions and the following disclaimer.
michael@0 10 // * Redistributions in binary form must reproduce the above
michael@0 11 // copyright notice, this list of conditions and the following disclaimer
michael@0 12 // in the documentation and/or other materials provided with the
michael@0 13 // distribution.
michael@0 14 // * Neither the name of Google Inc. nor the names of its
michael@0 15 // contributors may be used to endorse or promote products derived from
michael@0 16 // this software without specific prior written permission.
michael@0 17 //
michael@0 18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
michael@0 19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
michael@0 20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
michael@0 21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
michael@0 22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
michael@0 23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
michael@0 24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
michael@0 25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
michael@0 26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
michael@0 27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
michael@0 28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
michael@0 29
michael@0 30 // Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com>
michael@0 31
michael@0 32 // stackwalker_x86_unittest.cc: Unit tests for StackwalkerX86 class.
michael@0 33
michael@0 34 #include <string>
michael@0 35 #include <vector>
michael@0 36
michael@0 37 #include "breakpad_googletest_includes.h"
michael@0 38 #include "common/test_assembler.h"
michael@0 39 #include "common/using_std_string.h"
michael@0 40 #include "google_breakpad/common/minidump_format.h"
michael@0 41 #include "google_breakpad/processor/basic_source_line_resolver.h"
michael@0 42 #include "google_breakpad/processor/call_stack.h"
michael@0 43 #include "google_breakpad/processor/code_module.h"
michael@0 44 #include "google_breakpad/processor/source_line_resolver_interface.h"
michael@0 45 #include "google_breakpad/processor/stack_frame_cpu.h"
michael@0 46 #include "processor/stackwalker_unittest_utils.h"
michael@0 47 #include "processor/stackwalker_x86.h"
michael@0 48 #include "processor/windows_frame_info.h"
michael@0 49
michael@0 50 using google_breakpad::BasicSourceLineResolver;
michael@0 51 using google_breakpad::CallStack;
michael@0 52 using google_breakpad::CodeModule;
michael@0 53 using google_breakpad::StackFrameSymbolizer;
michael@0 54 using google_breakpad::StackFrame;
michael@0 55 using google_breakpad::StackFrameX86;
michael@0 56 using google_breakpad::StackwalkerX86;
michael@0 57 using google_breakpad::SystemInfo;
michael@0 58 using google_breakpad::WindowsFrameInfo;
michael@0 59 using google_breakpad::test_assembler::kLittleEndian;
michael@0 60 using google_breakpad::test_assembler::Label;
michael@0 61 using google_breakpad::test_assembler::Section;
michael@0 62 using std::vector;
michael@0 63 using testing::_;
michael@0 64 using testing::Return;
michael@0 65 using testing::SetArgumentPointee;
michael@0 66 using testing::Test;
michael@0 67
michael@0 68 class StackwalkerX86Fixture {
michael@0 69 public:
michael@0 70 StackwalkerX86Fixture()
michael@0 71 : stack_section(kLittleEndian),
michael@0 72 // Give the two modules reasonable standard locations and names
michael@0 73 // for tests to play with.
michael@0 74 module1(0x40000000, 0x10000, "module1", "version1"),
michael@0 75 module2(0x50000000, 0x10000, "module2", "version2"),
michael@0 76 module3(0x771d0000, 0x180000, "module3", "version3"),
michael@0 77 module4(0x75f90000, 0x46000, "module4", "version4"),
michael@0 78 module5(0x75730000, 0x110000, "module5", "version5"),
michael@0 79 module6(0x647f0000, 0x1ba8000, "module6", "version6") {
michael@0 80 // Identify the system as a Linux system.
michael@0 81 system_info.os = "Linux";
michael@0 82 system_info.os_short = "linux";
michael@0 83 system_info.os_version = "Salacious Skink";
michael@0 84 system_info.cpu = "x86";
michael@0 85 system_info.cpu_info = "";
michael@0 86
michael@0 87 // Put distinctive values in the raw CPU context.
michael@0 88 BrandContext(&raw_context);
michael@0 89
michael@0 90 // Create some modules with some stock debugging information.
michael@0 91 modules.Add(&module1);
michael@0 92 modules.Add(&module2);
michael@0 93 modules.Add(&module3);
michael@0 94 modules.Add(&module4);
michael@0 95 modules.Add(&module5);
michael@0 96 modules.Add(&module6);
michael@0 97
michael@0 98 // By default, none of the modules have symbol info; call
michael@0 99 // SetModuleSymbols to override this.
michael@0 100 EXPECT_CALL(supplier, GetCStringSymbolData(_, _, _, _))
michael@0 101 .WillRepeatedly(Return(MockSymbolSupplier::NOT_FOUND));
michael@0 102 }
michael@0 103
michael@0 104 // Set the Breakpad symbol information that supplier should return for
michael@0 105 // MODULE to INFO.
michael@0 106 void SetModuleSymbols(MockCodeModule *module, const string &info) {
michael@0 107 char *buffer = supplier.CopySymbolDataAndOwnTheCopy(info);
michael@0 108 EXPECT_CALL(supplier, GetCStringSymbolData(module, &system_info, _, _))
michael@0 109 .WillRepeatedly(DoAll(SetArgumentPointee<3>(buffer),
michael@0 110 Return(MockSymbolSupplier::FOUND)));
michael@0 111 }
michael@0 112
michael@0 113 // Populate stack_region with the contents of stack_section. Use
michael@0 114 // stack_section.start() as the region's starting address.
michael@0 115 void RegionFromSection() {
michael@0 116 string contents;
michael@0 117 ASSERT_TRUE(stack_section.GetContents(&contents));
michael@0 118 stack_region.Init(stack_section.start().Value(), contents);
michael@0 119 }
michael@0 120
michael@0 121 // Fill RAW_CONTEXT with pseudo-random data, for round-trip checking.
michael@0 122 void BrandContext(MDRawContextX86 *raw_context) {
michael@0 123 uint8_t x = 173;
michael@0 124 for (size_t i = 0; i < sizeof(*raw_context); i++)
michael@0 125 reinterpret_cast<uint8_t *>(raw_context)[i] = (x += 17);
michael@0 126 }
michael@0 127
michael@0 128 SystemInfo system_info;
michael@0 129 MDRawContextX86 raw_context;
michael@0 130 Section stack_section;
michael@0 131 MockMemoryRegion stack_region;
michael@0 132 MockCodeModule module1;
michael@0 133 MockCodeModule module2;
michael@0 134 MockCodeModule module3;
michael@0 135 MockCodeModule module4;
michael@0 136 MockCodeModule module5;
michael@0 137 MockCodeModule module6;
michael@0 138 MockCodeModules modules;
michael@0 139 MockSymbolSupplier supplier;
michael@0 140 BasicSourceLineResolver resolver;
michael@0 141 CallStack call_stack;
michael@0 142 const vector<StackFrame *> *frames;
michael@0 143 };
michael@0 144
michael@0 145 class SanityCheck: public StackwalkerX86Fixture, public Test { };
michael@0 146
michael@0 147 TEST_F(SanityCheck, NoResolver) {
michael@0 148 stack_section.start() = 0x80000000;
michael@0 149 stack_section.D32(0).D32(0); // end-of-stack marker
michael@0 150 RegionFromSection();
michael@0 151 raw_context.eip = 0x40000200;
michael@0 152 raw_context.ebp = 0x80000000;
michael@0 153
michael@0 154 StackFrameSymbolizer frame_symbolizer(NULL, NULL);
michael@0 155 StackwalkerX86 walker(&system_info, &raw_context, &stack_region, &modules,
michael@0 156 &frame_symbolizer);
michael@0 157 // This should succeed, even without a resolver or supplier.
michael@0 158 vector<const CodeModule*> modules_without_symbols;
michael@0 159 ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols));
michael@0 160 ASSERT_EQ(1U, modules_without_symbols.size());
michael@0 161 ASSERT_EQ("module1", modules_without_symbols[0]->debug_file());
michael@0 162 frames = call_stack.frames();
michael@0 163 StackFrameX86 *frame = static_cast<StackFrameX86 *>(frames->at(0));
michael@0 164 // Check that the values from the original raw context made it
michael@0 165 // through to the context in the stack frame.
michael@0 166 EXPECT_EQ(0, memcmp(&raw_context, &frame->context, sizeof(raw_context)));
michael@0 167 }
michael@0 168
michael@0 169 class GetContextFrame: public StackwalkerX86Fixture, public Test { };
michael@0 170
michael@0 171 TEST_F(GetContextFrame, Simple) {
michael@0 172 stack_section.start() = 0x80000000;
michael@0 173 stack_section.D32(0).D32(0); // end-of-stack marker
michael@0 174 RegionFromSection();
michael@0 175 raw_context.eip = 0x40000200;
michael@0 176 raw_context.ebp = 0x80000000;
michael@0 177
michael@0 178 StackFrameSymbolizer frame_symbolizer(&supplier, &resolver);
michael@0 179 StackwalkerX86 walker(&system_info, &raw_context, &stack_region, &modules,
michael@0 180 &frame_symbolizer);
michael@0 181 vector<const CodeModule*> modules_without_symbols;
michael@0 182 ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols));
michael@0 183 ASSERT_EQ(1U, modules_without_symbols.size());
michael@0 184 ASSERT_EQ("module1", modules_without_symbols[0]->debug_file());
michael@0 185 frames = call_stack.frames();
michael@0 186 StackFrameX86 *frame = static_cast<StackFrameX86 *>(frames->at(0));
michael@0 187 // Check that the values from the original raw context made it
michael@0 188 // through to the context in the stack frame.
michael@0 189 EXPECT_EQ(0, memcmp(&raw_context, &frame->context, sizeof(raw_context)));
michael@0 190 }
michael@0 191
michael@0 192 // The stackwalker should be able to produce the context frame even
michael@0 193 // without stack memory present.
michael@0 194 TEST_F(GetContextFrame, NoStackMemory) {
michael@0 195 raw_context.eip = 0x40000200;
michael@0 196 raw_context.ebp = 0x80000000;
michael@0 197
michael@0 198 StackFrameSymbolizer frame_symbolizer(&supplier, &resolver);
michael@0 199 StackwalkerX86 walker(&system_info, &raw_context, NULL, &modules,
michael@0 200 &frame_symbolizer);
michael@0 201 vector<const CodeModule*> modules_without_symbols;
michael@0 202 ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols));
michael@0 203 ASSERT_EQ(1U, modules_without_symbols.size());
michael@0 204 ASSERT_EQ("module1", modules_without_symbols[0]->debug_file());
michael@0 205 frames = call_stack.frames();
michael@0 206 StackFrameX86 *frame = static_cast<StackFrameX86 *>(frames->at(0));
michael@0 207 // Check that the values from the original raw context made it
michael@0 208 // through to the context in the stack frame.
michael@0 209 EXPECT_EQ(0, memcmp(&raw_context, &frame->context, sizeof(raw_context)));
michael@0 210 }
michael@0 211
michael@0 212 class GetCallerFrame: public StackwalkerX86Fixture, public Test { };
michael@0 213
michael@0 214 // Walk a traditional frame. A traditional frame saves the caller's
michael@0 215 // %ebp just below the return address, and has its own %ebp pointing
michael@0 216 // at the saved %ebp.
michael@0 217 TEST_F(GetCallerFrame, Traditional) {
michael@0 218 stack_section.start() = 0x80000000;
michael@0 219 Label frame0_ebp, frame1_ebp;
michael@0 220 stack_section
michael@0 221 .Append(12, 0) // frame 0: space
michael@0 222 .Mark(&frame0_ebp) // frame 0 %ebp points here
michael@0 223 .D32(frame1_ebp) // frame 0: saved %ebp
michael@0 224 .D32(0x40008679) // frame 0: return address
michael@0 225 .Append(8, 0) // frame 1: space
michael@0 226 .Mark(&frame1_ebp) // frame 1 %ebp points here
michael@0 227 .D32(0) // frame 1: saved %ebp (stack end)
michael@0 228 .D32(0); // frame 1: return address (stack end)
michael@0 229 RegionFromSection();
michael@0 230 raw_context.eip = 0x4000c7a5;
michael@0 231 raw_context.esp = stack_section.start().Value();
michael@0 232 raw_context.ebp = frame0_ebp.Value();
michael@0 233
michael@0 234 StackFrameSymbolizer frame_symbolizer(&supplier, &resolver);
michael@0 235 StackwalkerX86 walker(&system_info, &raw_context, &stack_region, &modules,
michael@0 236 &frame_symbolizer);
michael@0 237 vector<const CodeModule*> modules_without_symbols;
michael@0 238 ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols));
michael@0 239 ASSERT_EQ(1U, modules_without_symbols.size());
michael@0 240 ASSERT_EQ("module1", modules_without_symbols[0]->debug_file());
michael@0 241 frames = call_stack.frames();
michael@0 242 ASSERT_EQ(2U, frames->size());
michael@0 243
michael@0 244 { // To avoid reusing locals by mistake
michael@0 245 StackFrameX86 *frame0 = static_cast<StackFrameX86 *>(frames->at(0));
michael@0 246 EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust);
michael@0 247 EXPECT_EQ(StackFrameX86::CONTEXT_VALID_ALL, frame0->context_validity);
michael@0 248 EXPECT_EQ(0x4000c7a5U, frame0->instruction);
michael@0 249 EXPECT_EQ(0x4000c7a5U, frame0->context.eip);
michael@0 250 EXPECT_EQ(frame0_ebp.Value(), frame0->context.ebp);
michael@0 251 EXPECT_EQ(NULL, frame0->windows_frame_info);
michael@0 252 }
michael@0 253
michael@0 254 { // To avoid reusing locals by mistake
michael@0 255 StackFrameX86 *frame1 = static_cast<StackFrameX86 *>(frames->at(1));
michael@0 256 EXPECT_EQ(StackFrame::FRAME_TRUST_FP, frame1->trust);
michael@0 257 ASSERT_EQ((StackFrameX86::CONTEXT_VALID_EIP
michael@0 258 | StackFrameX86::CONTEXT_VALID_ESP
michael@0 259 | StackFrameX86::CONTEXT_VALID_EBP),
michael@0 260 frame1->context_validity);
michael@0 261 EXPECT_EQ(0x40008679U, frame1->instruction + 1);
michael@0 262 EXPECT_EQ(0x40008679U, frame1->context.eip);
michael@0 263 EXPECT_EQ(frame1_ebp.Value(), frame1->context.ebp);
michael@0 264 EXPECT_EQ(NULL, frame1->windows_frame_info);
michael@0 265 }
michael@0 266 }
michael@0 267
michael@0 268 // Walk a traditional frame, but use a bogus %ebp value, forcing a scan
michael@0 269 // of the stack for something that looks like a return address.
michael@0 270 TEST_F(GetCallerFrame, TraditionalScan) {
michael@0 271 stack_section.start() = 0x80000000;
michael@0 272 Label frame1_ebp;
michael@0 273 stack_section
michael@0 274 // frame 0
michael@0 275 .D32(0xf065dc76) // locals area:
michael@0 276 .D32(0x46ee2167) // garbage that doesn't look like
michael@0 277 .D32(0xbab023ec) // a return address
michael@0 278 .D32(frame1_ebp) // saved %ebp (%ebp fails to point here, forcing scan)
michael@0 279 .D32(0x4000129d) // return address
michael@0 280 // frame 1
michael@0 281 .Append(8, 0) // space
michael@0 282 .Mark(&frame1_ebp) // %ebp points here
michael@0 283 .D32(0) // saved %ebp (stack end)
michael@0 284 .D32(0); // return address (stack end)
michael@0 285
michael@0 286 RegionFromSection();
michael@0 287 raw_context.eip = 0x4000f49d;
michael@0 288 raw_context.esp = stack_section.start().Value();
michael@0 289 // Make the frame pointer bogus, to make the stackwalker scan the stack
michael@0 290 // for something that looks like a return address.
michael@0 291 raw_context.ebp = 0xd43eed6e;
michael@0 292
michael@0 293 StackFrameSymbolizer frame_symbolizer(&supplier, &resolver);
michael@0 294 StackwalkerX86 walker(&system_info, &raw_context, &stack_region, &modules,
michael@0 295 &frame_symbolizer);
michael@0 296 vector<const CodeModule*> modules_without_symbols;
michael@0 297 ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols));
michael@0 298 ASSERT_EQ(1U, modules_without_symbols.size());
michael@0 299 ASSERT_EQ("module1", modules_without_symbols[0]->debug_file());
michael@0 300 frames = call_stack.frames();
michael@0 301 ASSERT_EQ(2U, frames->size());
michael@0 302
michael@0 303 { // To avoid reusing locals by mistake
michael@0 304 StackFrameX86 *frame0 = static_cast<StackFrameX86 *>(frames->at(0));
michael@0 305 EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust);
michael@0 306 ASSERT_EQ(StackFrameX86::CONTEXT_VALID_ALL, frame0->context_validity);
michael@0 307 EXPECT_EQ(0x4000f49dU, frame0->instruction);
michael@0 308 EXPECT_EQ(0x4000f49dU, frame0->context.eip);
michael@0 309 EXPECT_EQ(stack_section.start().Value(), frame0->context.esp);
michael@0 310 EXPECT_EQ(0xd43eed6eU, frame0->context.ebp);
michael@0 311 EXPECT_EQ(NULL, frame0->windows_frame_info);
michael@0 312 }
michael@0 313
michael@0 314 { // To avoid reusing locals by mistake
michael@0 315 StackFrameX86 *frame1 = static_cast<StackFrameX86 *>(frames->at(1));
michael@0 316 EXPECT_EQ(StackFrame::FRAME_TRUST_SCAN, frame1->trust);
michael@0 317 // I'd argue that CONTEXT_VALID_EBP shouldn't be here, since the
michael@0 318 // walker does not actually fetch the EBP after a scan (forcing the
michael@0 319 // next frame to be scanned as well). But let's grandfather the existing
michael@0 320 // behavior in for now.
michael@0 321 ASSERT_EQ((StackFrameX86::CONTEXT_VALID_EIP
michael@0 322 | StackFrameX86::CONTEXT_VALID_ESP
michael@0 323 | StackFrameX86::CONTEXT_VALID_EBP),
michael@0 324 frame1->context_validity);
michael@0 325 EXPECT_EQ(0x4000129dU, frame1->instruction + 1);
michael@0 326 EXPECT_EQ(0x4000129dU, frame1->context.eip);
michael@0 327 EXPECT_EQ(0x80000014U, frame1->context.esp);
michael@0 328 EXPECT_EQ(0xd43eed6eU, frame1->context.ebp);
michael@0 329 EXPECT_EQ(NULL, frame1->windows_frame_info);
michael@0 330 }
michael@0 331 }
michael@0 332
michael@0 333 // Force scanning for a return address a long way down the stack
michael@0 334 TEST_F(GetCallerFrame, TraditionalScanLongWay) {
michael@0 335 stack_section.start() = 0x80000000;
michael@0 336 Label frame1_ebp;
michael@0 337 stack_section
michael@0 338 // frame 0
michael@0 339 .D32(0xf065dc76) // locals area:
michael@0 340 .D32(0x46ee2167) // garbage that doesn't look like
michael@0 341 .D32(0xbab023ec) // a return address
michael@0 342 .Append(20 * 4, 0) // a bunch of space
michael@0 343 .D32(frame1_ebp) // saved %ebp (%ebp fails to point here, forcing scan)
michael@0 344 .D32(0x4000129d) // return address
michael@0 345 // frame 1
michael@0 346 .Append(8, 0) // space
michael@0 347 .Mark(&frame1_ebp) // %ebp points here
michael@0 348 .D32(0) // saved %ebp (stack end)
michael@0 349 .D32(0); // return address (stack end)
michael@0 350
michael@0 351 RegionFromSection();
michael@0 352 raw_context.eip = 0x4000f49d;
michael@0 353 raw_context.esp = stack_section.start().Value();
michael@0 354 // Make the frame pointer bogus, to make the stackwalker scan the stack
michael@0 355 // for something that looks like a return address.
michael@0 356 raw_context.ebp = 0xd43eed6e;
michael@0 357
michael@0 358 StackFrameSymbolizer frame_symbolizer(&supplier, &resolver);
michael@0 359 StackwalkerX86 walker(&system_info, &raw_context, &stack_region, &modules,
michael@0 360 &frame_symbolizer);
michael@0 361 vector<const CodeModule*> modules_without_symbols;
michael@0 362 ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols));
michael@0 363 ASSERT_EQ(1U, modules_without_symbols.size());
michael@0 364 ASSERT_EQ("module1", modules_without_symbols[0]->debug_file());
michael@0 365 frames = call_stack.frames();
michael@0 366 ASSERT_EQ(2U, frames->size());
michael@0 367
michael@0 368 { // To avoid reusing locals by mistake
michael@0 369 StackFrameX86 *frame0 = static_cast<StackFrameX86 *>(frames->at(0));
michael@0 370 EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust);
michael@0 371 ASSERT_EQ(StackFrameX86::CONTEXT_VALID_ALL, frame0->context_validity);
michael@0 372 EXPECT_EQ(0x4000f49dU, frame0->instruction);
michael@0 373 EXPECT_EQ(0x4000f49dU, frame0->context.eip);
michael@0 374 EXPECT_EQ(stack_section.start().Value(), frame0->context.esp);
michael@0 375 EXPECT_EQ(0xd43eed6eU, frame0->context.ebp);
michael@0 376 EXPECT_EQ(NULL, frame0->windows_frame_info);
michael@0 377 }
michael@0 378
michael@0 379 { // To avoid reusing locals by mistake
michael@0 380 StackFrameX86 *frame1 = static_cast<StackFrameX86 *>(frames->at(1));
michael@0 381 EXPECT_EQ(StackFrame::FRAME_TRUST_SCAN, frame1->trust);
michael@0 382 // I'd argue that CONTEXT_VALID_EBP shouldn't be here, since the
michael@0 383 // walker does not actually fetch the EBP after a scan (forcing the
michael@0 384 // next frame to be scanned as well). But let's grandfather the existing
michael@0 385 // behavior in for now.
michael@0 386 ASSERT_EQ((StackFrameX86::CONTEXT_VALID_EIP
michael@0 387 | StackFrameX86::CONTEXT_VALID_ESP
michael@0 388 | StackFrameX86::CONTEXT_VALID_EBP),
michael@0 389 frame1->context_validity);
michael@0 390 EXPECT_EQ(0x4000129dU, frame1->instruction + 1);
michael@0 391 EXPECT_EQ(0x4000129dU, frame1->context.eip);
michael@0 392 EXPECT_EQ(0x80000064U, frame1->context.esp);
michael@0 393 EXPECT_EQ(0xd43eed6eU, frame1->context.ebp);
michael@0 394 EXPECT_EQ(NULL, frame1->windows_frame_info);
michael@0 395 }
michael@0 396 }
michael@0 397
michael@0 398 // Use Windows frame data (a "STACK WIN 4" record, from a
michael@0 399 // FrameTypeFrameData DIA record) to walk a stack frame.
michael@0 400 TEST_F(GetCallerFrame, WindowsFrameData) {
michael@0 401 SetModuleSymbols(&module1,
michael@0 402 "STACK WIN 4 aa85 176 0 0 4 10 4 0 1"
michael@0 403 " $T2 $esp .cbSavedRegs + ="
michael@0 404 " $T0 .raSearchStart ="
michael@0 405 " $eip $T0 ^ ="
michael@0 406 " $esp $T0 4 + ="
michael@0 407 " $ebx $T2 4 - ^ ="
michael@0 408 " $edi $T2 8 - ^ ="
michael@0 409 " $esi $T2 12 - ^ ="
michael@0 410 " $ebp $T2 16 - ^ =\n");
michael@0 411 Label frame1_esp, frame1_ebp;
michael@0 412 stack_section.start() = 0x80000000;
michael@0 413 stack_section
michael@0 414 // frame 0
michael@0 415 .D32(frame1_ebp) // saved regs: %ebp
michael@0 416 .D32(0xa7120d1a) // %esi
michael@0 417 .D32(0x630891be) // %edi
michael@0 418 .D32(0x9068a878) // %ebx
michael@0 419 .D32(0xa08ea45f) // locals: unused
michael@0 420 .D32(0x40001350) // return address
michael@0 421 // frame 1
michael@0 422 .Mark(&frame1_esp)
michael@0 423 .Append(12, 0) // empty space
michael@0 424 .Mark(&frame1_ebp)
michael@0 425 .D32(0) // saved %ebp (stack end)
michael@0 426 .D32(0); // saved %eip (stack end)
michael@0 427
michael@0 428 RegionFromSection();
michael@0 429 raw_context.eip = 0x4000aa85;
michael@0 430 raw_context.esp = stack_section.start().Value();
michael@0 431 raw_context.ebp = 0xf052c1de; // should not be needed to walk frame
michael@0 432
michael@0 433 StackFrameSymbolizer frame_symbolizer(&supplier, &resolver);
michael@0 434 StackwalkerX86 walker(&system_info, &raw_context, &stack_region, &modules,
michael@0 435 &frame_symbolizer);
michael@0 436 vector<const CodeModule*> modules_without_symbols;
michael@0 437 ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols));
michael@0 438 ASSERT_EQ(0U, modules_without_symbols.size());
michael@0 439 frames = call_stack.frames();
michael@0 440 ASSERT_EQ(2U, frames->size());
michael@0 441
michael@0 442 { // To avoid reusing locals by mistake
michael@0 443 StackFrameX86 *frame0 = static_cast<StackFrameX86 *>(frames->at(0));
michael@0 444 EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust);
michael@0 445 ASSERT_EQ(StackFrameX86::CONTEXT_VALID_ALL, frame0->context_validity);
michael@0 446 EXPECT_EQ(0x4000aa85U, frame0->instruction);
michael@0 447 EXPECT_EQ(0x4000aa85U, frame0->context.eip);
michael@0 448 EXPECT_EQ(stack_section.start().Value(), frame0->context.esp);
michael@0 449 EXPECT_EQ(0xf052c1deU, frame0->context.ebp);
michael@0 450 EXPECT_TRUE(frame0->windows_frame_info != NULL);
michael@0 451 }
michael@0 452
michael@0 453 { // To avoid reusing locals by mistake
michael@0 454 StackFrameX86 *frame1 = static_cast<StackFrameX86 *>(frames->at(1));
michael@0 455 EXPECT_EQ(StackFrame::FRAME_TRUST_CFI, frame1->trust);
michael@0 456 ASSERT_EQ((StackFrameX86::CONTEXT_VALID_EIP
michael@0 457 | StackFrameX86::CONTEXT_VALID_ESP
michael@0 458 | StackFrameX86::CONTEXT_VALID_EBP
michael@0 459 | StackFrameX86::CONTEXT_VALID_EBX
michael@0 460 | StackFrameX86::CONTEXT_VALID_ESI
michael@0 461 | StackFrameX86::CONTEXT_VALID_EDI),
michael@0 462 frame1->context_validity);
michael@0 463 EXPECT_EQ(0x40001350U, frame1->instruction + 1);
michael@0 464 EXPECT_EQ(0x40001350U, frame1->context.eip);
michael@0 465 EXPECT_EQ(frame1_esp.Value(), frame1->context.esp);
michael@0 466 EXPECT_EQ(frame1_ebp.Value(), frame1->context.ebp);
michael@0 467 EXPECT_EQ(0x9068a878U, frame1->context.ebx);
michael@0 468 EXPECT_EQ(0xa7120d1aU, frame1->context.esi);
michael@0 469 EXPECT_EQ(0x630891beU, frame1->context.edi);
michael@0 470 EXPECT_EQ(NULL, frame1->windows_frame_info);
michael@0 471 }
michael@0 472 }
michael@0 473
michael@0 474 // Use Windows frame data (a "STACK WIN 4" record, from a
michael@0 475 // FrameTypeFrameData DIA record) to walk a stack frame where the stack
michael@0 476 // is aligned and we must search
michael@0 477 TEST_F(GetCallerFrame, WindowsFrameDataAligned) {
michael@0 478 SetModuleSymbols(&module1,
michael@0 479 "STACK WIN 4 aa85 176 0 0 4 4 8 0 1"
michael@0 480 " $T1 .raSearch ="
michael@0 481 " $T0 $T1 4 - 8 @ ="
michael@0 482 " $ebp $T1 4 - ^ ="
michael@0 483 " $eip $T1 ^ ="
michael@0 484 " $esp $T1 4 + =");
michael@0 485 Label frame1_esp, frame1_ebp;
michael@0 486 stack_section.start() = 0x80000000;
michael@0 487 stack_section
michael@0 488 // frame 0
michael@0 489 .D32(0x0ffa0ffa) // unused saved register
michael@0 490 .D32(0xdeaddead) // locals
michael@0 491 .D32(0xbeefbeef)
michael@0 492 .D32(0) // 8-byte alignment
michael@0 493 .D32(frame1_ebp)
michael@0 494 .D32(0x5000129d) // return address
michael@0 495 // frame 1
michael@0 496 .Mark(&frame1_esp)
michael@0 497 .D32(0x1) // parameter
michael@0 498 .Mark(&frame1_ebp)
michael@0 499 .D32(0) // saved %ebp (stack end)
michael@0 500 .D32(0); // saved %eip (stack end)
michael@0 501
michael@0 502 RegionFromSection();
michael@0 503 raw_context.eip = 0x4000aa85;
michael@0 504 raw_context.esp = stack_section.start().Value();
michael@0 505 raw_context.ebp = 0xf052c1de; // should not be needed to walk frame
michael@0 506
michael@0 507 StackFrameSymbolizer frame_symbolizer(&supplier, &resolver);
michael@0 508 StackwalkerX86 walker(&system_info, &raw_context, &stack_region, &modules,
michael@0 509 &frame_symbolizer);
michael@0 510 vector<const CodeModule*> modules_without_symbols;
michael@0 511 ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols));
michael@0 512 ASSERT_EQ(1U, modules_without_symbols.size());
michael@0 513 ASSERT_EQ("module2", modules_without_symbols[0]->debug_file());
michael@0 514 frames = call_stack.frames();
michael@0 515 ASSERT_EQ(2U, frames->size());
michael@0 516
michael@0 517 { // To avoid reusing locals by mistake
michael@0 518 StackFrameX86 *frame0 = static_cast<StackFrameX86 *>(frames->at(0));
michael@0 519 EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust);
michael@0 520 ASSERT_EQ(StackFrameX86::CONTEXT_VALID_ALL, frame0->context_validity);
michael@0 521 EXPECT_EQ(0x4000aa85U, frame0->instruction);
michael@0 522 EXPECT_EQ(0x4000aa85U, frame0->context.eip);
michael@0 523 EXPECT_EQ(stack_section.start().Value(), frame0->context.esp);
michael@0 524 EXPECT_EQ(0xf052c1deU, frame0->context.ebp);
michael@0 525 EXPECT_TRUE(frame0->windows_frame_info != NULL);
michael@0 526 }
michael@0 527
michael@0 528 { // To avoid reusing locals by mistake
michael@0 529 StackFrameX86 *frame1 = static_cast<StackFrameX86 *>(frames->at(1));
michael@0 530 EXPECT_EQ(StackFrame::FRAME_TRUST_CFI, frame1->trust);
michael@0 531 ASSERT_EQ((StackFrameX86::CONTEXT_VALID_EIP
michael@0 532 | StackFrameX86::CONTEXT_VALID_ESP
michael@0 533 | StackFrameX86::CONTEXT_VALID_EBP),
michael@0 534 frame1->context_validity);
michael@0 535 EXPECT_EQ(0x5000129dU, frame1->instruction + 1);
michael@0 536 EXPECT_EQ(0x5000129dU, frame1->context.eip);
michael@0 537 EXPECT_EQ(frame1_esp.Value(), frame1->context.esp);
michael@0 538 EXPECT_EQ(frame1_ebp.Value(), frame1->context.ebp);
michael@0 539 EXPECT_EQ(NULL, frame1->windows_frame_info);
michael@0 540 }
michael@0 541 }
michael@0 542
michael@0 543 // Use Windows frame data (a "STACK WIN 4" record, from a
michael@0 544 // FrameTypeFrameData DIA record) to walk a frame, and depend on the
michael@0 545 // parameter size from the callee as well.
michael@0 546 TEST_F(GetCallerFrame, WindowsFrameDataParameterSize) {
michael@0 547 SetModuleSymbols(&module1, "FUNC 1000 100 c module1::wheedle\n");
michael@0 548 SetModuleSymbols(&module2,
michael@0 549 // Note bogus parameter size in FUNC record; the stack walker
michael@0 550 // should prefer the STACK WIN record, and see '4' below.
michael@0 551 "FUNC aa85 176 beef module2::whine\n"
michael@0 552 "STACK WIN 4 aa85 176 0 0 4 10 4 0 1"
michael@0 553 " $T2 $esp .cbLocals + .cbSavedRegs + ="
michael@0 554 " $T0 .raSearchStart ="
michael@0 555 " $eip $T0 ^ ="
michael@0 556 " $esp $T0 4 + ="
michael@0 557 " $ebp $T0 20 - ^ ="
michael@0 558 " $ebx $T0 8 - ^ =\n");
michael@0 559 Label frame0_esp, frame0_ebp;
michael@0 560 Label frame1_esp;
michael@0 561 Label frame2_esp, frame2_ebp;
michael@0 562 stack_section.start() = 0x80000000;
michael@0 563 stack_section
michael@0 564 // frame 0, in module1::wheedle. Traditional frame.
michael@0 565 .Mark(&frame0_esp)
michael@0 566 .Append(16, 0) // frame space
michael@0 567 .Mark(&frame0_ebp)
michael@0 568 .D32(0x6fa902e0) // saved %ebp. Not a frame pointer.
michael@0 569 .D32(0x5000aa95) // return address, in module2::whine
michael@0 570 // frame 1, in module2::whine. FrameData frame.
michael@0 571 .Mark(&frame1_esp)
michael@0 572 .D32(0xbaa0cb7a) // argument 3 passed to module1::wheedle
michael@0 573 .D32(0xbdc92f9f) // argument 2
michael@0 574 .D32(0x0b1d8442) // argument 1
michael@0 575 .D32(frame2_ebp) // saved %ebp
michael@0 576 .D32(0xb1b90a15) // unused
michael@0 577 .D32(0xf18e072d) // unused
michael@0 578 .D32(0x2558c7f3) // saved %ebx
michael@0 579 .D32(0x0365e25e) // unused
michael@0 580 .D32(0x2a179e38) // return address; $T0 points here
michael@0 581 // frame 2, in no module
michael@0 582 .Mark(&frame2_esp)
michael@0 583 .Append(12, 0) // empty space
michael@0 584 .Mark(&frame2_ebp)
michael@0 585 .D32(0) // saved %ebp (stack end)
michael@0 586 .D32(0); // saved %eip (stack end)
michael@0 587
michael@0 588 RegionFromSection();
michael@0 589 raw_context.eip = 0x40001004; // in module1::wheedle
michael@0 590 raw_context.esp = stack_section.start().Value();
michael@0 591 raw_context.ebp = frame0_ebp.Value();
michael@0 592
michael@0 593 StackFrameSymbolizer frame_symbolizer(&supplier, &resolver);
michael@0 594 StackwalkerX86 walker(&system_info, &raw_context, &stack_region, &modules,
michael@0 595 &frame_symbolizer);
michael@0 596 vector<const CodeModule*> modules_without_symbols;
michael@0 597 ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols));
michael@0 598 ASSERT_EQ(0U, modules_without_symbols.size());
michael@0 599 frames = call_stack.frames();
michael@0 600 ASSERT_EQ(3U, frames->size());
michael@0 601
michael@0 602 { // To avoid reusing locals by mistake
michael@0 603 StackFrameX86 *frame0 = static_cast<StackFrameX86 *>(frames->at(0));
michael@0 604 EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust);
michael@0 605 ASSERT_EQ(StackFrameX86::CONTEXT_VALID_ALL, frame0->context_validity);
michael@0 606 EXPECT_EQ(0x40001004U, frame0->instruction);
michael@0 607 EXPECT_EQ(0x40001004U, frame0->context.eip);
michael@0 608 EXPECT_EQ(frame0_esp.Value(), frame0->context.esp);
michael@0 609 EXPECT_EQ(frame0_ebp.Value(), frame0->context.ebp);
michael@0 610 EXPECT_EQ(&module1, frame0->module);
michael@0 611 EXPECT_EQ("module1::wheedle", frame0->function_name);
michael@0 612 EXPECT_EQ(0x40001000U, frame0->function_base);
michael@0 613 // The FUNC record for module1::wheedle should have produced a
michael@0 614 // WindowsFrameInfo structure with only the parameter size valid.
michael@0 615 ASSERT_TRUE(frame0->windows_frame_info != NULL);
michael@0 616 EXPECT_EQ(WindowsFrameInfo::VALID_PARAMETER_SIZE,
michael@0 617 frame0->windows_frame_info->valid);
michael@0 618 EXPECT_EQ(WindowsFrameInfo::STACK_INFO_UNKNOWN,
michael@0 619 frame0->windows_frame_info->type_);
michael@0 620 EXPECT_EQ(12U, frame0->windows_frame_info->parameter_size);
michael@0 621 }
michael@0 622
michael@0 623 { // To avoid reusing locals by mistake
michael@0 624 StackFrameX86 *frame1 = static_cast<StackFrameX86 *>(frames->at(1));
michael@0 625 EXPECT_EQ(StackFrame::FRAME_TRUST_FP, frame1->trust);
michael@0 626 ASSERT_EQ((StackFrameX86::CONTEXT_VALID_EIP
michael@0 627 | StackFrameX86::CONTEXT_VALID_ESP
michael@0 628 | StackFrameX86::CONTEXT_VALID_EBP),
michael@0 629 frame1->context_validity);
michael@0 630 EXPECT_EQ(0x5000aa95U, frame1->instruction + 1);
michael@0 631 EXPECT_EQ(0x5000aa95U, frame1->context.eip);
michael@0 632 EXPECT_EQ(frame1_esp.Value(), frame1->context.esp);
michael@0 633 EXPECT_EQ(0x6fa902e0U, frame1->context.ebp);
michael@0 634 EXPECT_EQ(&module2, frame1->module);
michael@0 635 EXPECT_EQ("module2::whine", frame1->function_name);
michael@0 636 EXPECT_EQ(0x5000aa85U, frame1->function_base);
michael@0 637 ASSERT_TRUE(frame1->windows_frame_info != NULL);
michael@0 638 EXPECT_EQ(WindowsFrameInfo::VALID_ALL, frame1->windows_frame_info->valid);
michael@0 639 EXPECT_EQ(WindowsFrameInfo::STACK_INFO_FRAME_DATA,
michael@0 640 frame1->windows_frame_info->type_);
michael@0 641 // This should not see the 0xbeef parameter size from the FUNC
michael@0 642 // record, but should instead see the STACK WIN record.
michael@0 643 EXPECT_EQ(4U, frame1->windows_frame_info->parameter_size);
michael@0 644 }
michael@0 645
michael@0 646 { // To avoid reusing locals by mistake
michael@0 647 StackFrameX86 *frame2 = static_cast<StackFrameX86 *>(frames->at(2));
michael@0 648 EXPECT_EQ(StackFrame::FRAME_TRUST_CFI, frame2->trust);
michael@0 649 ASSERT_EQ((StackFrameX86::CONTEXT_VALID_EIP
michael@0 650 | StackFrameX86::CONTEXT_VALID_ESP
michael@0 651 | StackFrameX86::CONTEXT_VALID_EBP
michael@0 652 | StackFrameX86::CONTEXT_VALID_EBX),
michael@0 653 frame2->context_validity);
michael@0 654 EXPECT_EQ(0x2a179e38U, frame2->instruction + 1);
michael@0 655 EXPECT_EQ(0x2a179e38U, frame2->context.eip);
michael@0 656 EXPECT_EQ(frame2_esp.Value(), frame2->context.esp);
michael@0 657 EXPECT_EQ(frame2_ebp.Value(), frame2->context.ebp);
michael@0 658 EXPECT_EQ(0x2558c7f3U, frame2->context.ebx);
michael@0 659 EXPECT_EQ(NULL, frame2->module);
michael@0 660 EXPECT_EQ(NULL, frame2->windows_frame_info);
michael@0 661 }
michael@0 662 }
michael@0 663
michael@0 664 // Use Windows frame data (a "STACK WIN 4" record, from a
michael@0 665 // FrameTypeFrameData DIA record) to walk a stack frame, where the
michael@0 666 // expression fails to yield both an $eip and an $ebp value, and the stack
michael@0 667 // walker must scan.
michael@0 668 TEST_F(GetCallerFrame, WindowsFrameDataScan) {
michael@0 669 SetModuleSymbols(&module1,
michael@0 670 "STACK WIN 4 c8c 111 0 0 4 10 4 0 1 bad program string\n");
michael@0 671 // Mark frame 1's PC as the end of the stack.
michael@0 672 SetModuleSymbols(&module2,
michael@0 673 "FUNC 7c38 accf 0 module2::function\n"
michael@0 674 "STACK WIN 4 7c38 accf 0 0 4 10 4 0 1 $eip 0 = $ebp 0 =\n");
michael@0 675 Label frame1_esp;
michael@0 676 stack_section.start() = 0x80000000;
michael@0 677 stack_section
michael@0 678 // frame 0
michael@0 679 .Append(16, 0x2a) // unused, garbage
michael@0 680 .D32(0x50007ce9) // return address
michael@0 681 // frame 1
michael@0 682 .Mark(&frame1_esp)
michael@0 683 .Append(8, 0); // empty space
michael@0 684
michael@0 685 RegionFromSection();
michael@0 686 raw_context.eip = 0x40000c9c;
michael@0 687 raw_context.esp = stack_section.start().Value();
michael@0 688 raw_context.ebp = 0x2ae314cd; // should not be needed to walk frame
michael@0 689
michael@0 690 StackFrameSymbolizer frame_symbolizer(&supplier, &resolver);
michael@0 691 StackwalkerX86 walker(&system_info, &raw_context, &stack_region, &modules,
michael@0 692 &frame_symbolizer);
michael@0 693 vector<const CodeModule*> modules_without_symbols;
michael@0 694 ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols));
michael@0 695 ASSERT_EQ(0U, modules_without_symbols.size());
michael@0 696 frames = call_stack.frames();
michael@0 697 ASSERT_EQ(2U, frames->size());
michael@0 698
michael@0 699 { // To avoid reusing locals by mistake
michael@0 700 StackFrameX86 *frame0 = static_cast<StackFrameX86 *>(frames->at(0));
michael@0 701 EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust);
michael@0 702 ASSERT_EQ(StackFrameX86::CONTEXT_VALID_ALL, frame0->context_validity);
michael@0 703 EXPECT_EQ(0x40000c9cU, frame0->instruction);
michael@0 704 EXPECT_EQ(0x40000c9cU, frame0->context.eip);
michael@0 705 EXPECT_EQ(stack_section.start().Value(), frame0->context.esp);
michael@0 706 EXPECT_EQ(0x2ae314cdU, frame0->context.ebp);
michael@0 707 EXPECT_TRUE(frame0->windows_frame_info != NULL);
michael@0 708 }
michael@0 709
michael@0 710 { // To avoid reusing locals by mistake
michael@0 711 StackFrameX86 *frame1 = static_cast<StackFrameX86 *>(frames->at(1));
michael@0 712 EXPECT_EQ(StackFrame::FRAME_TRUST_SCAN, frame1->trust);
michael@0 713 // I'd argue that CONTEXT_VALID_EBP shouldn't be here, since the walker
michael@0 714 // does not actually fetch the EBP after a scan (forcing the next frame
michael@0 715 // to be scanned as well). But let's grandfather the existing behavior in
michael@0 716 // for now.
michael@0 717 ASSERT_EQ((StackFrameX86::CONTEXT_VALID_EIP
michael@0 718 | StackFrameX86::CONTEXT_VALID_ESP
michael@0 719 | StackFrameX86::CONTEXT_VALID_EBP),
michael@0 720 frame1->context_validity);
michael@0 721 EXPECT_EQ(0x50007ce9U, frame1->instruction + 1);
michael@0 722 EXPECT_EQ(0x50007ce9U, frame1->context.eip);
michael@0 723 EXPECT_EQ(frame1_esp.Value(), frame1->context.esp);
michael@0 724 EXPECT_TRUE(frame1->windows_frame_info != NULL);
michael@0 725 }
michael@0 726 }
michael@0 727
michael@0 728 // Use Windows frame data (a "STACK WIN 4" record, from a
michael@0 729 // FrameTypeFrameData DIA record) to walk a stack frame, where the
michael@0 730 // expression yields an $eip that falls outside of any module, and the
michael@0 731 // stack walker must scan.
michael@0 732 TEST_F(GetCallerFrame, WindowsFrameDataBadEIPScan) {
michael@0 733 SetModuleSymbols(&module1,
michael@0 734 "STACK WIN 4 6e6 e7 0 0 0 8 4 0 1"
michael@0 735 // A traditional frame, actually.
michael@0 736 " $eip $ebp 4 + ^ = $esp $ebp 8 + = $ebp $ebp ^ =\n");
michael@0 737 // Mark frame 1's PC as the end of the stack.
michael@0 738 SetModuleSymbols(&module2,
michael@0 739 "FUNC cfdb 8406 0 module2::function\n"
michael@0 740 "STACK WIN 4 cfdb 8406 0 0 0 0 0 0 1 $eip 0 = $ebp 0 =\n");
michael@0 741 stack_section.start() = 0x80000000;
michael@0 742
michael@0 743 // In this stack, the context's %ebp is pointing at the wrong place, so
michael@0 744 // the stack walker needs to scan to find the return address, and then
michael@0 745 // scan again to find the caller's saved %ebp.
michael@0 746 Label frame0_ebp, frame1_ebp, frame1_esp;
michael@0 747 stack_section
michael@0 748 // frame 0
michael@0 749 .Append(8, 0x2a) // garbage
michael@0 750 .Mark(&frame0_ebp) // frame 0 %ebp points here, but should point
michael@0 751 // at *** below
michael@0 752 // The STACK WIN record says that the following two values are
michael@0 753 // frame 1's saved %ebp and return address, but the %ebp is wrong;
michael@0 754 // they're garbage. The stack walker will scan for the right values.
michael@0 755 .D32(0x3d937b2b) // alleged to be frame 1's saved %ebp
michael@0 756 .D32(0x17847f5b) // alleged to be frame 1's return address
michael@0 757 .D32(frame1_ebp) // frame 1's real saved %ebp; scan will find
michael@0 758 .D32(0x2b2b2b2b) // first word of realigned register save area
michael@0 759 // *** frame 0 %ebp ought to be pointing here
michael@0 760 .D32(0x2c2c2c2c) // realigned locals area
michael@0 761 .D32(0x5000d000) // frame 1's real saved %eip; scan will find
michael@0 762 // Frame 1, in module2::function. The STACK WIN record describes
michael@0 763 // this as the oldest frame, without referring to its contents, so
michael@0 764 // we needn't to provide any actual data here.
michael@0 765 .Mark(&frame1_esp)
michael@0 766 .Mark(&frame1_ebp) // frame 1 %ebp points here
michael@0 767 // A dummy value for frame 1's %ebp to point at. The scan recognizes the
michael@0 768 // saved %ebp because it points to a valid word in the stack memory region.
michael@0 769 .D32(0x2d2d2d2d);
michael@0 770
michael@0 771 RegionFromSection();
michael@0 772 raw_context.eip = 0x40000700;
michael@0 773 raw_context.esp = stack_section.start().Value();
michael@0 774 raw_context.ebp = frame0_ebp.Value();
michael@0 775
michael@0 776 StackFrameSymbolizer frame_symbolizer(&supplier, &resolver);
michael@0 777 StackwalkerX86 walker(&system_info, &raw_context, &stack_region, &modules,
michael@0 778 &frame_symbolizer);
michael@0 779 vector<const CodeModule*> modules_without_symbols;
michael@0 780 ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols));
michael@0 781 ASSERT_EQ(0U, modules_without_symbols.size());
michael@0 782 frames = call_stack.frames();
michael@0 783 ASSERT_EQ(2U, frames->size());
michael@0 784
michael@0 785 { // To avoid reusing locals by mistake
michael@0 786 StackFrameX86 *frame0 = static_cast<StackFrameX86 *>(frames->at(0));
michael@0 787 EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust);
michael@0 788 ASSERT_EQ(StackFrameX86::CONTEXT_VALID_ALL, frame0->context_validity);
michael@0 789 EXPECT_EQ(0x40000700U, frame0->instruction);
michael@0 790 EXPECT_EQ(0x40000700U, frame0->context.eip);
michael@0 791 EXPECT_EQ(stack_section.start().Value(), frame0->context.esp);
michael@0 792 EXPECT_EQ(frame0_ebp.Value(), frame0->context.ebp);
michael@0 793 EXPECT_TRUE(frame0->windows_frame_info != NULL);
michael@0 794 }
michael@0 795
michael@0 796 { // To avoid reusing locals by mistake
michael@0 797 StackFrameX86 *frame1 = static_cast<StackFrameX86 *>(frames->at(1));
michael@0 798 EXPECT_EQ(StackFrame::FRAME_TRUST_CFI_SCAN, frame1->trust);
michael@0 799 // I'd argue that CONTEXT_VALID_EBP shouldn't be here, since the
michael@0 800 // walker does not actually fetch the EBP after a scan (forcing the
michael@0 801 // next frame to be scanned as well). But let's grandfather the existing
michael@0 802 // behavior in for now.
michael@0 803 ASSERT_EQ((StackFrameX86::CONTEXT_VALID_EIP
michael@0 804 | StackFrameX86::CONTEXT_VALID_ESP
michael@0 805 | StackFrameX86::CONTEXT_VALID_EBP),
michael@0 806 frame1->context_validity);
michael@0 807 EXPECT_EQ(0x5000d000U, frame1->instruction + 1);
michael@0 808 EXPECT_EQ(0x5000d000U, frame1->context.eip);
michael@0 809 EXPECT_EQ(frame1_esp.Value(), frame1->context.esp);
michael@0 810 EXPECT_EQ(frame1_ebp.Value(), frame1->context.ebp);
michael@0 811 EXPECT_TRUE(frame1->windows_frame_info != NULL);
michael@0 812 }
michael@0 813 }
michael@0 814
michael@0 815 // Use Windows FrameTypeFPO data to walk a stack frame for a function that
michael@0 816 // does not modify %ebp from the value it had in the caller.
michael@0 817 TEST_F(GetCallerFrame, WindowsFPOUnchangedEBP) {
michael@0 818 SetModuleSymbols(&module1,
michael@0 819 // Note bogus parameter size in FUNC record; the walker
michael@0 820 // should prefer the STACK WIN record, and see the '8' below.
michael@0 821 "FUNC e8a8 100 feeb module1::discombobulated\n"
michael@0 822 "STACK WIN 0 e8a8 100 0 0 8 4 10 0 0 0\n");
michael@0 823 Label frame0_esp;
michael@0 824 Label frame1_esp, frame1_ebp;
michael@0 825 stack_section.start() = 0x80000000;
michael@0 826 stack_section
michael@0 827 // frame 0, in module1::wheedle. FrameTypeFPO (STACK WIN 0) frame.
michael@0 828 .Mark(&frame0_esp)
michael@0 829 // no outgoing parameters; this is the youngest frame.
michael@0 830 .D32(0x7c521352) // four bytes of saved registers
michael@0 831 .Append(0x10, 0x42) // local area
michael@0 832 .D32(0x40009b5b) // return address, in module1, no function
michael@0 833 // frame 1, in module1, no function.
michael@0 834 .Mark(&frame1_esp)
michael@0 835 .D32(0xf60ea7fc) // junk
michael@0 836 .Mark(&frame1_ebp)
michael@0 837 .D32(0) // saved %ebp (stack end)
michael@0 838 .D32(0); // saved %eip (stack end)
michael@0 839
michael@0 840 RegionFromSection();
michael@0 841 raw_context.eip = 0x4000e8b8; // in module1::whine
michael@0 842 raw_context.esp = stack_section.start().Value();
michael@0 843 // Frame pointer unchanged from caller.
michael@0 844 raw_context.ebp = frame1_ebp.Value();
michael@0 845
michael@0 846 StackFrameSymbolizer frame_symbolizer(&supplier, &resolver);
michael@0 847 StackwalkerX86 walker(&system_info, &raw_context, &stack_region, &modules,
michael@0 848 &frame_symbolizer);
michael@0 849 vector<const CodeModule*> modules_without_symbols;
michael@0 850 ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols));
michael@0 851 ASSERT_EQ(0U, modules_without_symbols.size());
michael@0 852 frames = call_stack.frames();
michael@0 853 ASSERT_EQ(2U, frames->size());
michael@0 854
michael@0 855 { // To avoid reusing locals by mistake
michael@0 856 StackFrameX86 *frame0 = static_cast<StackFrameX86 *>(frames->at(0));
michael@0 857 EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust);
michael@0 858 ASSERT_EQ(StackFrameX86::CONTEXT_VALID_ALL, frame0->context_validity);
michael@0 859 EXPECT_EQ(0x4000e8b8U, frame0->instruction);
michael@0 860 EXPECT_EQ(0x4000e8b8U, frame0->context.eip);
michael@0 861 EXPECT_EQ(frame0_esp.Value(), frame0->context.esp);
michael@0 862 EXPECT_EQ(frame1_ebp.Value(), frame0->context.ebp); // unchanged from caller
michael@0 863 EXPECT_EQ(&module1, frame0->module);
michael@0 864 EXPECT_EQ("module1::discombobulated", frame0->function_name);
michael@0 865 EXPECT_EQ(0x4000e8a8U, frame0->function_base);
michael@0 866 // The STACK WIN record for module1::discombobulated should have
michael@0 867 // produced a fully populated WindowsFrameInfo structure.
michael@0 868 ASSERT_TRUE(frame0->windows_frame_info != NULL);
michael@0 869 EXPECT_EQ(WindowsFrameInfo::VALID_ALL, frame0->windows_frame_info->valid);
michael@0 870 EXPECT_EQ(WindowsFrameInfo::STACK_INFO_FPO,
michael@0 871 frame0->windows_frame_info->type_);
michael@0 872 EXPECT_EQ(0x10U, frame0->windows_frame_info->local_size);
michael@0 873 }
michael@0 874
michael@0 875 { // To avoid reusing locals by mistake
michael@0 876 StackFrameX86 *frame1 = static_cast<StackFrameX86 *>(frames->at(1));
michael@0 877 EXPECT_EQ(StackFrame::FRAME_TRUST_CFI, frame1->trust);
michael@0 878 ASSERT_EQ((StackFrameX86::CONTEXT_VALID_EIP
michael@0 879 | StackFrameX86::CONTEXT_VALID_ESP
michael@0 880 | StackFrameX86::CONTEXT_VALID_EBP),
michael@0 881 frame1->context_validity);
michael@0 882 EXPECT_EQ(0x40009b5bU, frame1->instruction + 1);
michael@0 883 EXPECT_EQ(0x40009b5bU, frame1->context.eip);
michael@0 884 EXPECT_EQ(frame1_esp.Value(), frame1->context.esp);
michael@0 885 EXPECT_EQ(frame1_ebp.Value(), frame1->context.ebp);
michael@0 886 EXPECT_EQ(&module1, frame1->module);
michael@0 887 EXPECT_EQ("", frame1->function_name);
michael@0 888 EXPECT_EQ(NULL, frame1->windows_frame_info);
michael@0 889 }
michael@0 890 }
michael@0 891
michael@0 892 // Use Windows FrameTypeFPO data to walk a stack frame for a function
michael@0 893 // that uses %ebp for its own purposes, saving the value it had in the
michael@0 894 // caller in the standard place in the saved register area.
michael@0 895 TEST_F(GetCallerFrame, WindowsFPOUsedEBP) {
michael@0 896 SetModuleSymbols(&module1,
michael@0 897 // Note bogus parameter size in FUNC record; the walker
michael@0 898 // should prefer the STACK WIN record, and see the '8' below.
michael@0 899 "FUNC 9aa8 e6 abbe module1::RaisedByTheAliens\n"
michael@0 900 "STACK WIN 0 9aa8 e6 a 0 10 8 4 0 0 1\n");
michael@0 901 Label frame0_esp;
michael@0 902 Label frame1_esp, frame1_ebp;
michael@0 903 stack_section.start() = 0x80000000;
michael@0 904 stack_section
michael@0 905 // frame 0, in module1::wheedle. FrameTypeFPO (STACK WIN 0) frame.
michael@0 906 .Mark(&frame0_esp)
michael@0 907 // no outgoing parameters; this is the youngest frame.
michael@0 908 .D32(frame1_ebp) // saved register area: saved %ebp
michael@0 909 .D32(0xb68bd5f9) // saved register area: something else
michael@0 910 .D32(0xd25d05fc) // local area
michael@0 911 .D32(0x4000debe) // return address, in module1, no function
michael@0 912 // frame 1, in module1, no function.
michael@0 913 .Mark(&frame1_esp)
michael@0 914 .D32(0xf0c9a974) // junk
michael@0 915 .Mark(&frame1_ebp)
michael@0 916 .D32(0) // saved %ebp (stack end)
michael@0 917 .D32(0); // saved %eip (stack end)
michael@0 918
michael@0 919 RegionFromSection();
michael@0 920 raw_context.eip = 0x40009ab8; // in module1::RaisedByTheAliens
michael@0 921 raw_context.esp = stack_section.start().Value();
michael@0 922 // RaisedByTheAliens uses %ebp for its own mysterious purposes.
michael@0 923 raw_context.ebp = 0xecbdd1a5;
michael@0 924
michael@0 925 StackFrameSymbolizer frame_symbolizer(&supplier, &resolver);
michael@0 926 StackwalkerX86 walker(&system_info, &raw_context, &stack_region, &modules,
michael@0 927 &frame_symbolizer);
michael@0 928 vector<const CodeModule*> modules_without_symbols;
michael@0 929 ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols));
michael@0 930 ASSERT_EQ(0U, modules_without_symbols.size());
michael@0 931 frames = call_stack.frames();
michael@0 932 ASSERT_EQ(2U, frames->size());
michael@0 933
michael@0 934 { // To avoid reusing locals by mistake
michael@0 935 StackFrameX86 *frame0 = static_cast<StackFrameX86 *>(frames->at(0));
michael@0 936 EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust);
michael@0 937 ASSERT_EQ(StackFrameX86::CONTEXT_VALID_ALL, frame0->context_validity);
michael@0 938 EXPECT_EQ(0x40009ab8U, frame0->instruction);
michael@0 939 EXPECT_EQ(0x40009ab8U, frame0->context.eip);
michael@0 940 EXPECT_EQ(frame0_esp.Value(), frame0->context.esp);
michael@0 941 EXPECT_EQ(0xecbdd1a5, frame0->context.ebp);
michael@0 942 EXPECT_EQ(&module1, frame0->module);
michael@0 943 EXPECT_EQ("module1::RaisedByTheAliens", frame0->function_name);
michael@0 944 EXPECT_EQ(0x40009aa8U, frame0->function_base);
michael@0 945 // The STACK WIN record for module1::RaisedByTheAliens should have
michael@0 946 // produced a fully populated WindowsFrameInfo structure.
michael@0 947 ASSERT_TRUE(frame0->windows_frame_info != NULL);
michael@0 948 EXPECT_EQ(WindowsFrameInfo::VALID_ALL, frame0->windows_frame_info->valid);
michael@0 949 EXPECT_EQ(WindowsFrameInfo::STACK_INFO_FPO,
michael@0 950 frame0->windows_frame_info->type_);
michael@0 951 EXPECT_EQ("", frame0->windows_frame_info->program_string);
michael@0 952 EXPECT_TRUE(frame0->windows_frame_info->allocates_base_pointer);
michael@0 953 }
michael@0 954
michael@0 955 { // To avoid reusing locals by mistake
michael@0 956 StackFrameX86 *frame1 = static_cast<StackFrameX86 *>(frames->at(1));
michael@0 957 EXPECT_EQ(StackFrame::FRAME_TRUST_CFI, frame1->trust);
michael@0 958 ASSERT_EQ((StackFrameX86::CONTEXT_VALID_EIP
michael@0 959 | StackFrameX86::CONTEXT_VALID_ESP
michael@0 960 | StackFrameX86::CONTEXT_VALID_EBP),
michael@0 961 frame1->context_validity);
michael@0 962 EXPECT_EQ(0x4000debeU, frame1->instruction + 1);
michael@0 963 EXPECT_EQ(0x4000debeU, frame1->context.eip);
michael@0 964 EXPECT_EQ(frame1_esp.Value(), frame1->context.esp);
michael@0 965 EXPECT_EQ(frame1_ebp.Value(), frame1->context.ebp);
michael@0 966 EXPECT_EQ(&module1, frame1->module);
michael@0 967 EXPECT_EQ("", frame1->function_name);
michael@0 968 EXPECT_EQ(NULL, frame1->windows_frame_info);
michael@0 969 }
michael@0 970 }
michael@0 971
michael@0 972 // This is a regression unit test which covers a bug which has to do with
michael@0 973 // FPO-optimized Windows system call stubs in the context frame. There is
michael@0 974 // a more recent Windows system call dispatch mechanism which differs from
michael@0 975 // the one which is being tested here. The newer system call dispatch
michael@0 976 // mechanism creates an extra context frame (KiFastSystemCallRet).
michael@0 977 TEST_F(GetCallerFrame, WindowsFPOSystemCall) {
michael@0 978 SetModuleSymbols(&module3, // ntdll.dll
michael@0 979 "PUBLIC 1f8ac c ZwWaitForSingleObject\n"
michael@0 980 "STACK WIN 0 1f8ac 1b 0 0 c 0 0 0 0 0\n");
michael@0 981 SetModuleSymbols(&module4, // kernelbase.dll
michael@0 982 "PUBLIC 109f9 c WaitForSingleObjectEx\n"
michael@0 983 "PUBLIC 36590 0 _except_handler4\n"
michael@0 984 "STACK WIN 4 109f9 df c 0 c c 48 0 1 $T0 $ebp = $eip "
michael@0 985 "$T0 4 + ^ = $ebp $T0 ^ = $esp $T0 8 + = $L "
michael@0 986 "$T0 .cbSavedRegs - = $P $T0 8 + .cbParams + =\n"
michael@0 987 "STACK WIN 4 36590 154 17 0 10 0 14 0 1 $T0 $ebp = $eip "
michael@0 988 "$T0 4 + ^ = $ebp $T0 ^ = $esp $T0 8 + = $L $T0 "
michael@0 989 ".cbSavedRegs - = $P $T0 8 + .cbParams + =\n");
michael@0 990 SetModuleSymbols(&module5, // kernel32.dll
michael@0 991 "PUBLIC 11136 8 WaitForSingleObject\n"
michael@0 992 "PUBLIC 11151 c WaitForSingleObjectExImplementation\n"
michael@0 993 "STACK WIN 4 11136 16 5 0 8 0 0 0 1 $T0 $ebp = $eip "
michael@0 994 "$T0 4 + ^ = $ebp $T0 ^ = $esp $T0 8 + = $L "
michael@0 995 "$T0 .cbSavedRegs - = $P $T0 8 + .cbParams + =\n"
michael@0 996 "STACK WIN 4 11151 7a 5 0 c 0 0 0 1 $T0 $ebp = $eip "
michael@0 997 "$T0 4 + ^ = $ebp $T0 ^ = $esp $T0 8 + = $L "
michael@0 998 "$T0 .cbSavedRegs - = $P $T0 8 + .cbParams + =\n");
michael@0 999 SetModuleSymbols(&module6, // chrome.dll
michael@0 1000 "FILE 7038 some_file_name.h\n"
michael@0 1001 "FILE 839776 some_file_name.cc\n"
michael@0 1002 "FUNC 217fda 17 4 function_217fda\n"
michael@0 1003 "217fda 4 102 839776\n"
michael@0 1004 "FUNC 217ff1 a 4 function_217ff1\n"
michael@0 1005 "217ff1 0 594 7038\n"
michael@0 1006 "217ff1 a 596 7038\n"
michael@0 1007 "STACK WIN 0 217ff1 a 0 0 4 0 0 0 0 0\n");
michael@0 1008
michael@0 1009 Label frame0_esp, frame1_esp;
michael@0 1010 Label frame1_ebp, frame2_ebp, frame3_ebp;
michael@0 1011 stack_section.start() = 0x002ff290;
michael@0 1012 stack_section
michael@0 1013 .Mark(&frame0_esp)
michael@0 1014 .D32(0x771ef8c1) // EIP in frame 0 (system call)
michael@0 1015 .D32(0x75fa0a91) // return address of frame 0
michael@0 1016 .Mark(&frame1_esp)
michael@0 1017 .D32(0x000017b0) // args to child
michael@0 1018 .D32(0x00000000)
michael@0 1019 .D32(0x002ff2d8)
michael@0 1020 .D32(0x88014a2e)
michael@0 1021 .D32(0x002ff364)
michael@0 1022 .D32(0x000017b0)
michael@0 1023 .D32(0x00000000)
michael@0 1024 .D32(0x00000024)
michael@0 1025 .D32(0x00000001)
michael@0 1026 .D32(0x00000000)
michael@0 1027 .D32(0x00000000)
michael@0 1028 .D32(0x00000000)
michael@0 1029 .D32(0x00000000)
michael@0 1030 .D32(0x00000000)
michael@0 1031 .D32(0x00000000)
michael@0 1032 .D32(0x00000000)
michael@0 1033 .D32(0x9e3b9800)
michael@0 1034 .D32(0xfffffff7)
michael@0 1035 .D32(0x00000000)
michael@0 1036 .D32(0x002ff2a4)
michael@0 1037 .D32(0x64a07ff1) // random value to be confused with a return address
michael@0 1038 .D32(0x002ff8dc)
michael@0 1039 .D32(0x75fc6590) // random value to be confused with a return address
michael@0 1040 .D32(0xfdd2c6ea)
michael@0 1041 .D32(0x00000000)
michael@0 1042 .Mark(&frame1_ebp)
michael@0 1043 .D32(frame2_ebp) // Child EBP
michael@0 1044 .D32(0x75741194) // return address of frame 1
michael@0 1045 .D32(0x000017b0) // args to child
michael@0 1046 .D32(0x0036ee80)
michael@0 1047 .D32(0x00000000)
michael@0 1048 .D32(0x65bc7d14)
michael@0 1049 .Mark(&frame2_ebp)
michael@0 1050 .D32(frame3_ebp) // Child EBP
michael@0 1051 .D32(0x75741148) // return address of frame 2
michael@0 1052 .D32(0x000017b0) // args to child
michael@0 1053 .D32(0x0036ee80)
michael@0 1054 .D32(0x00000000)
michael@0 1055 .Mark(&frame3_ebp)
michael@0 1056 .D32(0) // saved %ebp (stack end)
michael@0 1057 .D32(0); // saved %eip (stack end)
michael@0 1058
michael@0 1059 RegionFromSection();
michael@0 1060 raw_context.eip = 0x771ef8c1; // in ntdll::ZwWaitForSingleObject
michael@0 1061 raw_context.esp = stack_section.start().Value();
michael@0 1062 ASSERT_TRUE(raw_context.esp == frame0_esp.Value());
michael@0 1063 raw_context.ebp = frame1_ebp.Value();
michael@0 1064
michael@0 1065 StackFrameSymbolizer frame_symbolizer(&supplier, &resolver);
michael@0 1066 StackwalkerX86 walker(&system_info, &raw_context, &stack_region, &modules,
michael@0 1067 &frame_symbolizer);
michael@0 1068 vector<const CodeModule*> modules_without_symbols;
michael@0 1069 ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols));
michael@0 1070 ASSERT_EQ(0U, modules_without_symbols.size());
michael@0 1071 frames = call_stack.frames();
michael@0 1072
michael@0 1073 ASSERT_EQ(4U, frames->size());
michael@0 1074
michael@0 1075 { // To avoid reusing locals by mistake
michael@0 1076 StackFrameX86 *frame0 = static_cast<StackFrameX86 *>(frames->at(0));
michael@0 1077 EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust);
michael@0 1078 ASSERT_EQ(StackFrameX86::CONTEXT_VALID_ALL, frame0->context_validity);
michael@0 1079 EXPECT_EQ(0x771ef8c1U, frame0->instruction);
michael@0 1080 EXPECT_EQ(0x771ef8c1U, frame0->context.eip);
michael@0 1081 EXPECT_EQ(frame0_esp.Value(), frame0->context.esp);
michael@0 1082 EXPECT_EQ(frame1_ebp.Value(), frame0->context.ebp);
michael@0 1083 EXPECT_EQ(&module3, frame0->module);
michael@0 1084 EXPECT_EQ("ZwWaitForSingleObject", frame0->function_name);
michael@0 1085 // The STACK WIN record for module3!ZwWaitForSingleObject should have
michael@0 1086 // produced a fully populated WindowsFrameInfo structure.
michael@0 1087 ASSERT_TRUE(frame0->windows_frame_info != NULL);
michael@0 1088 EXPECT_EQ(WindowsFrameInfo::VALID_ALL, frame0->windows_frame_info->valid);
michael@0 1089 EXPECT_EQ(WindowsFrameInfo::STACK_INFO_FPO,
michael@0 1090 frame0->windows_frame_info->type_);
michael@0 1091 EXPECT_EQ("", frame0->windows_frame_info->program_string);
michael@0 1092 EXPECT_FALSE(frame0->windows_frame_info->allocates_base_pointer);
michael@0 1093 }
michael@0 1094
michael@0 1095 { // To avoid reusing locals by mistake
michael@0 1096 StackFrameX86 *frame1 = static_cast<StackFrameX86 *>(frames->at(1));
michael@0 1097 EXPECT_EQ(StackFrame::FRAME_TRUST_CFI, frame1->trust);
michael@0 1098 ASSERT_EQ((StackFrameX86::CONTEXT_VALID_EIP
michael@0 1099 | StackFrameX86::CONTEXT_VALID_ESP
michael@0 1100 | StackFrameX86::CONTEXT_VALID_EBP),
michael@0 1101 frame1->context_validity);
michael@0 1102 EXPECT_EQ(0x75fa0a91U, frame1->instruction + 1);
michael@0 1103 EXPECT_EQ(0x75fa0a91U, frame1->context.eip);
michael@0 1104 EXPECT_EQ(frame1_esp.Value(), frame1->context.esp);
michael@0 1105 EXPECT_EQ(frame1_ebp.Value(), frame1->context.ebp);
michael@0 1106 EXPECT_EQ(&module4, frame1->module);
michael@0 1107 EXPECT_EQ("WaitForSingleObjectEx", frame1->function_name);
michael@0 1108 // The STACK WIN record for module4!WaitForSingleObjectEx should have
michael@0 1109 // produced a fully populated WindowsFrameInfo structure.
michael@0 1110 ASSERT_TRUE(frame1->windows_frame_info != NULL);
michael@0 1111 EXPECT_EQ(WindowsFrameInfo::VALID_ALL, frame1->windows_frame_info->valid);
michael@0 1112 EXPECT_EQ(WindowsFrameInfo::STACK_INFO_FRAME_DATA,
michael@0 1113 frame1->windows_frame_info->type_);
michael@0 1114 EXPECT_EQ("$T0 $ebp = $eip $T0 4 + ^ = $ebp $T0 ^ = $esp $T0 8 + = $L "
michael@0 1115 "$T0 .cbSavedRegs - = $P $T0 8 + .cbParams + =",
michael@0 1116 frame1->windows_frame_info->program_string);
michael@0 1117 EXPECT_FALSE(frame1->windows_frame_info->allocates_base_pointer);
michael@0 1118 }
michael@0 1119 }
michael@0 1120
michael@0 1121 // Scan the stack for a better return address and potentially skip frames
michael@0 1122 // when the calculated return address is not in a known module.
michael@0 1123 // Note, that the span of this scan is somewhat arbitrarily limited to 30
michael@0 1124 // search words (pointers):
michael@0 1125 // const int kRASearchWords = 30;
michael@0 1126 // This means that frames can be skipped only when their size is relatively
michael@0 1127 // small: smaller than kRASearchWords * sizeof(InstructionType)
michael@0 1128 TEST_F(GetCallerFrame, ReturnAddressIsNotInKnownModule) {
michael@0 1129 MockCodeModule msvcrt_dll(0x77be0000, 0x58000, "msvcrt.dll", "version1");
michael@0 1130 SetModuleSymbols(&msvcrt_dll, // msvcrt.dll
michael@0 1131 "PUBLIC 38180 0 wcsstr\n"
michael@0 1132 "STACK WIN 4 38180 61 10 0 8 0 0 0 1 $T0 $ebp = $eip $T0 "
michael@0 1133 "4 + ^ = $ebp $T0 ^ = $esp $T0 8 + = $L $T0 .cbSavedRegs "
michael@0 1134 "- = $P $T0 4 + .cbParams + =\n");
michael@0 1135
michael@0 1136 MockCodeModule kernel32_dll(0x7c800000, 0x103000, "kernel32.dll", "version1");
michael@0 1137 SetModuleSymbols(&kernel32_dll, // kernel32.dll
michael@0 1138 "PUBLIC efda 8 FindNextFileW\n"
michael@0 1139 "STACK WIN 4 efda 1bb c 0 8 8 3c 0 1 $T0 $ebp = $eip $T0 "
michael@0 1140 "4 + ^ = $ebp $T0 ^ = $esp $T0 8 + = $L $T0 .cbSavedRegs "
michael@0 1141 "- = $P $T0 4 + .cbParams + =\n");
michael@0 1142
michael@0 1143 MockCodeModule chrome_dll(0x1c30000, 0x28C8000, "chrome.dll", "version1");
michael@0 1144 SetModuleSymbols(&chrome_dll, // chrome.dll
michael@0 1145 "FUNC e3cff 4af 0 file_util::FileEnumerator::Next()\n"
michael@0 1146 "e3cff 1a 711 2505\n"
michael@0 1147 "STACK WIN 4 e3cff 4af 20 0 4 c 94 0 1 $T1 .raSearch = "
michael@0 1148 "$T0 $T1 4 - 8 @ = $ebp $T1 4 - ^ = $eip $T1 ^ = $esp "
michael@0 1149 "$T1 4 + = $20 $T0 152 - ^ = $23 $T0 156 - ^ = $24 "
michael@0 1150 "$T0 160 - ^ =\n");
michael@0 1151
michael@0 1152 // Create some modules with some stock debugging information.
michael@0 1153 MockCodeModules local_modules;
michael@0 1154 local_modules.Add(&msvcrt_dll);
michael@0 1155 local_modules.Add(&kernel32_dll);
michael@0 1156 local_modules.Add(&chrome_dll);
michael@0 1157
michael@0 1158 Label frame0_esp;
michael@0 1159 Label frame0_ebp;
michael@0 1160 Label frame1_ebp;
michael@0 1161 Label frame2_ebp;
michael@0 1162 Label frame3_ebp;
michael@0 1163
michael@0 1164 stack_section.start() = 0x0932f2d0;
michael@0 1165 stack_section
michael@0 1166 .Mark(&frame0_esp)
michael@0 1167 .D32(0x0764e000)
michael@0 1168 .D32(0x0764e068)
michael@0 1169 .Mark(&frame0_ebp)
michael@0 1170 .D32(frame1_ebp) // Child EBP
michael@0 1171 .D32(0x001767a0) // return address of frame 0
michael@0 1172 // Not in known module
michael@0 1173 .D32(0x0764e0c6)
michael@0 1174 .D32(0x001bb1b8)
michael@0 1175 .D32(0x0764e068)
michael@0 1176 .D32(0x00000003)
michael@0 1177 .D32(0x0764e068)
michael@0 1178 .D32(0x00000003)
michael@0 1179 .D32(0x07578828)
michael@0 1180 .D32(0x0764e000)
michael@0 1181 .D32(0x00000000)
michael@0 1182 .D32(0x001c0010)
michael@0 1183 .D32(0x0764e0c6)
michael@0 1184 .Mark(&frame1_ebp)
michael@0 1185 .D32(frame2_ebp) // Child EBP
michael@0 1186 .D32(0x7c80f10f) // return address of frame 1
michael@0 1187 // inside kernel32!FindNextFileW
michael@0 1188 .D32(0x000008f8)
michael@0 1189 .D32(0x00000000)
michael@0 1190 .D32(0x00000000)
michael@0 1191 .D32(0x00000000)
michael@0 1192 .D32(0x0932f34c)
michael@0 1193 .D32(0x0764e000)
michael@0 1194 .D32(0x00001000)
michael@0 1195 .D32(0x00000000)
michael@0 1196 .D32(0x00000001)
michael@0 1197 .D32(0x00000000)
michael@0 1198 .D32(0x00000000)
michael@0 1199 .D32(0x0932f6a8)
michael@0 1200 .D32(0x00000000)
michael@0 1201 .D32(0x0932f6d8)
michael@0 1202 .D32(0x00000000)
michael@0 1203 .D32(0x000000d6)
michael@0 1204 .D32(0x0764e000)
michael@0 1205 .D32(0x7ff9a000)
michael@0 1206 .D32(0x0932f3fc)
michael@0 1207 .D32(0x00000001)
michael@0 1208 .D32(0x00000001)
michael@0 1209 .D32(0x07578828)
michael@0 1210 .D32(0x0000002e)
michael@0 1211 .D32(0x0932f340)
michael@0 1212 .D32(0x0932eef4)
michael@0 1213 .D32(0x0932ffdc)
michael@0 1214 .D32(0x7c839ad8)
michael@0 1215 .D32(0x7c80f0d8)
michael@0 1216 .D32(0x00000000)
michael@0 1217 .Mark(&frame2_ebp)
michael@0 1218 .D32(frame3_ebp) // Child EBP
michael@0 1219 .D32(0x01d13f91) // return address of frame 2
michael@0 1220 // inside chrome_dll!file_util::FileEnumerator::Next
michael@0 1221 .D32(0x07578828)
michael@0 1222 .D32(0x0932f6ac)
michael@0 1223 .D32(0x0932f9c4)
michael@0 1224 .D32(0x0932f9b4)
michael@0 1225 .D32(0x00000000)
michael@0 1226 .D32(0x00000003)
michael@0 1227 .D32(0x0932f978)
michael@0 1228 .D32(0x01094330)
michael@0 1229 .D32(0x00000000)
michael@0 1230 .D32(0x00000001)
michael@0 1231 .D32(0x01094330)
michael@0 1232 .D32(0x00000000)
michael@0 1233 .D32(0x00000000)
michael@0 1234 .D32(0x07f30000)
michael@0 1235 .D32(0x01c3ba17)
michael@0 1236 .D32(0x08bab840)
michael@0 1237 .D32(0x07f31580)
michael@0 1238 .D32(0x00000000)
michael@0 1239 .D32(0x00000007)
michael@0 1240 .D32(0x0932f940)
michael@0 1241 .D32(0x0000002e)
michael@0 1242 .D32(0x0932f40c)
michael@0 1243 .D32(0x01d13b53)
michael@0 1244 .D32(0x0932f958)
michael@0 1245 .D32(0x00000001)
michael@0 1246 .D32(0x00000007)
michael@0 1247 .D32(0x0932f940)
michael@0 1248 .D32(0x0000002e)
michael@0 1249 .D32(0x00000000)
michael@0 1250 .D32(0x0932f6ac)
michael@0 1251 .D32(0x01e13ef0)
michael@0 1252 .D32(0x00000001)
michael@0 1253 .D32(0x00000007)
michael@0 1254 .D32(0x0932f958)
michael@0 1255 .D32(0x08bab840)
michael@0 1256 .D32(0x0932f9b4)
michael@0 1257 .D32(0x00000000)
michael@0 1258 .D32(0x0932f9b4)
michael@0 1259 .D32(0x000000a7)
michael@0 1260 .D32(0x000000a7)
michael@0 1261 .D32(0x0932f998)
michael@0 1262 .D32(0x579627a2)
michael@0 1263 .Mark(&frame3_ebp)
michael@0 1264 .D32(0) // saved %ebp (stack end)
michael@0 1265 .D32(0); // saved %eip (stack end)
michael@0 1266
michael@0 1267 RegionFromSection();
michael@0 1268 raw_context.eip = 0x77c181cd; // inside msvcrt!wcsstr
michael@0 1269 raw_context.esp = frame0_esp.Value();
michael@0 1270 raw_context.ebp = frame0_ebp.Value();
michael@0 1271 // sanity
michael@0 1272 ASSERT_TRUE(raw_context.esp == stack_section.start().Value());
michael@0 1273 ASSERT_TRUE(raw_context.ebp == stack_section.start().Value() + 8);
michael@0 1274
michael@0 1275 StackFrameSymbolizer frame_symbolizer(&supplier, &resolver);
michael@0 1276 StackwalkerX86 walker(&system_info, &raw_context, &stack_region,
michael@0 1277 &local_modules, &frame_symbolizer);
michael@0 1278 vector<const CodeModule*> modules_without_symbols;
michael@0 1279 ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols));
michael@0 1280 ASSERT_EQ(0U, modules_without_symbols.size());
michael@0 1281 frames = call_stack.frames();
michael@0 1282
michael@0 1283 ASSERT_EQ(3U, frames->size());
michael@0 1284
michael@0 1285 { // To avoid reusing locals by mistake
michael@0 1286 StackFrameX86 *frame0 = static_cast<StackFrameX86 *>(frames->at(0));
michael@0 1287 EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust);
michael@0 1288 ASSERT_EQ(StackFrameX86::CONTEXT_VALID_ALL, frame0->context_validity);
michael@0 1289 EXPECT_EQ(0x77c181cdU, frame0->instruction);
michael@0 1290 EXPECT_EQ(0x77c181cdU, frame0->context.eip);
michael@0 1291 EXPECT_EQ(frame0_esp.Value(), frame0->context.esp);
michael@0 1292 EXPECT_EQ(frame0_ebp.Value(), frame0->context.ebp);
michael@0 1293 EXPECT_EQ(&msvcrt_dll, frame0->module);
michael@0 1294 EXPECT_EQ("wcsstr", frame0->function_name);
michael@0 1295 ASSERT_TRUE(frame0->windows_frame_info != NULL);
michael@0 1296 EXPECT_EQ(WindowsFrameInfo::VALID_ALL, frame0->windows_frame_info->valid);
michael@0 1297 EXPECT_EQ(WindowsFrameInfo::STACK_INFO_FRAME_DATA,
michael@0 1298 frame0->windows_frame_info->type_);
michael@0 1299 EXPECT_EQ("$T0 $ebp = $eip $T0 "
michael@0 1300 "4 + ^ = $ebp $T0 ^ = $esp $T0 8 + = $L $T0 .cbSavedRegs "
michael@0 1301 "- = $P $T0 4 + .cbParams + =",
michael@0 1302 frame0->windows_frame_info->program_string);
michael@0 1303 // It has program string, so allocates_base_pointer is not expected
michael@0 1304 EXPECT_FALSE(frame0->windows_frame_info->allocates_base_pointer);
michael@0 1305 }
michael@0 1306
michael@0 1307 { // To avoid reusing locals by mistake
michael@0 1308 StackFrameX86 *frame1 = static_cast<StackFrameX86 *>(frames->at(1));
michael@0 1309 EXPECT_EQ(StackFrame::FRAME_TRUST_CFI_SCAN, frame1->trust);
michael@0 1310 ASSERT_EQ((StackFrameX86::CONTEXT_VALID_EIP |
michael@0 1311 StackFrameX86::CONTEXT_VALID_ESP |
michael@0 1312 StackFrameX86::CONTEXT_VALID_EBP),
michael@0 1313 frame1->context_validity);
michael@0 1314 EXPECT_EQ(0x7c80f10fU, frame1->instruction + 1);
michael@0 1315 EXPECT_EQ(0x7c80f10fU, frame1->context.eip);
michael@0 1316 // frame 1 was skipped, so intead of frame1_ebp compare with frame2_ebp.
michael@0 1317 EXPECT_EQ(frame2_ebp.Value(), frame1->context.ebp);
michael@0 1318 EXPECT_EQ(&kernel32_dll, frame1->module);
michael@0 1319 EXPECT_EQ("FindNextFileW", frame1->function_name);
michael@0 1320 ASSERT_TRUE(frame1->windows_frame_info != NULL);
michael@0 1321 EXPECT_EQ(WindowsFrameInfo::VALID_ALL, frame1->windows_frame_info->valid);
michael@0 1322 EXPECT_EQ(WindowsFrameInfo::STACK_INFO_FRAME_DATA,
michael@0 1323 frame1->windows_frame_info->type_);
michael@0 1324 EXPECT_EQ("$T0 $ebp = $eip $T0 "
michael@0 1325 "4 + ^ = $ebp $T0 ^ = $esp $T0 8 + = $L $T0 .cbSavedRegs "
michael@0 1326 "- = $P $T0 4 + .cbParams + =",
michael@0 1327 frame1->windows_frame_info->program_string);
michael@0 1328 EXPECT_FALSE(frame1->windows_frame_info->allocates_base_pointer);
michael@0 1329 }
michael@0 1330
michael@0 1331 { // To avoid reusing locals by mistake
michael@0 1332 StackFrameX86 *frame2 = static_cast<StackFrameX86 *>(frames->at(2));
michael@0 1333 EXPECT_EQ(StackFrame::FRAME_TRUST_CFI, frame2->trust);
michael@0 1334 ASSERT_EQ((StackFrameX86::CONTEXT_VALID_EIP |
michael@0 1335 StackFrameX86::CONTEXT_VALID_ESP |
michael@0 1336 StackFrameX86::CONTEXT_VALID_EBP),
michael@0 1337 frame2->context_validity);
michael@0 1338 EXPECT_EQ(0x01d13f91U, frame2->instruction + 1);
michael@0 1339 EXPECT_EQ(0x01d13f91U, frame2->context.eip);
michael@0 1340 // frame 1 was skipped, so intead of frame2_ebp compare with frame3_ebp.
michael@0 1341 EXPECT_EQ(frame3_ebp.Value(), frame2->context.ebp);
michael@0 1342 EXPECT_EQ(&chrome_dll, frame2->module);
michael@0 1343 EXPECT_EQ("file_util::FileEnumerator::Next()", frame2->function_name);
michael@0 1344 ASSERT_TRUE(frame2->windows_frame_info != NULL);
michael@0 1345 EXPECT_EQ(WindowsFrameInfo::VALID_ALL, frame2->windows_frame_info->valid);
michael@0 1346 EXPECT_EQ(WindowsFrameInfo::STACK_INFO_FRAME_DATA,
michael@0 1347 frame2->windows_frame_info->type_);
michael@0 1348 EXPECT_EQ("$T1 .raSearch = "
michael@0 1349 "$T0 $T1 4 - 8 @ = $ebp $T1 4 - ^ = $eip $T1 ^ = $esp "
michael@0 1350 "$T1 4 + = $20 $T0 152 - ^ = $23 $T0 156 - ^ = $24 "
michael@0 1351 "$T0 160 - ^ =",
michael@0 1352 frame2->windows_frame_info->program_string);
michael@0 1353 EXPECT_FALSE(frame2->windows_frame_info->allocates_base_pointer);
michael@0 1354 }
michael@0 1355 }
michael@0 1356
michael@0 1357 struct CFIFixture: public StackwalkerX86Fixture {
michael@0 1358 CFIFixture() {
michael@0 1359 // Provide a bunch of STACK CFI records; individual tests walk to the
michael@0 1360 // caller from every point in this series, expecting to find the same
michael@0 1361 // set of register values.
michael@0 1362 SetModuleSymbols(&module1,
michael@0 1363 // The youngest frame's function.
michael@0 1364 "FUNC 4000 1000 10 enchiridion\n"
michael@0 1365 // Initially, just a return address.
michael@0 1366 "STACK CFI INIT 4000 100 .cfa: $esp 4 + .ra: .cfa 4 - ^\n"
michael@0 1367 // Push %ebx.
michael@0 1368 "STACK CFI 4001 .cfa: $esp 8 + $ebx: .cfa 8 - ^\n"
michael@0 1369 // Move %esi into %ebx. Weird, but permitted.
michael@0 1370 "STACK CFI 4002 $esi: $ebx\n"
michael@0 1371 // Allocate frame space, and save %edi.
michael@0 1372 "STACK CFI 4003 .cfa: $esp 20 + $edi: .cfa 16 - ^\n"
michael@0 1373 // Put the return address in %edi.
michael@0 1374 "STACK CFI 4005 .ra: $edi\n"
michael@0 1375 // Save %ebp, and use it as a frame pointer.
michael@0 1376 "STACK CFI 4006 .cfa: $ebp 8 + $ebp: .cfa 12 - ^\n"
michael@0 1377
michael@0 1378 // The calling function.
michael@0 1379 "FUNC 5000 1000 10 epictetus\n"
michael@0 1380 // Mark it as end of stack.
michael@0 1381 "STACK CFI INIT 5000 1000 .cfa: $esp .ra 0\n");
michael@0 1382
michael@0 1383 // Provide some distinctive values for the caller's registers.
michael@0 1384 expected.esp = 0x80000000;
michael@0 1385 expected.eip = 0x40005510;
michael@0 1386 expected.ebp = 0xc0d4aab9;
michael@0 1387 expected.ebx = 0x60f20ce6;
michael@0 1388 expected.esi = 0x53d1379d;
michael@0 1389 expected.edi = 0xafbae234;
michael@0 1390
michael@0 1391 // By default, registers are unchanged.
michael@0 1392 raw_context = expected;
michael@0 1393 }
michael@0 1394
michael@0 1395 // Walk the stack, using stack_section as the contents of the stack
michael@0 1396 // and raw_context as the current register values. (Set
michael@0 1397 // raw_context.esp to the stack's starting address.) Expect two
michael@0 1398 // stack frames; in the older frame, expect the callee-saves
michael@0 1399 // registers to have values matching those in 'expected'.
michael@0 1400 void CheckWalk() {
michael@0 1401 RegionFromSection();
michael@0 1402 raw_context.esp = stack_section.start().Value();
michael@0 1403
michael@0 1404 StackFrameSymbolizer frame_symbolizer(&supplier, &resolver);
michael@0 1405 StackwalkerX86 walker(&system_info, &raw_context, &stack_region, &modules,
michael@0 1406 &frame_symbolizer);
michael@0 1407 vector<const CodeModule*> modules_without_symbols;
michael@0 1408 ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols));
michael@0 1409 ASSERT_EQ(0U, modules_without_symbols.size());
michael@0 1410 frames = call_stack.frames();
michael@0 1411 ASSERT_EQ(2U, frames->size());
michael@0 1412
michael@0 1413 { // To avoid reusing locals by mistake
michael@0 1414 StackFrameX86 *frame0 = static_cast<StackFrameX86 *>(frames->at(0));
michael@0 1415 EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust);
michael@0 1416 ASSERT_EQ(StackFrameX86::CONTEXT_VALID_ALL, frame0->context_validity);
michael@0 1417 EXPECT_EQ("enchiridion", frame0->function_name);
michael@0 1418 EXPECT_EQ(0x40004000U, frame0->function_base);
michael@0 1419 ASSERT_TRUE(frame0->windows_frame_info != NULL);
michael@0 1420 ASSERT_EQ(WindowsFrameInfo::VALID_PARAMETER_SIZE,
michael@0 1421 frame0->windows_frame_info->valid);
michael@0 1422 ASSERT_TRUE(frame0->cfi_frame_info != NULL);
michael@0 1423 }
michael@0 1424
michael@0 1425 { // To avoid reusing locals by mistake
michael@0 1426 StackFrameX86 *frame1 = static_cast<StackFrameX86 *>(frames->at(1));
michael@0 1427 EXPECT_EQ(StackFrame::FRAME_TRUST_CFI, frame1->trust);
michael@0 1428 ASSERT_EQ((StackFrameX86::CONTEXT_VALID_EIP |
michael@0 1429 StackFrameX86::CONTEXT_VALID_ESP |
michael@0 1430 StackFrameX86::CONTEXT_VALID_EBP |
michael@0 1431 StackFrameX86::CONTEXT_VALID_EBX |
michael@0 1432 StackFrameX86::CONTEXT_VALID_ESI |
michael@0 1433 StackFrameX86::CONTEXT_VALID_EDI),
michael@0 1434 frame1->context_validity);
michael@0 1435 EXPECT_EQ(expected.eip, frame1->context.eip);
michael@0 1436 EXPECT_EQ(expected.esp, frame1->context.esp);
michael@0 1437 EXPECT_EQ(expected.ebp, frame1->context.ebp);
michael@0 1438 EXPECT_EQ(expected.ebx, frame1->context.ebx);
michael@0 1439 EXPECT_EQ(expected.esi, frame1->context.esi);
michael@0 1440 EXPECT_EQ(expected.edi, frame1->context.edi);
michael@0 1441 EXPECT_EQ("epictetus", frame1->function_name);
michael@0 1442 }
michael@0 1443 }
michael@0 1444
michael@0 1445 // The values the stack walker should find for the caller's registers.
michael@0 1446 MDRawContextX86 expected;
michael@0 1447 };
michael@0 1448
michael@0 1449 class CFI: public CFIFixture, public Test { };
michael@0 1450
michael@0 1451 TEST_F(CFI, At4000) {
michael@0 1452 Label frame1_esp = expected.esp;
michael@0 1453 stack_section
michael@0 1454 .D32(0x40005510) // return address
michael@0 1455 .Mark(&frame1_esp); // This effectively sets stack_section.start().
michael@0 1456 raw_context.eip = 0x40004000;
michael@0 1457 CheckWalk();
michael@0 1458 }
michael@0 1459
michael@0 1460 TEST_F(CFI, At4001) {
michael@0 1461 Label frame1_esp = expected.esp;
michael@0 1462 stack_section
michael@0 1463 .D32(0x60f20ce6) // saved %ebx
michael@0 1464 .D32(0x40005510) // return address
michael@0 1465 .Mark(&frame1_esp); // This effectively sets stack_section.start().
michael@0 1466 raw_context.eip = 0x40004001;
michael@0 1467 raw_context.ebx = 0x91aa9a8b; // callee's %ebx value
michael@0 1468 CheckWalk();
michael@0 1469 }
michael@0 1470
michael@0 1471 TEST_F(CFI, At4002) {
michael@0 1472 Label frame1_esp = expected.esp;
michael@0 1473 stack_section
michael@0 1474 .D32(0x60f20ce6) // saved %ebx
michael@0 1475 .D32(0x40005510) // return address
michael@0 1476 .Mark(&frame1_esp); // This effectively sets stack_section.start().
michael@0 1477 raw_context.eip = 0x40004002;
michael@0 1478 raw_context.ebx = 0x53d1379d; // saved %esi
michael@0 1479 raw_context.esi = 0xa5c790ed; // callee's %esi value
michael@0 1480 CheckWalk();
michael@0 1481 }
michael@0 1482
michael@0 1483 TEST_F(CFI, At4003) {
michael@0 1484 Label frame1_esp = expected.esp;
michael@0 1485 stack_section
michael@0 1486 .D32(0x56ec3db7) // garbage
michael@0 1487 .D32(0xafbae234) // saved %edi
michael@0 1488 .D32(0x53d67131) // garbage
michael@0 1489 .D32(0x60f20ce6) // saved %ebx
michael@0 1490 .D32(0x40005510) // return address
michael@0 1491 .Mark(&frame1_esp); // This effectively sets stack_section.start().
michael@0 1492 raw_context.eip = 0x40004003;
michael@0 1493 raw_context.ebx = 0x53d1379d; // saved %esi
michael@0 1494 raw_context.esi = 0xa97f229d; // callee's %esi
michael@0 1495 raw_context.edi = 0xb05cc997; // callee's %edi
michael@0 1496 CheckWalk();
michael@0 1497 }
michael@0 1498
michael@0 1499 // The results here should be the same as those at module offset
michael@0 1500 // 0x4003.
michael@0 1501 TEST_F(CFI, At4004) {
michael@0 1502 Label frame1_esp = expected.esp;
michael@0 1503 stack_section
michael@0 1504 .D32(0xe29782c2) // garbage
michael@0 1505 .D32(0xafbae234) // saved %edi
michael@0 1506 .D32(0x5ba29ce9) // garbage
michael@0 1507 .D32(0x60f20ce6) // saved %ebx
michael@0 1508 .D32(0x40005510) // return address
michael@0 1509 .Mark(&frame1_esp); // This effectively sets stack_section.start().
michael@0 1510 raw_context.eip = 0x40004004;
michael@0 1511 raw_context.ebx = 0x53d1379d; // saved %esi
michael@0 1512 raw_context.esi = 0x0fb7dc4e; // callee's %esi
michael@0 1513 raw_context.edi = 0x993b4280; // callee's %edi
michael@0 1514 CheckWalk();
michael@0 1515 }
michael@0 1516
michael@0 1517 TEST_F(CFI, At4005) {
michael@0 1518 Label frame1_esp = expected.esp;
michael@0 1519 stack_section
michael@0 1520 .D32(0xe29782c2) // garbage
michael@0 1521 .D32(0xafbae234) // saved %edi
michael@0 1522 .D32(0x5ba29ce9) // garbage
michael@0 1523 .D32(0x60f20ce6) // saved %ebx
michael@0 1524 .D32(0x8036cc02) // garbage
michael@0 1525 .Mark(&frame1_esp); // This effectively sets stack_section.start().
michael@0 1526 raw_context.eip = 0x40004005;
michael@0 1527 raw_context.ebx = 0x53d1379d; // saved %esi
michael@0 1528 raw_context.esi = 0x0fb7dc4e; // callee's %esi
michael@0 1529 raw_context.edi = 0x40005510; // return address
michael@0 1530 CheckWalk();
michael@0 1531 }
michael@0 1532
michael@0 1533 TEST_F(CFI, At4006) {
michael@0 1534 Label frame0_ebp;
michael@0 1535 Label frame1_esp = expected.esp;
michael@0 1536 stack_section
michael@0 1537 .D32(0xdcdd25cd) // garbage
michael@0 1538 .D32(0xafbae234) // saved %edi
michael@0 1539 .D32(0xc0d4aab9) // saved %ebp
michael@0 1540 .Mark(&frame0_ebp) // frame pointer points here
michael@0 1541 .D32(0x60f20ce6) // saved %ebx
michael@0 1542 .D32(0x8036cc02) // garbage
michael@0 1543 .Mark(&frame1_esp); // This effectively sets stack_section.start().
michael@0 1544 raw_context.eip = 0x40004006;
michael@0 1545 raw_context.ebp = frame0_ebp.Value();
michael@0 1546 raw_context.ebx = 0x53d1379d; // saved %esi
michael@0 1547 raw_context.esi = 0x743833c9; // callee's %esi
michael@0 1548 raw_context.edi = 0x40005510; // return address
michael@0 1549 CheckWalk();
michael@0 1550 }
michael@0 1551

mercurial