Coverage for /Syzygy/agent/common/stack_walker_x86_unittest.cc

CoverageLines executed / instrumented / missingexe / inst / missLanguageGroup
100.0%1621620.C++test

Line-by-line coverage:

   1    :  // Copyright 2015 Google Inc. All Rights Reserved.
   2    :  //
   3    :  // Licensed under the Apache License, Version 2.0 (the "License");
   4    :  // you may not use this file except in compliance with the License.
   5    :  // You may obtain a copy of the License at
   6    :  //
   7    :  //     http://www.apache.org/licenses/LICENSE-2.0
   8    :  //
   9    :  // Unless required by applicable law or agreed to in writing, software
  10    :  // distributed under the License is distributed on an "AS IS" BASIS,
  11    :  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12    :  // See the License for the specific language governing permissions and
  13    :  // limitations under the License.
  14    :  
  15    :  #include "syzygy/agent/common/stack_walker_x86.h"
  16    :  
  17    :  #include <windows.h>
  18    :  
  19    :  #include "base/basictypes.h"
  20    :  #include "gtest/gtest.h"
  21    :  #include "syzygy/testing/metrics.h"
  22    :  
  23    :  namespace agent {
  24    :  namespace common {
  25    :  
  26    :  namespace {
  27    :  
  28    :  class StackWalkerX86Test : public testing::Test {
  29    :   public:
  30  E :    StackWalkerX86Test()
  31    :        : dummy_ebp_(nullptr), dummy_esp_(nullptr), dummy_ret_(0u) {
  32  E :      ::memset(frames_, 0, sizeof(frames_));
  33  E :      ::memset(frames2_, 0, sizeof(frames2_));
  34  E :      ::memset(dummy_stack_, 0, sizeof(dummy_stack_));
  35  E :    }
  36    :  
  37    :    static const uintptr_t kBaseRet = 0x1000000u;
  38    :  
  39  E :    void Push(uintptr_t value) {
  40  E :      --dummy_esp_;
  41  E :      ASSERT_LE(dummy_stack_, dummy_esp_);
  42  E :      *dummy_esp_ = value;
  43  E :    }
  44    :  
  45  E :    void PushEbp() {
  46  E :      Push(reinterpret_cast<uintptr_t>(dummy_ebp_));
  47  E :      dummy_ebp_ = dummy_esp_;
  48  E :    }
  49    :  
  50  E :    void PopEbp() {
  51  E :      dummy_ebp_ = reinterpret_cast<uintptr_t*>(*dummy_esp_);
  52  E :      ++dummy_esp_;
  53  E :      ASSERT_LE(dummy_esp_, dummy_stack_ + arraysize(dummy_stack_));
  54  E :    }
  55    :  
  56  E :    void PushRet() {
  57  E :      Push(dummy_ret_);
  58  E :      ++dummy_ret_;
  59  E :    }
  60    :  
  61  E :    void ResetStack() {
  62  E :      ::memset(dummy_stack_, 0, sizeof(dummy_stack_));
  63  E :      dummy_ebp_ = dummy_stack_ + arraysize(dummy_stack_);
  64  E :      dummy_esp_ = dummy_stack_ + arraysize(dummy_stack_);
  65  E :      dummy_ret_ = kBaseRet;
  66    :  
  67    :      // Push a return address, so that the very topmost thing on the
  68    :      // stack is a return.
  69  E :      PushRet();
  70  E :    }
  71    :  
  72  E :    void SetUp() override {
  73  E :      ResetStack();
  74  E :    }
  75    :  
  76  E :    void BuildValidFrame(size_t locals) {
  77  E :      PushEbp();
  78  E :      for (size_t i = 0; i < locals; ++i)
  79  E :        Push(::rand());
  80  E :      PushRet();
  81  E :    }
  82    :  
  83  E :    void BuildInvalidFrameTooSmall() {
  84    :      // Only push an EBP. This will be too close to the EBP of the next valid
  85    :      // stack frame.
  86  E :      PushEbp();
  87  E :    }
  88    :  
  89  E :    void BuildInvalidFrameNonIncreasingBasePointer() {
  90  E :      Push(*dummy_ebp_ - 4 * sizeof(uintptr_t));
  91  E :      dummy_ebp_ = dummy_esp_;
  92  E :      PushRet();
  93  E :    }
  94    :  
  95  E :    void BuildInvalidFrameUnalignedBasePointer() {
  96  E :      Push(*dummy_ebp_ - 1);
  97  E :      dummy_ebp_ = dummy_esp_;
  98  E :      PushRet();
  99  E :    }
 100    :  
 101  E :    void BuildInvalidFrameInvalidReturnAddress() {
 102  E :      PushEbp();
 103  E :      Push(0);  // Output a null return address.
 104  E :      ++dummy_ret_;
 105  E :    }
 106    :  
 107  E :    void BuildInvalidFrameInvalidBasePointer() {
 108  E :      Push(reinterpret_cast<uintptr_t>(dummy_stack_ + arraysize(dummy_stack_)));
 109  E :      dummy_ebp_ = dummy_esp_;
 110  E :      PushRet();
 111  E :    }
 112    :  
 113  E :    void BuildInvalidFrameOverflowingBasePointer() {
 114    :      // This base pointer will overflow to 0 when incremented.
 115  E :      Push(0xFFFFFFFC);
 116  E :      dummy_ebp_ = dummy_esp_;
 117  E :      PushRet();
 118  E :    }
 119    :  
 120    :    void ExpectSuccessfulWalk(size_t num_frames,
 121  E :                              size_t frames_to_skip) {
 122    :      // Push a dummy EBP on the stack, which simulates the stack frame of the
 123    :      // function actually calling WalkStack.
 124  E :      PushEbp();
 125    :      StackId stack_id;
 126  E :      EXPECT_EQ(num_frames,
 127    :                WalkStackImpl(dummy_ebp_, dummy_esp_,
 128    :                              dummy_stack_ + arraysize(dummy_stack_),
 129    :                              frames_to_skip, kMaxFrames, frames_, &stack_id));
 130  E :      for (size_t i = 0; i < num_frames; ++i) {
 131  E :        EXPECT_EQ(reinterpret_cast<void*>(dummy_ret_ - i - 1 - frames_to_skip),
 132    :                  frames_[i]);
 133  E :      }
 134    :  
 135  E :      PopEbp();
 136  E :    }
 137    :  
 138    :    static const size_t kMaxFrames = 100;
 139    :    void* frames_[kMaxFrames];
 140    :    void* frames2_[kMaxFrames];
 141    :  
 142    :    uintptr_t dummy_stack_[1024];
 143    :    uintptr_t* dummy_ebp_;
 144    :    uintptr_t* dummy_esp_;
 145    :    uintptr_t dummy_ret_;
 146    :  };
 147    :  
 148    :  }  // namespace
 149    :  
 150  E :  TEST_F(StackWalkerX86Test, ValidWalk) {
 151  E :    BuildValidFrame(0);
 152  E :    ExpectSuccessfulWalk(2, 0);
 153  E :    BuildValidFrame(2);
 154  E :    ExpectSuccessfulWalk(3, 0);
 155  E :    BuildValidFrame(1);
 156  E :    ExpectSuccessfulWalk(4, 0);
 157  E :    ExpectSuccessfulWalk(3, 1);
 158  E :    ExpectSuccessfulWalk(2, 2);
 159  E :  }
 160    :  
 161  E :  TEST_F(StackWalkerX86Test, WalkStopsWhenFrameTooSmall) {
 162  E :    BuildValidFrame(0);
 163  E :    ExpectSuccessfulWalk(2, 0);
 164    :  
 165  E :    BuildInvalidFrameTooSmall();
 166  E :    BuildValidFrame(1);
 167  E :    ExpectSuccessfulWalk(1, 0);
 168    :  
 169  E :    BuildValidFrame(2);
 170  E :    ExpectSuccessfulWalk(2, 0);
 171    :  
 172  E :    BuildValidFrame(1);
 173  E :    ExpectSuccessfulWalk(3, 0);
 174  E :    ExpectSuccessfulWalk(2, 1);
 175  E :  }
 176    :  
 177  E :  TEST_F(StackWalkerX86Test, WalkStopsAtNonIncreasingBasePointer) {
 178  E :    BuildValidFrame(0);
 179  E :    ExpectSuccessfulWalk(2, 0);
 180    :  
 181  E :    BuildInvalidFrameNonIncreasingBasePointer();
 182  E :    ExpectSuccessfulWalk(2, 0);
 183    :  
 184  E :    BuildValidFrame(2);
 185  E :    ExpectSuccessfulWalk(3, 0);
 186    :  
 187  E :    BuildValidFrame(1);
 188  E :    ExpectSuccessfulWalk(4, 0);
 189  E :    ExpectSuccessfulWalk(3, 1);
 190  E :  }
 191    :  
 192  E :  TEST_F(StackWalkerX86Test, WalkStopsAtUnalignedBasePointer) {
 193  E :    BuildValidFrame(0);
 194  E :    ExpectSuccessfulWalk(2, 0);
 195    :  
 196  E :    BuildInvalidFrameUnalignedBasePointer();
 197  E :    ExpectSuccessfulWalk(2, 0);
 198    :  
 199  E :    BuildValidFrame(2);
 200  E :    ExpectSuccessfulWalk(3, 0);
 201    :  
 202  E :    BuildValidFrame(1);
 203  E :    ExpectSuccessfulWalk(4, 0);
 204  E :    ExpectSuccessfulWalk(3, 1);
 205  E :  }
 206    :  
 207  E :  TEST_F(StackWalkerX86Test, WalkStopsAtInvalidReturnAddress) {
 208  E :    BuildValidFrame(0);
 209  E :    ExpectSuccessfulWalk(2, 0);
 210    :  
 211  E :    BuildInvalidFrameInvalidReturnAddress();
 212  E :    ExpectSuccessfulWalk(0, 0);
 213    :  
 214  E :    BuildValidFrame(2);
 215  E :    ExpectSuccessfulWalk(1, 0);
 216    :  
 217  E :    BuildValidFrame(1);
 218  E :    ExpectSuccessfulWalk(2, 0);
 219  E :  }
 220    :  
 221  E :  TEST_F(StackWalkerX86Test, WalkStopsAtInvalidBasePointer) {
 222  E :    BuildValidFrame(0);
 223  E :    ExpectSuccessfulWalk(2, 0);
 224    :  
 225  E :    BuildInvalidFrameInvalidBasePointer();
 226  E :    ExpectSuccessfulWalk(2, 0);
 227    :  
 228  E :    BuildValidFrame(2);
 229  E :    ExpectSuccessfulWalk(3, 0);
 230    :  
 231  E :    BuildValidFrame(1);
 232  E :    ExpectSuccessfulWalk(4, 0);
 233  E :    ExpectSuccessfulWalk(3, 1);
 234  E :  }
 235    :  
 236  E :  TEST_F(StackWalkerX86Test, WalkStopAtOverflowingBasePointer) {
 237  E :    BuildValidFrame(0);
 238  E :    ExpectSuccessfulWalk(2, 0);
 239    :  
 240  E :    BuildInvalidFrameOverflowingBasePointer();
 241  E :    ExpectSuccessfulWalk(2, 0);
 242    :  
 243  E :    BuildValidFrame(2);
 244  E :    ExpectSuccessfulWalk(3, 0);
 245    :  
 246  E :    BuildValidFrame(1);
 247  E :    ExpectSuccessfulWalk(4, 0);
 248  E :    ExpectSuccessfulWalk(3, 1);
 249  E :  }
 250    :  
 251  E :  TEST_F(StackWalkerX86Test, CompareToCaptureStackBackTrace) {
 252    :    // Use the OS stack walker to get the number of frames. Skip the top frame
 253    :    // (in this function) as WalkStack and CaptureStackBackTrace won't have the
 254    :    // same return address.
 255    :    size_t num_frames =
 256  E :        ::CaptureStackBackTrace(1, kMaxFrames, frames_, nullptr);
 257    :  
 258  E :    while (num_frames > 0) {
 259    :      StackId stack_id;
 260  E :      size_t num_frames2 = WalkStack(1, num_frames, frames_, &stack_id);
 261    :      size_t exp_frames2 =
 262  E :          ::CaptureStackBackTrace(1, num_frames, frames2_, nullptr);
 263  E :      EXPECT_EQ(num_frames, num_frames2);
 264  E :      EXPECT_EQ(exp_frames2, num_frames2);
 265  E :      EXPECT_EQ(0, ::memcmp(frames_, frames2_, num_frames * sizeof(*frames_)));
 266    :  
 267  E :      --num_frames;
 268  E :    }
 269  E :  }
 270    :  
 271    :  }  // namespace common
 272    :  }  // namespace agent

Coverage information generated Thu Jan 14 17:40:38 2016.