summaryrefslogtreecommitdiffstats
path: root/chrome_frame/test/function_stub_unittest.cc
blob: 6ef6f3692cf7890e8f6538a53d8a1f195d349b16 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome_frame/function_stub.h"

#include "chrome_frame/test/chrome_frame_unittests.h"

#define NO_INLINE __declspec(noinline)

namespace {

typedef int (__stdcall* FooPrototype)();

NO_INLINE int __stdcall Foo() {
  return 1;
}

NO_INLINE int __stdcall PatchedFoo(FooPrototype original) {
  return original() + 1;
}

}  // end namespace

TEST(PatchTests, FunctionStub) {
  EXPECT_EQ(Foo(), 1);
  // Create a function stub that calls PatchedFoo and supplies it with
  // a pointer to Foo.
  FunctionStub* stub = FunctionStub::Create(reinterpret_cast<uintptr_t>(&Foo),
                                            &PatchedFoo);
  EXPECT_TRUE(stub != NULL);
  // Call the stub as it were Foo().  The call should get forwarded to Foo().
  FooPrototype patch = reinterpret_cast<FooPrototype>(stub->code());
  EXPECT_EQ(patch(), 2);
  // Now neutralize the stub so that it calls Foo() directly without touching
  // PatchedFoo().
  // stub->BypassStub(&Foo);
  stub->BypassStub(reinterpret_cast<void*>(stub->argument()));
  EXPECT_EQ(patch(), 1);
  // We're done with the stub.
  FunctionStub::Destroy(stub);
}

// Basic tests to check the validity of a stub.
TEST(PatchTests, FunctionStubCompare) {
  EXPECT_EQ(Foo(), 1);

  // Detect the absence of a stub
  FunctionStub* stub = reinterpret_cast<FunctionStub*>(&Foo);
  EXPECT_FALSE(stub->is_valid());

  stub = FunctionStub::Create(reinterpret_cast<uintptr_t>(&Foo), &PatchedFoo);
  EXPECT_TRUE(stub != NULL);
  EXPECT_TRUE(stub->is_valid());

  FooPrototype patch = reinterpret_cast<FooPrototype>(stub->code());
  EXPECT_EQ(patch(), 2);

  // See if we can get the correct absolute pointer to the hook function
  // back from the stub.
  EXPECT_EQ(stub->absolute_target(), reinterpret_cast<uintptr_t>(&PatchedFoo));

  // Also verify that the argument being passed to the hook function is indeed
  // the pointer to the original function (again, absolute not relative).
  EXPECT_EQ(stub->argument(), reinterpret_cast<uintptr_t>(&Foo));
}