1 : // Copyright 2016 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/bard/events/play_util.h"
16 :
17 : #include <windows.h>
18 :
19 : #include "base/macros.h"
20 : #include "gtest/gtest.h"
21 :
22 : namespace bard {
23 :
24 : namespace {
25 :
26 : struct StackTrace {
27 : // One frame for each nibble of the stack ID.
28 : void* frames[8];
29 : };
30 :
31 : template <uint32_t kInvokeValue>
32 : using InvokeHelper =
33 : detail::InvokeFunctionWithStackIdHelper<kInvokeValue,
34 : bool(bool, StackTrace*),
35 : bool,
36 : bool,
37 : StackTrace*>;
38 :
39 E : bool ParrotImpl(bool input, StackTrace* stack_trace) {
40 : // Capture the current stack trace, but ignore the current frame. This should
41 : // only grab the InvokeFunctionWithStackIdHelper frames.
42 E : CaptureStackBackTrace(1, arraysize(stack_trace->frames), stack_trace->frames,
43 : nullptr);
44 E : return input;
45 E : }
46 :
47 : // Does nothing.
48 E : bool Dummy(bool input, StackTrace* stack_trace) {
49 E : return false;
50 E : }
51 :
52 : // Wraps a call to ParrotImpl via InvokeFunctionWithStackId.
53 E : bool Parrot(uint32_t stack_id, bool input, StackTrace* stack_trace) {
54 E : return InvokeFunctionWithStackId(stack_id, ParrotImpl, input, stack_trace);
55 E : }
56 :
57 : // Gets the extents of the associated InvokeHelper function.
58 : template <uint32_t kInvokeValue>
59 : struct GetInvokeFunctionExtents {
60 : static void Do(void const** invoke_helper_begins,
61 E : void const** invoke_helper_ends) {
62 E : InvokeHelper<kInvokeValue>::Do(detail::kGetFunctionExtentsDepth, 0, Dummy,
63 : false, nullptr);
64 E : invoke_helper_begins[kInvokeValue] = detail::kInvokeFunctionBegin;
65 E : invoke_helper_ends[kInvokeValue] = detail::kInvokeFunctionEnd;
66 E : }
67 : };
68 :
69 : } // namespace
70 :
71 E : TEST(InvokeFunctionWithStackIdTest, ExpectedStackId) {
72 : // Get the extents of the various invoke helper functions.
73 E : void const* invoke_helper_begins[16] = {};
74 E : void const* invoke_helper_ends[16] = {};
75 E : GetInvokeFunctionExtents<0x0>::Do(invoke_helper_begins, invoke_helper_ends);
76 E : GetInvokeFunctionExtents<0x1>::Do(invoke_helper_begins, invoke_helper_ends);
77 E : GetInvokeFunctionExtents<0x2>::Do(invoke_helper_begins, invoke_helper_ends);
78 E : GetInvokeFunctionExtents<0x3>::Do(invoke_helper_begins, invoke_helper_ends);
79 E : GetInvokeFunctionExtents<0x4>::Do(invoke_helper_begins, invoke_helper_ends);
80 E : GetInvokeFunctionExtents<0x5>::Do(invoke_helper_begins, invoke_helper_ends);
81 E : GetInvokeFunctionExtents<0x6>::Do(invoke_helper_begins, invoke_helper_ends);
82 E : GetInvokeFunctionExtents<0x7>::Do(invoke_helper_begins, invoke_helper_ends);
83 E : GetInvokeFunctionExtents<0x8>::Do(invoke_helper_begins, invoke_helper_ends);
84 E : GetInvokeFunctionExtents<0x9>::Do(invoke_helper_begins, invoke_helper_ends);
85 E : GetInvokeFunctionExtents<0xA>::Do(invoke_helper_begins, invoke_helper_ends);
86 E : GetInvokeFunctionExtents<0xB>::Do(invoke_helper_begins, invoke_helper_ends);
87 E : GetInvokeFunctionExtents<0xC>::Do(invoke_helper_begins, invoke_helper_ends);
88 E : GetInvokeFunctionExtents<0xD>::Do(invoke_helper_begins, invoke_helper_ends);
89 E : GetInvokeFunctionExtents<0xE>::Do(invoke_helper_begins, invoke_helper_ends);
90 E : GetInvokeFunctionExtents<0xF>::Do(invoke_helper_begins, invoke_helper_ends);
91 :
92 : // Generate a handful of random stack IDs and ensure they are dispatched via
93 : // the expected functions.
94 E : StackTrace stack_trace = {};
95 E : for (size_t i = 0; i < 100; ++i) {
96 E : uint32_t stack_id = ::rand();
97 E : bool value = ::rand() % 2;
98 E : EXPECT_EQ(value, Parrot(stack_id, value, &stack_trace));
99 :
100 E : for (size_t j = 0; j < 8; ++j) {
101 E : uint32_t nibble = (stack_id >> (28 - 4 * j)) & 0xF;
102 E : EXPECT_LT(invoke_helper_begins[nibble], stack_trace.frames[j]);
103 E : EXPECT_GE(invoke_helper_ends[nibble], stack_trace.frames[j]);
104 E : }
105 E : }
106 E : }
107 :
108 : } // namespace bard
|