stackwalker_x86_unittest.cc revision 3108b9dd7bbac28dd01d78f9264fe494ee9c95a0
1a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy// Copyright (c) 2010, Google Inc.
2a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy// All rights reserved.
3a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy//
4a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy// Redistribution and use in source and binary forms, with or without
5a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy// modification, are permitted provided that the following conditions are
6a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy// met:
7a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy//
8a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy//     * Redistributions of source code must retain the above copyright
9a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy// notice, this list of conditions and the following disclaimer.
10a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy//     * Redistributions in binary form must reproduce the above
11a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy// copyright notice, this list of conditions and the following disclaimer
12a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy// in the documentation and/or other materials provided with the
13a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy// distribution.
14a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy//     * Neither the name of Google Inc. nor the names of its
15a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy// contributors may be used to endorse or promote products derived from
16a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy// this software without specific prior written permission.
17a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy//
18a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy
30a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy// Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com>
31a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy
32a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy// stackwalker_x86_unittest.cc: Unit tests for StackwalkerX86 class.
33a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy
34a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy#include <string>
35a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy#include <vector>
36a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy
37a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy#include "breakpad_googletest_includes.h"
38865df5af57922a4dc1e2a24e3f5c371d84f0f574jimblandy#include "common/test_assembler.h"
394e518a4357a2d1c379d4a91df6d4e153ee791101ivan.penkov@gmail.com#include "common/using_std_string.h"
40a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy#include "google_breakpad/common/minidump_format.h"
41a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy#include "google_breakpad/processor/basic_source_line_resolver.h"
42a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy#include "google_breakpad/processor/call_stack.h"
43a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy#include "google_breakpad/processor/source_line_resolver_interface.h"
44a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy#include "google_breakpad/processor/stack_frame_cpu.h"
45a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy#include "processor/stackwalker_unittest_utils.h"
46a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy#include "processor/stackwalker_x86.h"
47a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy#include "processor/windows_frame_info.h"
48a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy
49a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandyusing google_breakpad::BasicSourceLineResolver;
50a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandyusing google_breakpad::CallStack;
519753aff85a9a20dbe294529b4184d9686ec42cddSiyangXie@gmail.comusing google_breakpad::StackFrameSymbolizer;
52a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandyusing google_breakpad::StackFrame;
53a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandyusing google_breakpad::StackFrameX86;
54a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandyusing google_breakpad::StackwalkerX86;
55a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandyusing google_breakpad::SystemInfo;
56a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandyusing google_breakpad::WindowsFrameInfo;
576f598cc435f8c557b33f85802f1571ef745c37b0ted.mielczarekusing google_breakpad::test_assembler::kLittleEndian;
586f598cc435f8c557b33f85802f1571ef745c37b0ted.mielczarekusing google_breakpad::test_assembler::Label;
596f598cc435f8c557b33f85802f1571ef745c37b0ted.mielczarekusing google_breakpad::test_assembler::Section;
60a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandyusing std::vector;
61a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandyusing testing::_;
62a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandyusing testing::Return;
63a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandyusing testing::SetArgumentPointee;
64a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandyusing testing::Test;
65a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy
66a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandyclass StackwalkerX86Fixture {
67a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy public:
68a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy  StackwalkerX86Fixture()
69a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy    : stack_section(kLittleEndian),
70a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy      // Give the two modules reasonable standard locations and names
71a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy      // for tests to play with.
72a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy      module1(0x40000000, 0x10000, "module1", "version1"),
732660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com      module2(0x50000000, 0x10000, "module2", "version2"),
742660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com      module3(0x771d0000, 0x180000, "module3", "version3"),
752660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com      module4(0x75f90000, 0x46000, "module4", "version4"),
762660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com      module5(0x75730000, 0x110000, "module5", "version5"),
772660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com      module6(0x647f0000, 0x1ba8000, "module6", "version6") {
78a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy    // Identify the system as a Linux system.
79a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy    system_info.os = "Linux";
80a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy    system_info.os_short = "linux";
81a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy    system_info.os_version = "Salacious Skink";
82a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy    system_info.cpu = "x86";
83a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy    system_info.cpu_info = "";
84a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy
85a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy    // Put distinctive values in the raw CPU context.
86a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy    BrandContext(&raw_context);
87a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy
88a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy    // Create some modules with some stock debugging information.
89a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy    modules.Add(&module1);
90a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy    modules.Add(&module2);
912660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    modules.Add(&module3);
922660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    modules.Add(&module4);
932660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    modules.Add(&module5);
942660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    modules.Add(&module6);
95a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy
96a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy    // By default, none of the modules have symbol info; call
97a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy    // SetModuleSymbols to override this.
985b117cf53af46f357d28761ced3a1d94aeb5df91SiyangXie@gmail.com    EXPECT_CALL(supplier, GetCStringSymbolData(_, _, _, _))
99a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy      .WillRepeatedly(Return(MockSymbolSupplier::NOT_FOUND));
100a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy  }
101a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy
102a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy  // Set the Breakpad symbol information that supplier should return for
103a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy  // MODULE to INFO.
104a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy  void SetModuleSymbols(MockCodeModule *module, const string &info) {
105df823ad6d7ec7b82d256ccfae2df859f9cb6060bivan.penkov@gmail.com    char *buffer = supplier.CopySymbolDataAndOwnTheCopy(info);
1065b117cf53af46f357d28761ced3a1d94aeb5df91SiyangXie@gmail.com    EXPECT_CALL(supplier, GetCStringSymbolData(module, &system_info, _, _))
1075b117cf53af46f357d28761ced3a1d94aeb5df91SiyangXie@gmail.com      .WillRepeatedly(DoAll(SetArgumentPointee<3>(buffer),
108a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy                            Return(MockSymbolSupplier::FOUND)));
109a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy  }
110a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy
111a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy  // Populate stack_region with the contents of stack_section. Use
112a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy  // stack_section.start() as the region's starting address.
113a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy  void RegionFromSection() {
114a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy    string contents;
115a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy    ASSERT_TRUE(stack_section.GetContents(&contents));
116a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy    stack_region.Init(stack_section.start().Value(), contents);
117a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy  }
118a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy
119a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy  // Fill RAW_CONTEXT with pseudo-random data, for round-trip checking.
120a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy  void BrandContext(MDRawContextX86 *raw_context) {
121a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy    u_int8_t x = 173;
122a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy    for (size_t i = 0; i < sizeof(*raw_context); i++)
123a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy      reinterpret_cast<u_int8_t *>(raw_context)[i] = (x += 17);
124a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy  }
125a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy
126a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy  SystemInfo system_info;
127a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy  MDRawContextX86 raw_context;
128a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy  Section stack_section;
129a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy  MockMemoryRegion stack_region;
130a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy  MockCodeModule module1;
131a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy  MockCodeModule module2;
1322660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com  MockCodeModule module3;
1332660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com  MockCodeModule module4;
1342660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com  MockCodeModule module5;
1352660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com  MockCodeModule module6;
136a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy  MockCodeModules modules;
137a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy  MockSymbolSupplier supplier;
138a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy  BasicSourceLineResolver resolver;
139a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy  CallStack call_stack;
140a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy  const vector<StackFrame *> *frames;
141a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy};
142a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy
143281d52d944d63ddfbe933a7bbe8adbfba3523966ted.mielczarekclass SanityCheck: public StackwalkerX86Fixture, public Test { };
144281d52d944d63ddfbe933a7bbe8adbfba3523966ted.mielczarek
145281d52d944d63ddfbe933a7bbe8adbfba3523966ted.mielczarekTEST_F(SanityCheck, NoResolver) {
146281d52d944d63ddfbe933a7bbe8adbfba3523966ted.mielczarek  stack_section.start() = 0x80000000;
147281d52d944d63ddfbe933a7bbe8adbfba3523966ted.mielczarek  stack_section.D32(0).D32(0); // end-of-stack marker
148281d52d944d63ddfbe933a7bbe8adbfba3523966ted.mielczarek  RegionFromSection();
149281d52d944d63ddfbe933a7bbe8adbfba3523966ted.mielczarek  raw_context.eip = 0x40000200;
150281d52d944d63ddfbe933a7bbe8adbfba3523966ted.mielczarek  raw_context.ebp = 0x80000000;
151281d52d944d63ddfbe933a7bbe8adbfba3523966ted.mielczarek
1529753aff85a9a20dbe294529b4184d9686ec42cddSiyangXie@gmail.com  StackFrameSymbolizer frame_symbolizer(NULL, NULL);
153281d52d944d63ddfbe933a7bbe8adbfba3523966ted.mielczarek  StackwalkerX86 walker(&system_info, &raw_context, &stack_region, &modules,
1549753aff85a9a20dbe294529b4184d9686ec42cddSiyangXie@gmail.com                        &frame_symbolizer);
155281d52d944d63ddfbe933a7bbe8adbfba3523966ted.mielczarek  // This should succeed, even without a resolver or supplier.
156281d52d944d63ddfbe933a7bbe8adbfba3523966ted.mielczarek  ASSERT_TRUE(walker.Walk(&call_stack));
157281d52d944d63ddfbe933a7bbe8adbfba3523966ted.mielczarek  frames = call_stack.frames();
158281d52d944d63ddfbe933a7bbe8adbfba3523966ted.mielczarek  StackFrameX86 *frame = static_cast<StackFrameX86 *>(frames->at(0));
159281d52d944d63ddfbe933a7bbe8adbfba3523966ted.mielczarek  // Check that the values from the original raw context made it
160281d52d944d63ddfbe933a7bbe8adbfba3523966ted.mielczarek  // through to the context in the stack frame.
161281d52d944d63ddfbe933a7bbe8adbfba3523966ted.mielczarek  EXPECT_EQ(0, memcmp(&raw_context, &frame->context, sizeof(raw_context)));
162281d52d944d63ddfbe933a7bbe8adbfba3523966ted.mielczarek}
163281d52d944d63ddfbe933a7bbe8adbfba3523966ted.mielczarek
164a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandyclass GetContextFrame: public StackwalkerX86Fixture, public Test { };
165a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy
166a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandyTEST_F(GetContextFrame, Simple) {
167a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy  stack_section.start() = 0x80000000;
168a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy  stack_section.D32(0).D32(0); // end-of-stack marker
169a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy  RegionFromSection();
170a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy  raw_context.eip = 0x40000200;
171a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy  raw_context.ebp = 0x80000000;
172a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy
1739753aff85a9a20dbe294529b4184d9686ec42cddSiyangXie@gmail.com  StackFrameSymbolizer frame_symbolizer(&supplier, &resolver);
174a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy  StackwalkerX86 walker(&system_info, &raw_context, &stack_region, &modules,
1759753aff85a9a20dbe294529b4184d9686ec42cddSiyangXie@gmail.com                        &frame_symbolizer);
176a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy  ASSERT_TRUE(walker.Walk(&call_stack));
177a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy  frames = call_stack.frames();
178a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy  StackFrameX86 *frame = static_cast<StackFrameX86 *>(frames->at(0));
179a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy  // Check that the values from the original raw context made it
180a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy  // through to the context in the stack frame.
181281d52d944d63ddfbe933a7bbe8adbfba3523966ted.mielczarek  EXPECT_EQ(0, memcmp(&raw_context, &frame->context, sizeof(raw_context)));
182a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy}
183a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy
184a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandyclass GetCallerFrame: public StackwalkerX86Fixture, public Test { };
185a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy
186a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy// Walk a traditional frame. A traditional frame saves the caller's
187a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy// %ebp just below the return address, and has its own %ebp pointing
188a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy// at the saved %ebp.
189a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandyTEST_F(GetCallerFrame, Traditional) {
190a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy  stack_section.start() = 0x80000000;
191a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy  Label frame0_ebp, frame1_ebp;
192a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy  stack_section
193a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy    .Append(12, 0)                      // frame 0: space
194a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy    .Mark(&frame0_ebp)                  // frame 0 %ebp points here
195a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy    .D32(frame1_ebp)                    // frame 0: saved %ebp
196a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy    .D32(0x40008679)                    // frame 0: return address
197a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy    .Append(8, 0)                       // frame 1: space
198a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy    .Mark(&frame1_ebp)                  // frame 1 %ebp points here
199a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy    .D32(0)                             // frame 1: saved %ebp (stack end)
200a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy    .D32(0);                            // frame 1: return address (stack end)
201a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy  RegionFromSection();
202a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy  raw_context.eip = 0x4000c7a5;
203a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy  raw_context.esp = stack_section.start().Value();
204a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy  raw_context.ebp = frame0_ebp.Value();
205a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy
2069753aff85a9a20dbe294529b4184d9686ec42cddSiyangXie@gmail.com  StackFrameSymbolizer frame_symbolizer(&supplier, &resolver);
207a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy  StackwalkerX86 walker(&system_info, &raw_context, &stack_region, &modules,
2089753aff85a9a20dbe294529b4184d9686ec42cddSiyangXie@gmail.com                        &frame_symbolizer);
209a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy  ASSERT_TRUE(walker.Walk(&call_stack));
210a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy  frames = call_stack.frames();
211a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy  ASSERT_EQ(2U, frames->size());
212a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy
2132660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com  {  // To avoid reusing locals by mistake
2142660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    StackFrameX86 *frame0 = static_cast<StackFrameX86 *>(frames->at(0));
2152660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust);
2162660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(StackFrameX86::CONTEXT_VALID_ALL, frame0->context_validity);
2172660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(0x4000c7a5U, frame0->instruction);
2182660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(0x4000c7a5U, frame0->context.eip);
2192660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(frame0_ebp.Value(), frame0->context.ebp);
2202660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(NULL, frame0->windows_frame_info);
2212660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com  }
2222660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com
2232660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com  {  // To avoid reusing locals by mistake
2242660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    StackFrameX86 *frame1 = static_cast<StackFrameX86 *>(frames->at(1));
2252660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(StackFrame::FRAME_TRUST_FP, frame1->trust);
2262660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    ASSERT_EQ((StackFrameX86::CONTEXT_VALID_EIP
2272660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com               | StackFrameX86::CONTEXT_VALID_ESP
2282660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com               | StackFrameX86::CONTEXT_VALID_EBP),
2292660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com              frame1->context_validity);
2302660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(0x40008679U, frame1->instruction + 1);
2312660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(0x40008679U, frame1->context.eip);
2322660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(frame1_ebp.Value(), frame1->context.ebp);
2332660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(NULL, frame1->windows_frame_info);
2342660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com  }
235a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy}
236a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy
237a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy// Walk a traditional frame, but use a bogus %ebp value, forcing a scan
238a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy// of the stack for something that looks like a return address.
239a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandyTEST_F(GetCallerFrame, TraditionalScan) {
240a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy  stack_section.start() = 0x80000000;
241a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy  Label frame1_ebp;
242a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy  stack_section
243a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy    // frame 0
244a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy    .D32(0xf065dc76)    // locals area:
245a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy    .D32(0x46ee2167)    // garbage that doesn't look like
246a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy    .D32(0xbab023ec)    // a return address
247a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy    .D32(frame1_ebp)    // saved %ebp (%ebp fails to point here, forcing scan)
248a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy    .D32(0x4000129d)    // return address
249a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy    // frame 1
250a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy    .Append(8, 0)       // space
251a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy    .Mark(&frame1_ebp)  // %ebp points here
252a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy    .D32(0)             // saved %ebp (stack end)
253a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy    .D32(0);            // return address (stack end)
254a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy
255a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy  RegionFromSection();
256a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy  raw_context.eip = 0x4000f49d;
257a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy  raw_context.esp = stack_section.start().Value();
258a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy  // Make the frame pointer bogus, to make the stackwalker scan the stack
259a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy  // for something that looks like a return address.
260a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy  raw_context.ebp = 0xd43eed6e;
261a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy
2629753aff85a9a20dbe294529b4184d9686ec42cddSiyangXie@gmail.com  StackFrameSymbolizer frame_symbolizer(&supplier, &resolver);
263a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy  StackwalkerX86 walker(&system_info, &raw_context, &stack_region, &modules,
2649753aff85a9a20dbe294529b4184d9686ec42cddSiyangXie@gmail.com                        &frame_symbolizer);
265a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy  ASSERT_TRUE(walker.Walk(&call_stack));
266a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy  frames = call_stack.frames();
267a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy  ASSERT_EQ(2U, frames->size());
268a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy
2692660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com  {  // To avoid reusing locals by mistake
2702660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    StackFrameX86 *frame0 = static_cast<StackFrameX86 *>(frames->at(0));
2712660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust);
2722660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    ASSERT_EQ(StackFrameX86::CONTEXT_VALID_ALL, frame0->context_validity);
2732660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(0x4000f49dU, frame0->instruction);
2742660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(0x4000f49dU, frame0->context.eip);
2752660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(stack_section.start().Value(), frame0->context.esp);
2762660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(0xd43eed6eU, frame0->context.ebp);
2772660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(NULL, frame0->windows_frame_info);
2782660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com  }
2792660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com
2802660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com  {  // To avoid reusing locals by mistake
2812660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    StackFrameX86 *frame1 = static_cast<StackFrameX86 *>(frames->at(1));
2822660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(StackFrame::FRAME_TRUST_SCAN, frame1->trust);
2832660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    // I'd argue that CONTEXT_VALID_EBP shouldn't be here, since the
2842660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    // walker does not actually fetch the EBP after a scan (forcing the
2852660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    // next frame to be scanned as well). But let's grandfather the existing
2862660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    // behavior in for now.
2872660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    ASSERT_EQ((StackFrameX86::CONTEXT_VALID_EIP
2882660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com               | StackFrameX86::CONTEXT_VALID_ESP
2892660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com               | StackFrameX86::CONTEXT_VALID_EBP),
2902660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com              frame1->context_validity);
2912660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(0x4000129dU, frame1->instruction + 1);
2922660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(0x4000129dU, frame1->context.eip);
2932660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(0x80000014U, frame1->context.esp);
2942660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(0xd43eed6eU, frame1->context.ebp);
2952660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(NULL, frame1->windows_frame_info);
2962660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com  }
297a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy}
298a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy
2999c30407f7f2c6e6a352cd62fe4be21fe55ee1879ted.mielczarek// Force scanning for a return address a long way down the stack
3009c30407f7f2c6e6a352cd62fe4be21fe55ee1879ted.mielczarekTEST_F(GetCallerFrame, TraditionalScanLongWay) {
3019c30407f7f2c6e6a352cd62fe4be21fe55ee1879ted.mielczarek  stack_section.start() = 0x80000000;
3029c30407f7f2c6e6a352cd62fe4be21fe55ee1879ted.mielczarek  Label frame1_ebp;
3039c30407f7f2c6e6a352cd62fe4be21fe55ee1879ted.mielczarek  stack_section
3049c30407f7f2c6e6a352cd62fe4be21fe55ee1879ted.mielczarek    // frame 0
3059c30407f7f2c6e6a352cd62fe4be21fe55ee1879ted.mielczarek    .D32(0xf065dc76)    // locals area:
3069c30407f7f2c6e6a352cd62fe4be21fe55ee1879ted.mielczarek    .D32(0x46ee2167)    // garbage that doesn't look like
3079c30407f7f2c6e6a352cd62fe4be21fe55ee1879ted.mielczarek    .D32(0xbab023ec)    // a return address
3089c30407f7f2c6e6a352cd62fe4be21fe55ee1879ted.mielczarek    .Append(20 * 4, 0)  // a bunch of space
3099c30407f7f2c6e6a352cd62fe4be21fe55ee1879ted.mielczarek    .D32(frame1_ebp)    // saved %ebp (%ebp fails to point here, forcing scan)
3109c30407f7f2c6e6a352cd62fe4be21fe55ee1879ted.mielczarek    .D32(0x4000129d)    // return address
3119c30407f7f2c6e6a352cd62fe4be21fe55ee1879ted.mielczarek    // frame 1
3129c30407f7f2c6e6a352cd62fe4be21fe55ee1879ted.mielczarek    .Append(8, 0)       // space
3139c30407f7f2c6e6a352cd62fe4be21fe55ee1879ted.mielczarek    .Mark(&frame1_ebp)  // %ebp points here
3149c30407f7f2c6e6a352cd62fe4be21fe55ee1879ted.mielczarek    .D32(0)             // saved %ebp (stack end)
3159c30407f7f2c6e6a352cd62fe4be21fe55ee1879ted.mielczarek    .D32(0);            // return address (stack end)
3169c30407f7f2c6e6a352cd62fe4be21fe55ee1879ted.mielczarek
3179c30407f7f2c6e6a352cd62fe4be21fe55ee1879ted.mielczarek  RegionFromSection();
3189c30407f7f2c6e6a352cd62fe4be21fe55ee1879ted.mielczarek  raw_context.eip = 0x4000f49d;
3199c30407f7f2c6e6a352cd62fe4be21fe55ee1879ted.mielczarek  raw_context.esp = stack_section.start().Value();
3209c30407f7f2c6e6a352cd62fe4be21fe55ee1879ted.mielczarek  // Make the frame pointer bogus, to make the stackwalker scan the stack
3219c30407f7f2c6e6a352cd62fe4be21fe55ee1879ted.mielczarek  // for something that looks like a return address.
3229c30407f7f2c6e6a352cd62fe4be21fe55ee1879ted.mielczarek  raw_context.ebp = 0xd43eed6e;
3239c30407f7f2c6e6a352cd62fe4be21fe55ee1879ted.mielczarek
3249753aff85a9a20dbe294529b4184d9686ec42cddSiyangXie@gmail.com  StackFrameSymbolizer frame_symbolizer(&supplier, &resolver);
3259c30407f7f2c6e6a352cd62fe4be21fe55ee1879ted.mielczarek  StackwalkerX86 walker(&system_info, &raw_context, &stack_region, &modules,
3269753aff85a9a20dbe294529b4184d9686ec42cddSiyangXie@gmail.com                        &frame_symbolizer);
3279c30407f7f2c6e6a352cd62fe4be21fe55ee1879ted.mielczarek  ASSERT_TRUE(walker.Walk(&call_stack));
3289c30407f7f2c6e6a352cd62fe4be21fe55ee1879ted.mielczarek  frames = call_stack.frames();
3299c30407f7f2c6e6a352cd62fe4be21fe55ee1879ted.mielczarek  ASSERT_EQ(2U, frames->size());
3309c30407f7f2c6e6a352cd62fe4be21fe55ee1879ted.mielczarek
3312660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com  {  // To avoid reusing locals by mistake
3322660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    StackFrameX86 *frame0 = static_cast<StackFrameX86 *>(frames->at(0));
3332660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust);
3342660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    ASSERT_EQ(StackFrameX86::CONTEXT_VALID_ALL, frame0->context_validity);
3352660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(0x4000f49dU, frame0->instruction);
3362660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(0x4000f49dU, frame0->context.eip);
3372660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(stack_section.start().Value(), frame0->context.esp);
3382660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(0xd43eed6eU, frame0->context.ebp);
3392660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(NULL, frame0->windows_frame_info);
3402660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com  }
3412660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com
3422660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com  {  // To avoid reusing locals by mistake
3432660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    StackFrameX86 *frame1 = static_cast<StackFrameX86 *>(frames->at(1));
3442660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(StackFrame::FRAME_TRUST_SCAN, frame1->trust);
3452660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    // I'd argue that CONTEXT_VALID_EBP shouldn't be here, since the
3462660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    // walker does not actually fetch the EBP after a scan (forcing the
3472660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    // next frame to be scanned as well). But let's grandfather the existing
3482660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    // behavior in for now.
3492660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    ASSERT_EQ((StackFrameX86::CONTEXT_VALID_EIP
3502660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com               | StackFrameX86::CONTEXT_VALID_ESP
3512660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com               | StackFrameX86::CONTEXT_VALID_EBP),
3522660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com              frame1->context_validity);
3532660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(0x4000129dU, frame1->instruction + 1);
3542660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(0x4000129dU, frame1->context.eip);
3552660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(0x80000064U, frame1->context.esp);
3562660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(0xd43eed6eU, frame1->context.ebp);
3572660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(NULL, frame1->windows_frame_info);
3582660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com  }
3599c30407f7f2c6e6a352cd62fe4be21fe55ee1879ted.mielczarek}
3609c30407f7f2c6e6a352cd62fe4be21fe55ee1879ted.mielczarek
361a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy// Use Windows frame data (a "STACK WIN 4" record, from a
362a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy// FrameTypeFrameData DIA record) to walk a stack frame.
363a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandyTEST_F(GetCallerFrame, WindowsFrameData) {
364a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy  SetModuleSymbols(&module1,
365a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy                   "STACK WIN 4 aa85 176 0 0 4 10 4 0 1"
366a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy                   " $T2 $esp .cbSavedRegs + ="
367a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy                   " $T0 .raSearchStart ="
368a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy                   " $eip $T0 ^ ="
369a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy                   " $esp $T0 4 + ="
370a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy                   " $ebx $T2 4  - ^ ="
371a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy                   " $edi $T2 8  - ^ ="
372a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy                   " $esi $T2 12 - ^ ="
373a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy                   " $ebp $T2 16 - ^ =\n");
374a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy  Label frame1_esp, frame1_ebp;
375a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy  stack_section.start() = 0x80000000;
376a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy  stack_section
377a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy    // frame 0
378a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy    .D32(frame1_ebp)                    // saved regs: %ebp
379a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy    .D32(0xa7120d1a)                    //             %esi
380a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy    .D32(0x630891be)                    //             %edi
381a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy    .D32(0x9068a878)                    //             %ebx
382a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy    .D32(0xa08ea45f)                    // locals: unused
383a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy    .D32(0x40001350)                    // return address
384a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy    // frame 1
385a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy    .Mark(&frame1_esp)
386a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy    .Append(12, 0)                      // empty space
387a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy    .Mark(&frame1_ebp)
388a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy    .D32(0)                             // saved %ebp (stack end)
389a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy    .D32(0);                            // saved %eip (stack end)
390a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy
391a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy  RegionFromSection();
392a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy  raw_context.eip = 0x4000aa85;
393a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy  raw_context.esp = stack_section.start().Value();
394a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy  raw_context.ebp = 0xf052c1de;         // should not be needed to walk frame
395a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy
3969753aff85a9a20dbe294529b4184d9686ec42cddSiyangXie@gmail.com  StackFrameSymbolizer frame_symbolizer(&supplier, &resolver);
397a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy  StackwalkerX86 walker(&system_info, &raw_context, &stack_region, &modules,
3989753aff85a9a20dbe294529b4184d9686ec42cddSiyangXie@gmail.com                        &frame_symbolizer);
399a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy  ASSERT_TRUE(walker.Walk(&call_stack));
400a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy  frames = call_stack.frames();
401a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy  ASSERT_EQ(2U, frames->size());
402a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy
4032660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com  {  // To avoid reusing locals by mistake
4042660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    StackFrameX86 *frame0 = static_cast<StackFrameX86 *>(frames->at(0));
4052660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust);
4062660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    ASSERT_EQ(StackFrameX86::CONTEXT_VALID_ALL, frame0->context_validity);
4072660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(0x4000aa85U, frame0->instruction);
4082660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(0x4000aa85U, frame0->context.eip);
4092660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(stack_section.start().Value(), frame0->context.esp);
4102660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(0xf052c1deU, frame0->context.ebp);
4112660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_TRUE(frame0->windows_frame_info != NULL);
4122660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com  }
4132660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com
4142660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com  {  // To avoid reusing locals by mistake
4152660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    StackFrameX86 *frame1 = static_cast<StackFrameX86 *>(frames->at(1));
4162660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(StackFrame::FRAME_TRUST_CFI, frame1->trust);
4172660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    ASSERT_EQ((StackFrameX86::CONTEXT_VALID_EIP
4182660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com               | StackFrameX86::CONTEXT_VALID_ESP
4192660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com               | StackFrameX86::CONTEXT_VALID_EBP
4202660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com               | StackFrameX86::CONTEXT_VALID_EBX
4212660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com               | StackFrameX86::CONTEXT_VALID_ESI
4222660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com               | StackFrameX86::CONTEXT_VALID_EDI),
4232660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com              frame1->context_validity);
4242660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(0x40001350U, frame1->instruction + 1);
4252660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(0x40001350U, frame1->context.eip);
4262660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(frame1_esp.Value(), frame1->context.esp);
4272660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(frame1_ebp.Value(), frame1->context.ebp);
4282660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(0x9068a878U, frame1->context.ebx);
4292660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(0xa7120d1aU, frame1->context.esi);
4302660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(0x630891beU, frame1->context.edi);
4312660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(NULL, frame1->windows_frame_info);
4322660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com  }
433a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy}
434a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy
435a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy// Use Windows frame data (a "STACK WIN 4" record, from a
4366679ad568c3e3796acab4022dbfdcfad484e34e8mark@chromium.org// FrameTypeFrameData DIA record) to walk a stack frame where the stack
4376679ad568c3e3796acab4022dbfdcfad484e34e8mark@chromium.org// is aligned and we must search
4386679ad568c3e3796acab4022dbfdcfad484e34e8mark@chromium.orgTEST_F(GetCallerFrame, WindowsFrameDataAligned) {
4396679ad568c3e3796acab4022dbfdcfad484e34e8mark@chromium.org  SetModuleSymbols(&module1,
4406679ad568c3e3796acab4022dbfdcfad484e34e8mark@chromium.org                   "STACK WIN 4 aa85 176 0 0 4 4 8 0 1"
4416679ad568c3e3796acab4022dbfdcfad484e34e8mark@chromium.org		   " $T1 .raSearch ="
4426679ad568c3e3796acab4022dbfdcfad484e34e8mark@chromium.org		   " $T0 $T1 4 - 8 @ ="
4436679ad568c3e3796acab4022dbfdcfad484e34e8mark@chromium.org		   " $ebp $T1 4 - ^ ="
4446679ad568c3e3796acab4022dbfdcfad484e34e8mark@chromium.org		   " $eip $T1 ^ ="
4456679ad568c3e3796acab4022dbfdcfad484e34e8mark@chromium.org		   " $esp $T1 4 + =");
4466679ad568c3e3796acab4022dbfdcfad484e34e8mark@chromium.org  Label frame1_esp, frame1_ebp;
4476679ad568c3e3796acab4022dbfdcfad484e34e8mark@chromium.org  stack_section.start() = 0x80000000;
4486679ad568c3e3796acab4022dbfdcfad484e34e8mark@chromium.org  stack_section
4496679ad568c3e3796acab4022dbfdcfad484e34e8mark@chromium.org    // frame 0
4506679ad568c3e3796acab4022dbfdcfad484e34e8mark@chromium.org    .D32(0x0ffa0ffa)                    // unused saved register
4516679ad568c3e3796acab4022dbfdcfad484e34e8mark@chromium.org    .D32(0xdeaddead)                    // locals
4526679ad568c3e3796acab4022dbfdcfad484e34e8mark@chromium.org    .D32(0xbeefbeef)
4536679ad568c3e3796acab4022dbfdcfad484e34e8mark@chromium.org    .D32(0)                             // 8-byte alignment
4546679ad568c3e3796acab4022dbfdcfad484e34e8mark@chromium.org    .D32(frame1_ebp)
4556679ad568c3e3796acab4022dbfdcfad484e34e8mark@chromium.org    .D32(0x5000129d)                    // return address
4566679ad568c3e3796acab4022dbfdcfad484e34e8mark@chromium.org    // frame 1
4576679ad568c3e3796acab4022dbfdcfad484e34e8mark@chromium.org    .Mark(&frame1_esp)
4586679ad568c3e3796acab4022dbfdcfad484e34e8mark@chromium.org    .D32(0x1)                           // parameter
4596679ad568c3e3796acab4022dbfdcfad484e34e8mark@chromium.org    .Mark(&frame1_ebp)
4606679ad568c3e3796acab4022dbfdcfad484e34e8mark@chromium.org    .D32(0)                             // saved %ebp (stack end)
4616679ad568c3e3796acab4022dbfdcfad484e34e8mark@chromium.org    .D32(0);                            // saved %eip (stack end)
4626679ad568c3e3796acab4022dbfdcfad484e34e8mark@chromium.org
4636679ad568c3e3796acab4022dbfdcfad484e34e8mark@chromium.org  RegionFromSection();
4646679ad568c3e3796acab4022dbfdcfad484e34e8mark@chromium.org  raw_context.eip = 0x4000aa85;
4656679ad568c3e3796acab4022dbfdcfad484e34e8mark@chromium.org  raw_context.esp = stack_section.start().Value();
4666679ad568c3e3796acab4022dbfdcfad484e34e8mark@chromium.org  raw_context.ebp = 0xf052c1de;         // should not be needed to walk frame
4676679ad568c3e3796acab4022dbfdcfad484e34e8mark@chromium.org
4689753aff85a9a20dbe294529b4184d9686ec42cddSiyangXie@gmail.com  StackFrameSymbolizer frame_symbolizer(&supplier, &resolver);
4696679ad568c3e3796acab4022dbfdcfad484e34e8mark@chromium.org  StackwalkerX86 walker(&system_info, &raw_context, &stack_region, &modules,
4709753aff85a9a20dbe294529b4184d9686ec42cddSiyangXie@gmail.com                        &frame_symbolizer);
4716679ad568c3e3796acab4022dbfdcfad484e34e8mark@chromium.org  ASSERT_TRUE(walker.Walk(&call_stack));
4726679ad568c3e3796acab4022dbfdcfad484e34e8mark@chromium.org  frames = call_stack.frames();
4736679ad568c3e3796acab4022dbfdcfad484e34e8mark@chromium.org  ASSERT_EQ(2U, frames->size());
4746679ad568c3e3796acab4022dbfdcfad484e34e8mark@chromium.org
4752660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com  {  // To avoid reusing locals by mistake
4762660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    StackFrameX86 *frame0 = static_cast<StackFrameX86 *>(frames->at(0));
4772660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust);
4782660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    ASSERT_EQ(StackFrameX86::CONTEXT_VALID_ALL, frame0->context_validity);
4792660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(0x4000aa85U, frame0->instruction);
4802660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(0x4000aa85U, frame0->context.eip);
4812660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(stack_section.start().Value(), frame0->context.esp);
4822660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(0xf052c1deU, frame0->context.ebp);
4832660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_TRUE(frame0->windows_frame_info != NULL);
4842660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com  }
4852660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com
4862660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com  {  // To avoid reusing locals by mistake
4872660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    StackFrameX86 *frame1 = static_cast<StackFrameX86 *>(frames->at(1));
4882660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(StackFrame::FRAME_TRUST_CFI, frame1->trust);
4892660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    ASSERT_EQ((StackFrameX86::CONTEXT_VALID_EIP
4902660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com               | StackFrameX86::CONTEXT_VALID_ESP
4912660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com               | StackFrameX86::CONTEXT_VALID_EBP),
4922660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com              frame1->context_validity);
4932660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(0x5000129dU, frame1->instruction + 1);
4942660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(0x5000129dU, frame1->context.eip);
4952660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(frame1_esp.Value(), frame1->context.esp);
4962660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(frame1_ebp.Value(), frame1->context.ebp);
4972660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(NULL, frame1->windows_frame_info);
4982660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com  }
4996679ad568c3e3796acab4022dbfdcfad484e34e8mark@chromium.org}
5006679ad568c3e3796acab4022dbfdcfad484e34e8mark@chromium.org
5016679ad568c3e3796acab4022dbfdcfad484e34e8mark@chromium.org// Use Windows frame data (a "STACK WIN 4" record, from a
502a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy// FrameTypeFrameData DIA record) to walk a frame, and depend on the
503a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy// parameter size from the callee as well.
504a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandyTEST_F(GetCallerFrame, WindowsFrameDataParameterSize) {
505a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy  SetModuleSymbols(&module1, "FUNC 1000 100 c module1::wheedle\n");
506a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy  SetModuleSymbols(&module2,
5076d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy                   // Note bogus parameter size in FUNC record; the stack walker
5086d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy                   // should prefer the STACK WIN record, and see '4' below.
509a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy                   "FUNC aa85 176 beef module2::whine\n"
510a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy                   "STACK WIN 4 aa85 176 0 0 4 10 4 0 1"
511a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy                   " $T2 $esp .cbLocals + .cbSavedRegs + ="
512a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy                   " $T0 .raSearchStart ="
513a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy                   " $eip $T0 ^ ="
514a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy                   " $esp $T0 4 + ="
515a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy                   " $ebp $T0 20 - ^ ="
516a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy                   " $ebx $T0 8 - ^ =\n");
517a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy  Label frame0_esp, frame0_ebp;
518a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy  Label frame1_esp;
519a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy  Label frame2_esp, frame2_ebp;
520a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy  stack_section.start() = 0x80000000;
521a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy  stack_section
522a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy    // frame 0, in module1::wheedle.  Traditional frame.
523a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy    .Mark(&frame0_esp)
524a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy    .Append(16, 0)      // frame space
525a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy    .Mark(&frame0_ebp)
526a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy    .D32(0x6fa902e0)    // saved %ebp.  Not a frame pointer.
527a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy    .D32(0x5000aa95)    // return address, in module2::whine
528a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy    // frame 1, in module2::whine.  FrameData frame.
529a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy    .Mark(&frame1_esp)
530a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy    .D32(0xbaa0cb7a)    // argument 3 passed to module1::wheedle
531a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy    .D32(0xbdc92f9f)    // argument 2
532a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy    .D32(0x0b1d8442)    // argument 1
533a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy    .D32(frame2_ebp)    // saved %ebp
534a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy    .D32(0xb1b90a15)    // unused
535a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy    .D32(0xf18e072d)    // unused
536a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy    .D32(0x2558c7f3)    // saved %ebx
537a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy    .D32(0x0365e25e)    // unused
538a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy    .D32(0x2a179e38)    // return address; $T0 points here
539a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy    // frame 2, in no module
540a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy    .Mark(&frame2_esp)
541a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy    .Append(12, 0)      // empty space
542a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy    .Mark(&frame2_ebp)
543a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy    .D32(0)             // saved %ebp (stack end)
544a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy    .D32(0);            // saved %eip (stack end)
545a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy
546a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy  RegionFromSection();
547a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy  raw_context.eip = 0x40001004; // in module1::wheedle
548a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy  raw_context.esp = stack_section.start().Value();
549a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy  raw_context.ebp = frame0_ebp.Value();
550a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy
5519753aff85a9a20dbe294529b4184d9686ec42cddSiyangXie@gmail.com  StackFrameSymbolizer frame_symbolizer(&supplier, &resolver);
552a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy  StackwalkerX86 walker(&system_info, &raw_context, &stack_region, &modules,
5539753aff85a9a20dbe294529b4184d9686ec42cddSiyangXie@gmail.com                        &frame_symbolizer);
554a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy  ASSERT_TRUE(walker.Walk(&call_stack));
555a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy  frames = call_stack.frames();
556a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy  ASSERT_EQ(3U, frames->size());
557a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy
5582660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com  {  // To avoid reusing locals by mistake
5592660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    StackFrameX86 *frame0 = static_cast<StackFrameX86 *>(frames->at(0));
5602660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust);
5612660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    ASSERT_EQ(StackFrameX86::CONTEXT_VALID_ALL, frame0->context_validity);
5622660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(0x40001004U, frame0->instruction);
5632660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(0x40001004U, frame0->context.eip);
5642660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(frame0_esp.Value(), frame0->context.esp);
5652660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(frame0_ebp.Value(), frame0->context.ebp);
5662660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(&module1, frame0->module);
5672660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ("module1::wheedle", frame0->function_name);
5682660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(0x40001000U, frame0->function_base);
5692660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    // The FUNC record for module1::wheedle should have produced a
5702660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    // WindowsFrameInfo structure with only the parameter size valid.
5712660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    ASSERT_TRUE(frame0->windows_frame_info != NULL);
5722660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(WindowsFrameInfo::VALID_PARAMETER_SIZE,
5732660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com              frame0->windows_frame_info->valid);
5742660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(WindowsFrameInfo::STACK_INFO_UNKNOWN,
5752660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com              frame0->windows_frame_info->type_);
5762660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(12U, frame0->windows_frame_info->parameter_size);
5772660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com  }
5782660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com
5792660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com  {  // To avoid reusing locals by mistake
5802660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    StackFrameX86 *frame1 = static_cast<StackFrameX86 *>(frames->at(1));
5812660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(StackFrame::FRAME_TRUST_FP, frame1->trust);
5822660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    ASSERT_EQ((StackFrameX86::CONTEXT_VALID_EIP
5832660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com               | StackFrameX86::CONTEXT_VALID_ESP
5842660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com               | StackFrameX86::CONTEXT_VALID_EBP),
5852660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com              frame1->context_validity);
5862660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(0x5000aa95U, frame1->instruction + 1);
5872660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(0x5000aa95U, frame1->context.eip);
5882660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(frame1_esp.Value(), frame1->context.esp);
5892660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(0x6fa902e0U, frame1->context.ebp);
5902660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(&module2, frame1->module);
5912660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ("module2::whine", frame1->function_name);
5922660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(0x5000aa85U, frame1->function_base);
5932660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    ASSERT_TRUE(frame1->windows_frame_info != NULL);
5942660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(WindowsFrameInfo::VALID_ALL, frame1->windows_frame_info->valid);
5952660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(WindowsFrameInfo::STACK_INFO_FRAME_DATA,
5962660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com              frame1->windows_frame_info->type_);
5972660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    // This should not see the 0xbeef parameter size from the FUNC
5982660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    // record, but should instead see the STACK WIN record.
5992660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(4U, frame1->windows_frame_info->parameter_size);
6002660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com  }
6012660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com
6022660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com  {  // To avoid reusing locals by mistake
6032660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    StackFrameX86 *frame2 = static_cast<StackFrameX86 *>(frames->at(2));
6042660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(StackFrame::FRAME_TRUST_CFI, frame2->trust);
6052660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    ASSERT_EQ((StackFrameX86::CONTEXT_VALID_EIP
6062660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com               | StackFrameX86::CONTEXT_VALID_ESP
6072660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com               | StackFrameX86::CONTEXT_VALID_EBP
6082660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com               | StackFrameX86::CONTEXT_VALID_EBX),
6092660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com              frame2->context_validity);
6102660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(0x2a179e38U, frame2->instruction + 1);
6112660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(0x2a179e38U, frame2->context.eip);
6122660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(frame2_esp.Value(), frame2->context.esp);
6132660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(frame2_ebp.Value(), frame2->context.ebp);
6142660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(0x2558c7f3U, frame2->context.ebx);
6152660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(NULL, frame2->module);
6162660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(NULL, frame2->windows_frame_info);
6172660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com  }
618a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy}
619a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy
620a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy// Use Windows frame data (a "STACK WIN 4" record, from a
621a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy// FrameTypeFrameData DIA record) to walk a stack frame, where the
6226d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy// expression fails to yield both an $eip and an $ebp value, and the stack
6236d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy// walker must scan.
624a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandyTEST_F(GetCallerFrame, WindowsFrameDataScan) {
625a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy  SetModuleSymbols(&module1,
626a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy                   "STACK WIN 4 c8c 111 0 0 4 10 4 0 1 bad program string\n");
627a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy  // Mark frame 1's PC as the end of the stack.
628a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy  SetModuleSymbols(&module2,
629a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy                   "FUNC 7c38 accf 0 module2::function\n"
630a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy                   "STACK WIN 4 7c38 accf 0 0 4 10 4 0 1 $eip 0 = $ebp 0 =\n");
631a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy  Label frame1_esp;
632a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy  stack_section.start() = 0x80000000;
633a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy  stack_section
634a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy    // frame 0
635a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy    .Append(16, 0x2a)                   // unused, garbage
636a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy    .D32(0x50007ce9)                    // return address
637a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy    // frame 1
638a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy    .Mark(&frame1_esp)
639a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy    .Append(8, 0);                      // empty space
640a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy
641a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy  RegionFromSection();
642a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy  raw_context.eip = 0x40000c9c;
643a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy  raw_context.esp = stack_section.start().Value();
644a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy  raw_context.ebp = 0x2ae314cd;         // should not be needed to walk frame
645a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy
6469753aff85a9a20dbe294529b4184d9686ec42cddSiyangXie@gmail.com  StackFrameSymbolizer frame_symbolizer(&supplier, &resolver);
647a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy  StackwalkerX86 walker(&system_info, &raw_context, &stack_region, &modules,
6489753aff85a9a20dbe294529b4184d9686ec42cddSiyangXie@gmail.com                        &frame_symbolizer);
649a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy  ASSERT_TRUE(walker.Walk(&call_stack));
650a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy  frames = call_stack.frames();
651a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy  ASSERT_EQ(2U, frames->size());
652a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy
6532660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com  {  // To avoid reusing locals by mistake
6542660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    StackFrameX86 *frame0 = static_cast<StackFrameX86 *>(frames->at(0));
6552660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust);
6562660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    ASSERT_EQ(StackFrameX86::CONTEXT_VALID_ALL, frame0->context_validity);
6572660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(0x40000c9cU, frame0->instruction);
6582660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(0x40000c9cU, frame0->context.eip);
6592660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(stack_section.start().Value(), frame0->context.esp);
6602660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(0x2ae314cdU, frame0->context.ebp);
6612660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_TRUE(frame0->windows_frame_info != NULL);
6622660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com  }
6632660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com
6642660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com  {  // To avoid reusing locals by mistake
6652660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    StackFrameX86 *frame1 = static_cast<StackFrameX86 *>(frames->at(1));
6662660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(StackFrame::FRAME_TRUST_SCAN, frame1->trust);
6672660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    // I'd argue that CONTEXT_VALID_EBP shouldn't be here, since the walker
6682660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    // does not actually fetch the EBP after a scan (forcing the next frame
6692660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    // to be scanned as well). But let's grandfather the existing behavior in
6702660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    // for now.
6712660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    ASSERT_EQ((StackFrameX86::CONTEXT_VALID_EIP
6722660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com               | StackFrameX86::CONTEXT_VALID_ESP
6732660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com               | StackFrameX86::CONTEXT_VALID_EBP),
6742660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com              frame1->context_validity);
6752660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(0x50007ce9U, frame1->instruction + 1);
6762660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(0x50007ce9U, frame1->context.eip);
6772660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(frame1_esp.Value(), frame1->context.esp);
6782660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_TRUE(frame1->windows_frame_info != NULL);
6792660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com  }
680a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy}
681a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy
682a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy// Use Windows frame data (a "STACK WIN 4" record, from a
683a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy// FrameTypeFrameData DIA record) to walk a stack frame, where the
6846d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy// expression yields an $eip that falls outside of any module, and the
6856d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy// stack walker must scan.
686a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandyTEST_F(GetCallerFrame, WindowsFrameDataBadEIPScan) {
687a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy  SetModuleSymbols(&module1,
688a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy                   "STACK WIN 4 6e6 e7 0 0 0 8 4 0 1"
689a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy                   // A traditional frame, actually.
690a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy                   " $eip $ebp 4 + ^ = $esp $ebp 8 + = $ebp $ebp ^ =\n");
691a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy  // Mark frame 1's PC as the end of the stack.
692a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy  SetModuleSymbols(&module2,
693a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy                   "FUNC cfdb 8406 0 module2::function\n"
694a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy                   "STACK WIN 4 cfdb 8406 0 0 0 0 0 0 1 $eip 0 = $ebp 0 =\n");
695a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy  stack_section.start() = 0x80000000;
696a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy
697a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy  // In this stack, the context's %ebp is pointing at the wrong place, so
6986d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  // the stack walker needs to scan to find the return address, and then
6996d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  // scan again to find the caller's saved %ebp.
700a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy  Label frame0_ebp, frame1_ebp, frame1_esp;
701a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy  stack_section
702a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy    // frame 0
703a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy    .Append(8, 0x2a)            // garbage
704a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy    .Mark(&frame0_ebp)          // frame 0 %ebp points here, but should point
705a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy                                // at *** below
706a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy    // The STACK WIN record says that the following two values are
707a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy    // frame 1's saved %ebp and return address, but the %ebp is wrong;
7086d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy    // they're garbage. The stack walker will scan for the right values.
709a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy    .D32(0x3d937b2b)            // alleged to be frame 1's saved %ebp
710a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy    .D32(0x17847f5b)            // alleged to be frame 1's return address
711a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy    .D32(frame1_ebp)            // frame 1's real saved %ebp; scan will find
712a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy    .D32(0x2b2b2b2b)            // first word of realigned register save area
713a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy    // *** frame 0 %ebp ought to be pointing here
714a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy    .D32(0x2c2c2c2c)            // realigned locals area
715a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy    .D32(0x5000d000)            // frame 1's real saved %eip; scan will find
716a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy    // Frame 1, in module2::function. The STACK WIN record describes
717a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy    // this as the oldest frame, without referring to its contents, so
7186d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy    // we needn't to provide any actual data here.
719a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy    .Mark(&frame1_esp)
720a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy    .Mark(&frame1_ebp)          // frame 1 %ebp points here
721a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy    // A dummy value for frame 1's %ebp to point at. The scan recognizes the
722a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy    // saved %ebp because it points to a valid word in the stack memory region.
723a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy    .D32(0x2d2d2d2d);
724a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy
725a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy  RegionFromSection();
726a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy  raw_context.eip = 0x40000700;
727a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy  raw_context.esp = stack_section.start().Value();
728a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy  raw_context.ebp = frame0_ebp.Value();
729a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy
7309753aff85a9a20dbe294529b4184d9686ec42cddSiyangXie@gmail.com  StackFrameSymbolizer frame_symbolizer(&supplier, &resolver);
731a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy  StackwalkerX86 walker(&system_info, &raw_context, &stack_region, &modules,
7329753aff85a9a20dbe294529b4184d9686ec42cddSiyangXie@gmail.com                        &frame_symbolizer);
733a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy  ASSERT_TRUE(walker.Walk(&call_stack));
734a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy  frames = call_stack.frames();
735a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy  ASSERT_EQ(2U, frames->size());
736a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy
7372660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com  {  // To avoid reusing locals by mistake
7382660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    StackFrameX86 *frame0 = static_cast<StackFrameX86 *>(frames->at(0));
7392660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust);
7402660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    ASSERT_EQ(StackFrameX86::CONTEXT_VALID_ALL, frame0->context_validity);
7412660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(0x40000700U, frame0->instruction);
7422660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(0x40000700U, frame0->context.eip);
7432660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(stack_section.start().Value(), frame0->context.esp);
7442660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(frame0_ebp.Value(), frame0->context.ebp);
7452660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_TRUE(frame0->windows_frame_info != NULL);
7462660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com  }
7472660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com
7482660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com  {  // To avoid reusing locals by mistake
7492660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    StackFrameX86 *frame1 = static_cast<StackFrameX86 *>(frames->at(1));
7502660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(StackFrame::FRAME_TRUST_CFI_SCAN, frame1->trust);
7512660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    // I'd argue that CONTEXT_VALID_EBP shouldn't be here, since the
7522660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    // walker does not actually fetch the EBP after a scan (forcing the
7532660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    // next frame to be scanned as well). But let's grandfather the existing
7542660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    // behavior in for now.
7552660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    ASSERT_EQ((StackFrameX86::CONTEXT_VALID_EIP
7562660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com               | StackFrameX86::CONTEXT_VALID_ESP
7572660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com               | StackFrameX86::CONTEXT_VALID_EBP),
7582660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com              frame1->context_validity);
7592660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(0x5000d000U, frame1->instruction + 1);
7602660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(0x5000d000U, frame1->context.eip);
7612660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(frame1_esp.Value(), frame1->context.esp);
7622660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(frame1_ebp.Value(), frame1->context.ebp);
7632660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_TRUE(frame1->windows_frame_info != NULL);
7642660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com  }
765a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy}
766a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy
767a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy// Use Windows FrameTypeFPO data to walk a stack frame for a function that
768a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy// does not modify %ebp from the value it had in the caller.
769a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandyTEST_F(GetCallerFrame, WindowsFPOUnchangedEBP) {
770a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy  SetModuleSymbols(&module1,
7716d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy                   // Note bogus parameter size in FUNC record; the walker
7726d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy                   // should prefer the STACK WIN record, and see the '8' below.
773a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy                   "FUNC e8a8 100 feeb module1::discombobulated\n"
774a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy                   "STACK WIN 0 e8a8 100 0 0 8 4 10 0 0 0\n");
775a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy  Label frame0_esp;
776a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy  Label frame1_esp, frame1_ebp;
777a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy  stack_section.start() = 0x80000000;
778a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy  stack_section
779a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy    // frame 0, in module1::wheedle.  FrameTypeFPO (STACK WIN 0) frame.
780a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy    .Mark(&frame0_esp)
781a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy    // no outgoing parameters; this is the youngest frame.
782a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy    .D32(0x7c521352)    // four bytes of saved registers
783a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy    .Append(0x10, 0x42) // local area
784a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy    .D32(0x40009b5b)    // return address, in module1, no function
785a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy    // frame 1, in module1, no function.
786a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy    .Mark(&frame1_esp)
787a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy    .D32(0xf60ea7fc)    // junk
788a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy    .Mark(&frame1_ebp)
789a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy    .D32(0)             // saved %ebp (stack end)
790a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy    .D32(0);            // saved %eip (stack end)
791a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy
792a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy  RegionFromSection();
793a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy  raw_context.eip = 0x4000e8b8; // in module1::whine
794a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy  raw_context.esp = stack_section.start().Value();
795a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy  // Frame pointer unchanged from caller.
796a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy  raw_context.ebp = frame1_ebp.Value();
797a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy
7989753aff85a9a20dbe294529b4184d9686ec42cddSiyangXie@gmail.com  StackFrameSymbolizer frame_symbolizer(&supplier, &resolver);
799a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy  StackwalkerX86 walker(&system_info, &raw_context, &stack_region, &modules,
8009753aff85a9a20dbe294529b4184d9686ec42cddSiyangXie@gmail.com                        &frame_symbolizer);
801a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy  ASSERT_TRUE(walker.Walk(&call_stack));
802a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy  frames = call_stack.frames();
803a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy  ASSERT_EQ(2U, frames->size());
804a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy
8052660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com  {  // To avoid reusing locals by mistake
8062660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    StackFrameX86 *frame0 = static_cast<StackFrameX86 *>(frames->at(0));
8072660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust);
8082660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    ASSERT_EQ(StackFrameX86::CONTEXT_VALID_ALL, frame0->context_validity);
8092660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(0x4000e8b8U, frame0->instruction);
8102660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(0x4000e8b8U, frame0->context.eip);
8112660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(frame0_esp.Value(), frame0->context.esp);
8122660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(frame1_ebp.Value(), frame0->context.ebp); // unchanged from caller
8132660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(&module1, frame0->module);
8142660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ("module1::discombobulated", frame0->function_name);
8152660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(0x4000e8a8U, frame0->function_base);
8162660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    // The STACK WIN record for module1::discombobulated should have
8172660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    // produced a fully populated WindowsFrameInfo structure.
8182660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    ASSERT_TRUE(frame0->windows_frame_info != NULL);
8192660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(WindowsFrameInfo::VALID_ALL, frame0->windows_frame_info->valid);
8202660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(WindowsFrameInfo::STACK_INFO_FPO,
8212660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com              frame0->windows_frame_info->type_);
8222660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(0x10U, frame0->windows_frame_info->local_size);
8232660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com  }
8242660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com
8252660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com  {  // To avoid reusing locals by mistake
8262660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    StackFrameX86 *frame1 = static_cast<StackFrameX86 *>(frames->at(1));
8272660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(StackFrame::FRAME_TRUST_CFI, frame1->trust);
8282660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    ASSERT_EQ((StackFrameX86::CONTEXT_VALID_EIP
8292660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com               | StackFrameX86::CONTEXT_VALID_ESP
8302660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com               | StackFrameX86::CONTEXT_VALID_EBP),
8312660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com              frame1->context_validity);
8322660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(0x40009b5bU, frame1->instruction + 1);
8332660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(0x40009b5bU, frame1->context.eip);
8342660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(frame1_esp.Value(), frame1->context.esp);
8352660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(frame1_ebp.Value(), frame1->context.ebp);
8362660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(&module1, frame1->module);
8372660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ("", frame1->function_name);
8382660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(NULL, frame1->windows_frame_info);
8392660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com  }
840a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy}
841a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy
842a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy// Use Windows FrameTypeFPO data to walk a stack frame for a function
843a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy// that uses %ebp for its own purposes, saving the value it had in the
844a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy// caller in the standard place in the saved register area.
845a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandyTEST_F(GetCallerFrame, WindowsFPOUsedEBP) {
846a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy  SetModuleSymbols(&module1,
8476d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy                   // Note bogus parameter size in FUNC record; the walker
8486d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy                   // should prefer the STACK WIN record, and see the '8' below.
849a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy                   "FUNC 9aa8 e6 abbe module1::RaisedByTheAliens\n"
850a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy                   "STACK WIN 0 9aa8 e6 a 0 10 8 4 0 0 1\n");
851a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy  Label frame0_esp;
852a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy  Label frame1_esp, frame1_ebp;
853a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy  stack_section.start() = 0x80000000;
854a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy  stack_section
855a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy    // frame 0, in module1::wheedle.  FrameTypeFPO (STACK WIN 0) frame.
856a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy    .Mark(&frame0_esp)
857a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy    // no outgoing parameters; this is the youngest frame.
858a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy    .D32(frame1_ebp)    // saved register area: saved %ebp
859a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy    .D32(0xb68bd5f9)    // saved register area: something else
860a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy    .D32(0xd25d05fc)    // local area
861a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy    .D32(0x4000debe)    // return address, in module1, no function
862a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy    // frame 1, in module1, no function.
863a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy    .Mark(&frame1_esp)
864a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy    .D32(0xf0c9a974)    // junk
865a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy    .Mark(&frame1_ebp)
866a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy    .D32(0)             // saved %ebp (stack end)
867a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy    .D32(0);            // saved %eip (stack end)
868a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy
869a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy  RegionFromSection();
870a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy  raw_context.eip = 0x40009ab8; // in module1::RaisedByTheAliens
871a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy  raw_context.esp = stack_section.start().Value();
872a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy  // RaisedByTheAliens uses %ebp for its own mysterious purposes.
873a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy  raw_context.ebp = 0xecbdd1a5;
874a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy
8759753aff85a9a20dbe294529b4184d9686ec42cddSiyangXie@gmail.com  StackFrameSymbolizer frame_symbolizer(&supplier, &resolver);
876a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy  StackwalkerX86 walker(&system_info, &raw_context, &stack_region, &modules,
8779753aff85a9a20dbe294529b4184d9686ec42cddSiyangXie@gmail.com                        &frame_symbolizer);
878a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy  ASSERT_TRUE(walker.Walk(&call_stack));
879a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy  frames = call_stack.frames();
880a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy  ASSERT_EQ(2U, frames->size());
881a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy
8822660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com  {  // To avoid reusing locals by mistake
8832660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    StackFrameX86 *frame0 = static_cast<StackFrameX86 *>(frames->at(0));
8842660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust);
8852660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    ASSERT_EQ(StackFrameX86::CONTEXT_VALID_ALL, frame0->context_validity);
8862660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(0x40009ab8U, frame0->instruction);
8872660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(0x40009ab8U, frame0->context.eip);
8882660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(frame0_esp.Value(), frame0->context.esp);
8892660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(0xecbdd1a5, frame0->context.ebp);
8902660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(&module1, frame0->module);
8912660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ("module1::RaisedByTheAliens", frame0->function_name);
8922660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(0x40009aa8U, frame0->function_base);
8932660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    // The STACK WIN record for module1::RaisedByTheAliens should have
8942660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    // produced a fully populated WindowsFrameInfo structure.
8952660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    ASSERT_TRUE(frame0->windows_frame_info != NULL);
8962660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(WindowsFrameInfo::VALID_ALL, frame0->windows_frame_info->valid);
8972660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(WindowsFrameInfo::STACK_INFO_FPO,
8982660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com              frame0->windows_frame_info->type_);
8992660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ("", frame0->windows_frame_info->program_string);
9002660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_TRUE(frame0->windows_frame_info->allocates_base_pointer);
9012660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com  }
9022660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com
9032660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com  {  // To avoid reusing locals by mistake
9042660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    StackFrameX86 *frame1 = static_cast<StackFrameX86 *>(frames->at(1));
9052660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(StackFrame::FRAME_TRUST_CFI, frame1->trust);
9062660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    ASSERT_EQ((StackFrameX86::CONTEXT_VALID_EIP
9072660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com               | StackFrameX86::CONTEXT_VALID_ESP
9082660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com               | StackFrameX86::CONTEXT_VALID_EBP),
9092660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com              frame1->context_validity);
9102660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(0x4000debeU, frame1->instruction + 1);
9112660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(0x4000debeU, frame1->context.eip);
9122660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(frame1_esp.Value(), frame1->context.esp);
9132660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(frame1_ebp.Value(), frame1->context.ebp);
9142660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(&module1, frame1->module);
9152660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ("", frame1->function_name);
9162660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(NULL, frame1->windows_frame_info);
9172660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com  }
9182660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com}
9192660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com
9202660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com// This is a regression unit test which covers a bug which has to do with
9212660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com// FPO-optimized Windows system call stubs in the context frame.  There is
9222660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com// a more recent Windows system call dispatch mechanism which differs from
9232660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com// the one which is being tested here.  The newer system call dispatch
9242660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com// mechanism creates an extra context frame (KiFastSystemCallRet).
9252660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.comTEST_F(GetCallerFrame, WindowsFPOSystemCall) {
9262660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com  SetModuleSymbols(&module3,  // ntdll.dll
9272660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com                   "PUBLIC 1f8ac c ZwWaitForSingleObject\n"
9282660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com                   "STACK WIN 0 1f8ac 1b 0 0 c 0 0 0 0 0\n");
9292660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com  SetModuleSymbols(&module4,  // kernelbase.dll
9302660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com                   "PUBLIC 109f9 c WaitForSingleObjectEx\n"
9312660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com                   "PUBLIC 36590 0 _except_handler4\n"
9322660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com                   "STACK WIN 4 109f9 df c 0 c c 48 0 1 $T0 $ebp = $eip "
9332660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com                   "$T0 4 + ^ = $ebp $T0 ^ = $esp $T0 8 + = $L "
9342660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com                   "$T0 .cbSavedRegs - = $P $T0 8 + .cbParams + =\n"
9352660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com                   "STACK WIN 4 36590 154 17 0 10 0 14 0 1 $T0 $ebp = $eip "
9362660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com                   "$T0 4 + ^ = $ebp $T0 ^ = $esp $T0 8 + = $L $T0 "
9372660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com                   ".cbSavedRegs - = $P $T0 8 + .cbParams + =\n");
9382660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com  SetModuleSymbols(&module5,  // kernel32.dll
9392660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com                   "PUBLIC 11136 8 WaitForSingleObject\n"
9402660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com                   "PUBLIC 11151 c WaitForSingleObjectExImplementation\n"
9412660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com                   "STACK WIN 4 11136 16 5 0 8 0 0 0 1 $T0 $ebp = $eip "
9422660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com                   "$T0 4 + ^ = $ebp $T0 ^ = $esp $T0 8 + = $L "
9432660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com                   "$T0 .cbSavedRegs - = $P $T0 8 + .cbParams + =\n"
9442660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com                   "STACK WIN 4 11151 7a 5 0 c 0 0 0 1 $T0 $ebp = $eip "
9452660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com                   "$T0 4 + ^ = $ebp $T0 ^ = $esp $T0 8 + = $L "
9462660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com                   "$T0 .cbSavedRegs - = $P $T0 8 + .cbParams + =\n");
9472660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com  SetModuleSymbols(&module6,  // chrome.dll
9482660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com                   "FILE 7038 some_file_name.h\n"
9492660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com                   "FILE 839776 some_file_name.cc\n"
9502660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com                   "FUNC 217fda 17 4 function_217fda\n"
9512660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com                   "217fda 4 102 839776\n"
9522660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com                   "FUNC 217ff1 a 4 function_217ff1\n"
9532660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com                   "217ff1 0 594 7038\n"
9542660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com                   "217ff1 a 596 7038\n"
9552660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com                   "STACK WIN 0 217ff1 a 0 0 4 0 0 0 0 0\n");
9562660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com
9572660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com  Label frame0_esp, frame1_esp;
9582660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com  Label frame1_ebp, frame2_ebp, frame3_ebp;
9592660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com  stack_section.start() = 0x002ff290;
9602660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com  stack_section
9612660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    .Mark(&frame0_esp)
9622660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    .D32(0x771ef8c1)    // EIP in frame 0 (system call)
9632660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    .D32(0x75fa0a91)    // return address of frame 0
9642660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    .Mark(&frame1_esp)
9652660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    .D32(0x000017b0)    // args to child
9662660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    .D32(0x00000000)
9672660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    .D32(0x002ff2d8)
9682660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    .D32(0x88014a2e)
9692660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    .D32(0x002ff364)
9702660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    .D32(0x000017b0)
9712660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    .D32(0x00000000)
9722660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    .D32(0x00000024)
9732660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    .D32(0x00000001)
9742660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    .D32(0x00000000)
9752660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    .D32(0x00000000)
9762660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    .D32(0x00000000)
9772660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    .D32(0x00000000)
9782660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    .D32(0x00000000)
9792660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    .D32(0x00000000)
9802660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    .D32(0x00000000)
9812660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    .D32(0x9e3b9800)
9822660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    .D32(0xfffffff7)
9832660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    .D32(0x00000000)
9842660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    .D32(0x002ff2a4)
9852660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    .D32(0x64a07ff1)    // random value to be confused with a return address
9862660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    .D32(0x002ff8dc)
9872660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    .D32(0x75fc6590)    // random value to be confused with a return address
9882660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    .D32(0xfdd2c6ea)
9892660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    .D32(0x00000000)
9902660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    .Mark(&frame1_ebp)
9912660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    .D32(frame2_ebp)    // Child EBP
9922660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    .D32(0x75741194)    // return address of frame 1
9932660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    .D32(0x000017b0)    // args to child
9942660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    .D32(0x0036ee80)
9952660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    .D32(0x00000000)
9962660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    .D32(0x65bc7d14)
9972660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    .Mark(&frame2_ebp)
9982660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    .D32(frame3_ebp)    // Child EBP
9992660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    .D32(0x75741148)    // return address of frame 2
10002660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    .D32(0x000017b0)    // args to child
10012660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    .D32(0x0036ee80)
10022660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    .D32(0x00000000)
10032660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    .Mark(&frame3_ebp)
10042660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    .D32(0)             // saved %ebp (stack end)
10052660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    .D32(0);            // saved %eip (stack end)
10062660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com
10072660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com  RegionFromSection();
10082660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com  raw_context.eip = 0x771ef8c1;  // in ntdll::ZwWaitForSingleObject
10092660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com  raw_context.esp = stack_section.start().Value();
10102660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com  ASSERT_TRUE(raw_context.esp == frame0_esp.Value());
10112660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com  raw_context.ebp = frame1_ebp.Value();
10122660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com
10139753aff85a9a20dbe294529b4184d9686ec42cddSiyangXie@gmail.com  StackFrameSymbolizer frame_symbolizer(&supplier, &resolver);
10142660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com  StackwalkerX86 walker(&system_info, &raw_context, &stack_region, &modules,
10159753aff85a9a20dbe294529b4184d9686ec42cddSiyangXie@gmail.com                        &frame_symbolizer);
10162660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com  ASSERT_TRUE(walker.Walk(&call_stack));
10172660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com  frames = call_stack.frames();
10182660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com
10192660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com  ASSERT_EQ(4U, frames->size());
10202660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com
10212660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com  {  // To avoid reusing locals by mistake
10222660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    StackFrameX86 *frame0 = static_cast<StackFrameX86 *>(frames->at(0));
10232660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust);
10242660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    ASSERT_EQ(StackFrameX86::CONTEXT_VALID_ALL, frame0->context_validity);
10252660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(0x771ef8c1U, frame0->instruction);
10262660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(0x771ef8c1U, frame0->context.eip);
10272660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(frame0_esp.Value(), frame0->context.esp);
10282660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(frame1_ebp.Value(), frame0->context.ebp);
10292660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(&module3, frame0->module);
10302660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ("ZwWaitForSingleObject", frame0->function_name);
10312660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    // The STACK WIN record for module3!ZwWaitForSingleObject should have
10322660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    // produced a fully populated WindowsFrameInfo structure.
10332660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    ASSERT_TRUE(frame0->windows_frame_info != NULL);
10342660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(WindowsFrameInfo::VALID_ALL, frame0->windows_frame_info->valid);
10352660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(WindowsFrameInfo::STACK_INFO_FPO,
10362660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com              frame0->windows_frame_info->type_);
10372660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ("", frame0->windows_frame_info->program_string);
10382660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_FALSE(frame0->windows_frame_info->allocates_base_pointer);
10392660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com  }
10402660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com
10412660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com  {  // To avoid reusing locals by mistake
10422660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    StackFrameX86 *frame1 = static_cast<StackFrameX86 *>(frames->at(1));
10432660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(StackFrame::FRAME_TRUST_CFI, frame1->trust);
10442660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    ASSERT_EQ((StackFrameX86::CONTEXT_VALID_EIP
10452660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com               | StackFrameX86::CONTEXT_VALID_ESP
10462660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com               | StackFrameX86::CONTEXT_VALID_EBP),
10472660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com              frame1->context_validity);
10482660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(0x75fa0a91U, frame1->instruction + 1);
10492660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(0x75fa0a91U, frame1->context.eip);
10502660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(frame1_esp.Value(), frame1->context.esp);
10512660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(frame1_ebp.Value(), frame1->context.ebp);
10522660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(&module4, frame1->module);
10532660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ("WaitForSingleObjectEx", frame1->function_name);
10542660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    // The STACK WIN record for module4!WaitForSingleObjectEx should have
10552660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    // produced a fully populated WindowsFrameInfo structure.
10562660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    ASSERT_TRUE(frame1->windows_frame_info != NULL);
10572660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(WindowsFrameInfo::VALID_ALL, frame1->windows_frame_info->valid);
10582660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ(WindowsFrameInfo::STACK_INFO_FRAME_DATA,
10592660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com              frame1->windows_frame_info->type_);
10602660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_EQ("$T0 $ebp = $eip $T0 4 + ^ = $ebp $T0 ^ = $esp $T0 8 + = $L "
10612660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com              "$T0 .cbSavedRegs - = $P $T0 8 + .cbParams + =",
10622660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com              frame1->windows_frame_info->program_string);
10632660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    EXPECT_FALSE(frame1->windows_frame_info->allocates_base_pointer);
10642660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com  }
1065a7eb2329ded3a3315be997a7bc7ba64c5c759bd6jimblandy}
10666d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy
10673108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com// Scan the stack for a better return address and potentially skip frames
10683108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com// when the calculated return address is not in a known module.
10693108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com// Note, that the span of this scan is somewhat arbitrarily limited to 30
10703108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com// search words (pointers):
10713108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com//     const int kRASearchWords = 30;
10723108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com// This means that frames can be skipped only when their size is relatively
10733108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com// small: smaller than kRASearchWords * sizeof(InstructionType)
10743108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.comTEST_F(GetCallerFrame, ReturnAddressIsNotInKnownModule) {
10753108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com  MockCodeModule msvcrt_dll(0x77be0000, 0x58000, "msvcrt.dll", "version1");
10763108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com  SetModuleSymbols(&msvcrt_dll,  // msvcrt.dll
10773108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com                   "PUBLIC 38180 0 wcsstr\n"
10783108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com                   "STACK WIN 4 38180 61 10 0 8 0 0 0 1 $T0 $ebp = $eip $T0 "
10793108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com                   "4 + ^ = $ebp $T0 ^ = $esp $T0 8 + = $L $T0 .cbSavedRegs "
10803108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com                   "- = $P $T0 4 + .cbParams + =\n");
10813108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com
10823108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com  MockCodeModule kernel32_dll(0x7c800000, 0x103000, "kernel32.dll", "version1");
10833108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com  SetModuleSymbols(&kernel32_dll,  // kernel32.dll
10843108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com                   "PUBLIC efda 8 FindNextFileW\n"
10853108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com                   "STACK WIN 4 efda 1bb c 0 8 8 3c 0 1 $T0 $ebp = $eip $T0 "
10863108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com                   "4 + ^ = $ebp $T0 ^ = $esp $T0 8 + = $L $T0 .cbSavedRegs "
10873108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com                   "- = $P $T0 4 + .cbParams + =\n");
10883108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com
10893108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com  MockCodeModule chrome_dll(0x1c30000, 0x28C8000, "chrome.dll", "version1");
10903108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com  SetModuleSymbols(&chrome_dll,  // chrome.dll
10913108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com                   "FUNC e3cff 4af 0 file_util::FileEnumerator::Next()\n"
10923108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com                   "e3cff 1a 711 2505\n"
10933108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com                   "STACK WIN 4 e3cff 4af 20 0 4 c 94 0 1 $T1 .raSearch = "
10943108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com                   "$T0  $T1 4 - 8 @ = $ebp $T1 4 - ^ = $eip $T1 ^ = $esp "
10953108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com                   "$T1 4 + = $20 $T0 152 - ^ =  $23 $T0 156 - ^ =  $24 "
10963108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com                   "$T0 160 - ^ =\n");
10973108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com
10983108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com  // Create some modules with some stock debugging information.
10993108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com  MockCodeModules local_modules;
11003108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com  local_modules.Add(&msvcrt_dll);
11013108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com  local_modules.Add(&kernel32_dll);
11023108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com  local_modules.Add(&chrome_dll);
11033108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com
11043108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com  Label frame0_esp;
11053108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com  Label frame0_ebp;
11063108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com  Label frame1_ebp;
11073108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com  Label frame2_ebp;
11083108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com  Label frame3_ebp;
11093108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com
11103108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com  stack_section.start() = 0x0932f2d0;
11113108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com  stack_section
11123108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com    .Mark(&frame0_esp)
11133108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com    .D32(0x0764e000)
11143108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com    .D32(0x0764e068)
11153108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com    .Mark(&frame0_ebp)
11163108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com    .D32(frame1_ebp)    // Child EBP
11173108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com    .D32(0x001767a0)    // return address of frame 0
11183108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com                        // Not in known module
11193108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com    .D32(0x0764e0c6)
11203108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com    .D32(0x001bb1b8)
11213108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com    .D32(0x0764e068)
11223108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com    .D32(0x00000003)
11233108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com    .D32(0x0764e068)
11243108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com    .D32(0x00000003)
11253108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com    .D32(0x07578828)
11263108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com    .D32(0x0764e000)
11273108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com    .D32(0x00000000)
11283108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com    .D32(0x001c0010)
11293108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com    .D32(0x0764e0c6)
11303108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com    .Mark(&frame1_ebp)
11313108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com    .D32(frame2_ebp)    // Child EBP
11323108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com    .D32(0x7c80f10f)    // return address of frame 1
11333108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com                        // inside kernel32!FindNextFileW
11343108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com    .D32(0x000008f8)
11353108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com    .D32(0x00000000)
11363108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com    .D32(0x00000000)
11373108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com    .D32(0x00000000)
11383108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com    .D32(0x0932f34c)
11393108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com    .D32(0x0764e000)
11403108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com    .D32(0x00001000)
11413108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com    .D32(0x00000000)
11423108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com    .D32(0x00000001)
11433108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com    .D32(0x00000000)
11443108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com    .D32(0x00000000)
11453108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com    .D32(0x0932f6a8)
11463108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com    .D32(0x00000000)
11473108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com    .D32(0x0932f6d8)
11483108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com    .D32(0x00000000)
11493108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com    .D32(0x000000d6)
11503108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com    .D32(0x0764e000)
11513108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com    .D32(0x7ff9a000)
11523108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com    .D32(0x0932f3fc)
11533108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com    .D32(0x00000001)
11543108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com    .D32(0x00000001)
11553108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com    .D32(0x07578828)
11563108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com    .D32(0x0000002e)
11573108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com    .D32(0x0932f340)
11583108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com    .D32(0x0932eef4)
11593108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com    .D32(0x0932ffdc)
11603108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com    .D32(0x7c839ad8)
11613108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com    .D32(0x7c80f0d8)
11623108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com    .D32(0x00000000)
11633108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com    .Mark(&frame2_ebp)
11643108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com    .D32(frame3_ebp)    // Child EBP
11653108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com    .D32(0x01d13f91)    // return address of frame 2
11663108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com                        // inside chrome_dll!file_util::FileEnumerator::Next
11673108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com    .D32(0x07578828)
11683108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com    .D32(0x0932f6ac)
11693108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com    .D32(0x0932f9c4)
11703108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com    .D32(0x0932f9b4)
11713108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com    .D32(0x00000000)
11723108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com    .D32(0x00000003)
11733108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com    .D32(0x0932f978)
11743108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com    .D32(0x01094330)
11753108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com    .D32(0x00000000)
11763108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com    .D32(0x00000001)
11773108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com    .D32(0x01094330)
11783108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com    .D32(0x00000000)
11793108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com    .D32(0x00000000)
11803108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com    .D32(0x07f30000)
11813108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com    .D32(0x01c3ba17)
11823108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com    .D32(0x08bab840)
11833108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com    .D32(0x07f31580)
11843108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com    .D32(0x00000000)
11853108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com    .D32(0x00000007)
11863108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com    .D32(0x0932f940)
11873108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com    .D32(0x0000002e)
11883108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com    .D32(0x0932f40c)
11893108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com    .D32(0x01d13b53)
11903108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com    .D32(0x0932f958)
11913108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com    .D32(0x00000001)
11923108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com    .D32(0x00000007)
11933108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com    .D32(0x0932f940)
11943108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com    .D32(0x0000002e)
11953108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com    .D32(0x00000000)
11963108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com    .D32(0x0932f6ac)
11973108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com    .D32(0x01e13ef0)
11983108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com    .D32(0x00000001)
11993108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com    .D32(0x00000007)
12003108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com    .D32(0x0932f958)
12013108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com    .D32(0x08bab840)
12023108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com    .D32(0x0932f9b4)
12033108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com    .D32(0x00000000)
12043108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com    .D32(0x0932f9b4)
12053108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com    .D32(0x000000a7)
12063108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com    .D32(0x000000a7)
12073108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com    .D32(0x0932f998)
12083108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com    .D32(0x579627a2)
12093108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com    .Mark(&frame3_ebp)
12103108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com    .D32(0)             // saved %ebp (stack end)
12113108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com    .D32(0);            // saved %eip (stack end)
12123108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com
12133108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com  RegionFromSection();
12143108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com  raw_context.eip = 0x77c181cd;  // inside msvcrt!wcsstr
12153108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com  raw_context.esp = frame0_esp.Value();
12163108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com  raw_context.ebp = frame0_ebp.Value();
12173108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com  // sanity
12183108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com  ASSERT_TRUE(raw_context.esp == stack_section.start().Value());
12193108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com  ASSERT_TRUE(raw_context.ebp == stack_section.start().Value() + 8);
12203108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com
12213108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com  StackFrameSymbolizer frame_symbolizer(&supplier, &resolver);
12223108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com  StackwalkerX86 walker(&system_info, &raw_context, &stack_region,
12233108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com                        &local_modules, &frame_symbolizer);
12243108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com  ASSERT_TRUE(walker.Walk(&call_stack));
12253108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com  frames = call_stack.frames();
12263108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com
12273108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com  ASSERT_EQ(3U, frames->size());
12283108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com
12293108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com  {  // To avoid reusing locals by mistake
12303108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com    StackFrameX86 *frame0 = static_cast<StackFrameX86 *>(frames->at(0));
12313108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com    EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust);
12323108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com    ASSERT_EQ(StackFrameX86::CONTEXT_VALID_ALL, frame0->context_validity);
12333108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com    EXPECT_EQ(0x77c181cdU, frame0->instruction);
12343108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com    EXPECT_EQ(0x77c181cdU, frame0->context.eip);
12353108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com    EXPECT_EQ(frame0_esp.Value(), frame0->context.esp);
12363108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com    EXPECT_EQ(frame0_ebp.Value(), frame0->context.ebp);
12373108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com    EXPECT_EQ(&msvcrt_dll, frame0->module);
12383108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com    EXPECT_EQ("wcsstr", frame0->function_name);
12393108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com    ASSERT_TRUE(frame0->windows_frame_info != NULL);
12403108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com    EXPECT_EQ(WindowsFrameInfo::VALID_ALL, frame0->windows_frame_info->valid);
12413108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com    EXPECT_EQ(WindowsFrameInfo::STACK_INFO_FRAME_DATA,
12423108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com              frame0->windows_frame_info->type_);
12433108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com    EXPECT_EQ("$T0 $ebp = $eip $T0 "
12443108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com              "4 + ^ = $ebp $T0 ^ = $esp $T0 8 + = $L $T0 .cbSavedRegs "
12453108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com              "- = $P $T0 4 + .cbParams + =",
12463108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com              frame0->windows_frame_info->program_string);
12473108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com    // It has program string, so allocates_base_pointer is not expected
12483108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com    EXPECT_FALSE(frame0->windows_frame_info->allocates_base_pointer);
12493108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com  }
12503108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com
12513108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com  {  // To avoid reusing locals by mistake
12523108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com    StackFrameX86 *frame1 = static_cast<StackFrameX86 *>(frames->at(1));
12533108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com    EXPECT_EQ(StackFrame::FRAME_TRUST_CFI_SCAN, frame1->trust);
12543108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com    ASSERT_EQ((StackFrameX86::CONTEXT_VALID_EIP |
12553108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com               StackFrameX86::CONTEXT_VALID_ESP |
12563108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com               StackFrameX86::CONTEXT_VALID_EBP),
12573108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com              frame1->context_validity);
12583108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com    EXPECT_EQ(0x7c80f10fU, frame1->instruction + 1);
12593108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com    EXPECT_EQ(0x7c80f10fU, frame1->context.eip);
12603108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com    // frame 1 was skipped, so intead of frame1_ebp compare with frame2_ebp.
12613108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com    EXPECT_EQ(frame2_ebp.Value(), frame1->context.ebp);
12623108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com    EXPECT_EQ(&kernel32_dll, frame1->module);
12633108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com    EXPECT_EQ("FindNextFileW", frame1->function_name);
12643108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com    ASSERT_TRUE(frame1->windows_frame_info != NULL);
12653108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com    EXPECT_EQ(WindowsFrameInfo::VALID_ALL, frame1->windows_frame_info->valid);
12663108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com    EXPECT_EQ(WindowsFrameInfo::STACK_INFO_FRAME_DATA,
12673108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com              frame1->windows_frame_info->type_);
12683108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com    EXPECT_EQ("$T0 $ebp = $eip $T0 "
12693108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com              "4 + ^ = $ebp $T0 ^ = $esp $T0 8 + = $L $T0 .cbSavedRegs "
12703108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com              "- = $P $T0 4 + .cbParams + =",
12713108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com              frame1->windows_frame_info->program_string);
12723108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com    EXPECT_FALSE(frame1->windows_frame_info->allocates_base_pointer);
12733108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com  }
12743108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com
12753108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com  {  // To avoid reusing locals by mistake
12763108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com    StackFrameX86 *frame2 = static_cast<StackFrameX86 *>(frames->at(2));
12773108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com    EXPECT_EQ(StackFrame::FRAME_TRUST_CFI, frame2->trust);
12783108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com    ASSERT_EQ((StackFrameX86::CONTEXT_VALID_EIP |
12793108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com               StackFrameX86::CONTEXT_VALID_ESP |
12803108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com               StackFrameX86::CONTEXT_VALID_EBP),
12813108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com              frame2->context_validity);
12823108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com    EXPECT_EQ(0x01d13f91U, frame2->instruction + 1);
12833108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com    EXPECT_EQ(0x01d13f91U, frame2->context.eip);
12843108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com    // frame 1 was skipped, so intead of frame2_ebp compare with frame3_ebp.
12853108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com    EXPECT_EQ(frame3_ebp.Value(), frame2->context.ebp);
12863108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com    EXPECT_EQ(&chrome_dll, frame2->module);
12873108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com    EXPECT_EQ("file_util::FileEnumerator::Next()", frame2->function_name);
12883108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com    ASSERT_TRUE(frame2->windows_frame_info != NULL);
12893108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com    EXPECT_EQ(WindowsFrameInfo::VALID_ALL, frame2->windows_frame_info->valid);
12903108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com    EXPECT_EQ(WindowsFrameInfo::STACK_INFO_FRAME_DATA,
12913108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com              frame2->windows_frame_info->type_);
12923108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com    EXPECT_EQ("$T1 .raSearch = "
12933108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com              "$T0  $T1 4 - 8 @ = $ebp $T1 4 - ^ = $eip $T1 ^ = $esp "
12943108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com              "$T1 4 + = $20 $T0 152 - ^ =  $23 $T0 156 - ^ =  $24 "
12953108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com              "$T0 160 - ^ =",
12963108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com              frame2->windows_frame_info->program_string);
12973108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com    EXPECT_FALSE(frame2->windows_frame_info->allocates_base_pointer);
12983108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com  }
12993108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com}
13003108b9dd7bbac28dd01d78f9264fe494ee9c95a0ivan.penkov@gmail.com
13016d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandystruct CFIFixture: public StackwalkerX86Fixture {
13026d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  CFIFixture() {
13036d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy    // Provide a bunch of STACK CFI records; individual tests walk to the
13046d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy    // caller from every point in this series, expecting to find the same
13056d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy    // set of register values.
13066d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy    SetModuleSymbols(&module1,
13076d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy                     // The youngest frame's function.
13086d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy                     "FUNC 4000 1000 10 enchiridion\n"
13096d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy                     // Initially, just a return address.
13106d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy                     "STACK CFI INIT 4000 100 .cfa: $esp 4 + .ra: .cfa 4 - ^\n"
13116d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy                     // Push %ebx.
13126d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy                     "STACK CFI 4001 .cfa: $esp 8 + $ebx: .cfa 8 - ^\n"
13136d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy                     // Move %esi into %ebx.  Weird, but permitted.
13146d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy                     "STACK CFI 4002 $esi: $ebx\n"
13156d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy                     // Allocate frame space, and save %edi.
13166d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy                     "STACK CFI 4003 .cfa: $esp 20 + $edi: .cfa 16 - ^\n"
13176d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy                     // Put the return address in %edi.
13186d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy                     "STACK CFI 4005 .ra: $edi\n"
13196d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy                     // Save %ebp, and use it as a frame pointer.
13206d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy                     "STACK CFI 4006 .cfa: $ebp 8 + $ebp: .cfa 12 - ^\n"
13216d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy
13226d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy                     // The calling function.
13236d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy                     "FUNC 5000 1000 10 epictetus\n"
13246d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy                     // Mark it as end of stack.
13256d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy                     "STACK CFI INIT 5000 1000 .cfa: $esp .ra 0\n");
13266d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy
13276d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy    // Provide some distinctive values for the caller's registers.
13286d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy    expected.esp = 0x80000000;
13296d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy    expected.eip = 0x40005510;
13306d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy    expected.ebp = 0xc0d4aab9;
13316d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy    expected.ebx = 0x60f20ce6;
13326d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy    expected.esi = 0x53d1379d;
13336d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy    expected.edi = 0xafbae234;
13346d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy
13356d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy    // By default, registers are unchanged.
13366d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy    raw_context = expected;
13376d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  }
13386d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy
13396d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  // Walk the stack, using stack_section as the contents of the stack
13406d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  // and raw_context as the current register values. (Set
13416d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  // raw_context.esp to the stack's starting address.) Expect two
13426d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  // stack frames; in the older frame, expect the callee-saves
13436d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  // registers to have values matching those in 'expected'.
13446d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  void CheckWalk() {
13456d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy    RegionFromSection();
13466d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy    raw_context.esp = stack_section.start().Value();
13476d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy
13489753aff85a9a20dbe294529b4184d9686ec42cddSiyangXie@gmail.com    StackFrameSymbolizer frame_symbolizer(&supplier, &resolver);
13496d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy    StackwalkerX86 walker(&system_info, &raw_context, &stack_region, &modules,
13509753aff85a9a20dbe294529b4184d9686ec42cddSiyangXie@gmail.com                          &frame_symbolizer);
13516d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy    ASSERT_TRUE(walker.Walk(&call_stack));
13526d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy    frames = call_stack.frames();
13536d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy    ASSERT_EQ(2U, frames->size());
13546d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy
13552660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    {  // To avoid reusing locals by mistake
13562660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com      StackFrameX86 *frame0 = static_cast<StackFrameX86 *>(frames->at(0));
13572660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com      EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust);
13582660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com      ASSERT_EQ(StackFrameX86::CONTEXT_VALID_ALL, frame0->context_validity);
13592660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com      EXPECT_EQ("enchiridion", frame0->function_name);
13602660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com      EXPECT_EQ(0x40004000U, frame0->function_base);
13612660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com      ASSERT_TRUE(frame0->windows_frame_info != NULL);
13622660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com      ASSERT_EQ(WindowsFrameInfo::VALID_PARAMETER_SIZE,
13632660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com                frame0->windows_frame_info->valid);
13642660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com      ASSERT_TRUE(frame0->cfi_frame_info != NULL);
13652660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    }
13662660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com
13672660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    {  // To avoid reusing locals by mistake
13682660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com      StackFrameX86 *frame1 = static_cast<StackFrameX86 *>(frames->at(1));
13692660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com      EXPECT_EQ(StackFrame::FRAME_TRUST_CFI, frame1->trust);
13702660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com      ASSERT_EQ((StackFrameX86::CONTEXT_VALID_EIP |
13712660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com                 StackFrameX86::CONTEXT_VALID_ESP |
13722660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com                 StackFrameX86::CONTEXT_VALID_EBP |
13732660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com                 StackFrameX86::CONTEXT_VALID_EBX |
13742660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com                 StackFrameX86::CONTEXT_VALID_ESI |
13752660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com                 StackFrameX86::CONTEXT_VALID_EDI),
13762660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com                 frame1->context_validity);
13772660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com      EXPECT_EQ(expected.eip, frame1->context.eip);
13782660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com      EXPECT_EQ(expected.esp, frame1->context.esp);
13792660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com      EXPECT_EQ(expected.ebp, frame1->context.ebp);
13802660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com      EXPECT_EQ(expected.ebx, frame1->context.ebx);
13812660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com      EXPECT_EQ(expected.esi, frame1->context.esi);
13822660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com      EXPECT_EQ(expected.edi, frame1->context.edi);
13832660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com      EXPECT_EQ("epictetus", frame1->function_name);
13842660caa1ad5b57ffa763a68c3b96abc10e7f16feivan.penkov@gmail.com    }
13856d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  }
13866d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy
13876d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  // The values the stack walker should find for the caller's registers.
13886d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  MDRawContextX86 expected;
13896d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy};
13906d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy
13916d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandyclass CFI: public CFIFixture, public Test { };
13926d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy
13936d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandyTEST_F(CFI, At4000) {
13946d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  Label frame1_esp = expected.esp;
13956d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  stack_section
13966d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy    .D32(0x40005510)            // return address
13976d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy    .Mark(&frame1_esp);         // This effectively sets stack_section.start().
13986d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  raw_context.eip = 0x40004000;
13996d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  CheckWalk();
14006d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy}
14016d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy
14026d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandyTEST_F(CFI, At4001) {
14036d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  Label frame1_esp = expected.esp;
14046d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  stack_section
14056d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy    .D32(0x60f20ce6)            // saved %ebx
14066d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy    .D32(0x40005510)            // return address
14076d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy    .Mark(&frame1_esp);         // This effectively sets stack_section.start().
14086d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  raw_context.eip = 0x40004001;
14096d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  raw_context.ebx = 0x91aa9a8b; // callee's %ebx value
14106d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  CheckWalk();
14116d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy}
14126d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy
14136d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandyTEST_F(CFI, At4002) {
14146d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  Label frame1_esp = expected.esp;
14156d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  stack_section
14166d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy    .D32(0x60f20ce6)            // saved %ebx
14176d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy    .D32(0x40005510)            // return address
14186d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy    .Mark(&frame1_esp);         // This effectively sets stack_section.start().
14196d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  raw_context.eip = 0x40004002;
14206d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  raw_context.ebx = 0x53d1379d; // saved %esi
14216d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  raw_context.esi = 0xa5c790ed; // callee's %esi value
14226d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  CheckWalk();
14236d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy}
14246d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy
14256d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandyTEST_F(CFI, At4003) {
14266d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  Label frame1_esp = expected.esp;
14276d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  stack_section
14286d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy    .D32(0x56ec3db7)            // garbage
14296d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy    .D32(0xafbae234)            // saved %edi
14306d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy    .D32(0x53d67131)            // garbage
14316d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy    .D32(0x60f20ce6)            // saved %ebx
14326d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy    .D32(0x40005510)            // return address
14336d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy    .Mark(&frame1_esp);         // This effectively sets stack_section.start().
14346d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  raw_context.eip = 0x40004003;
14356d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  raw_context.ebx = 0x53d1379d; // saved %esi
14366d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  raw_context.esi = 0xa97f229d; // callee's %esi
14376d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  raw_context.edi = 0xb05cc997; // callee's %edi
14386d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  CheckWalk();
14396d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy}
14406d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy
14416d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy// The results here should be the same as those at module offset
14426d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy// 0x4003.
14436d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandyTEST_F(CFI, At4004) {
14446d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  Label frame1_esp = expected.esp;
14456d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  stack_section
14466d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy    .D32(0xe29782c2)            // garbage
14476d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy    .D32(0xafbae234)            // saved %edi
14486d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy    .D32(0x5ba29ce9)            // garbage
14496d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy    .D32(0x60f20ce6)            // saved %ebx
14506d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy    .D32(0x40005510)            // return address
14516d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy    .Mark(&frame1_esp);         // This effectively sets stack_section.start().
14526d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  raw_context.eip = 0x40004004;
14536d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  raw_context.ebx = 0x53d1379d; // saved %esi
14546d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  raw_context.esi = 0x0fb7dc4e; // callee's %esi
14556d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  raw_context.edi = 0x993b4280; // callee's %edi
14566d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  CheckWalk();
14576d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy}
14586d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy
14596d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandyTEST_F(CFI, At4005) {
14606d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  Label frame1_esp = expected.esp;
14616d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  stack_section
14626d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy    .D32(0xe29782c2)            // garbage
14636d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy    .D32(0xafbae234)            // saved %edi
14646d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy    .D32(0x5ba29ce9)            // garbage
14656d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy    .D32(0x60f20ce6)            // saved %ebx
14666d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy    .D32(0x8036cc02)            // garbage
14676d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy    .Mark(&frame1_esp);         // This effectively sets stack_section.start().
14686d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  raw_context.eip = 0x40004005;
14696d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  raw_context.ebx = 0x53d1379d; // saved %esi
14706d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  raw_context.esi = 0x0fb7dc4e; // callee's %esi
14716d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  raw_context.edi = 0x40005510; // return address
14726d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  CheckWalk();
14736d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy}
14746d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy
14756d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandyTEST_F(CFI, At4006) {
14766d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  Label frame0_ebp;
14776d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  Label frame1_esp = expected.esp;
14786d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  stack_section
14796d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy    .D32(0xdcdd25cd)            // garbage
14806d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy    .D32(0xafbae234)            // saved %edi
14816d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy    .D32(0xc0d4aab9)            // saved %ebp
14826d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy    .Mark(&frame0_ebp)          // frame pointer points here
14836d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy    .D32(0x60f20ce6)            // saved %ebx
14846d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy    .D32(0x8036cc02)            // garbage
14856d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy    .Mark(&frame1_esp);         // This effectively sets stack_section.start().
14866d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  raw_context.eip = 0x40004006;
14876d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  raw_context.ebp = frame0_ebp.Value();
14886d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  raw_context.ebx = 0x53d1379d; // saved %esi
14896d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  raw_context.esi = 0x743833c9; // callee's %esi
14906d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  raw_context.edi = 0x40005510; // return address
14916d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  CheckWalk();
14926d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy}
14936d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy
1494