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

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

Coverage information generated Fri Jul 29 11:00:21 2016.