1 /*
2 * Copyright (C) 2018 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "gtest/gtest.h"
18
19 #include "berberis/base/bit_util.h"
20 #include "berberis/guest_abi/guest_params.h"
21 #include "berberis/guest_state/guest_state.h"
22
23 namespace berberis {
24
25 namespace {
26
SetVfpFloat(ThreadState * state,int index,float v)27 void SetVfpFloat(ThreadState* state, int index, float v) {
28 reinterpret_cast<float*>(state->cpu.d)[index] = v;
29 }
30
SetVfpDouble(ThreadState * state,int index,double v)31 void SetVfpDouble(ThreadState* state, int index, double v) {
32 reinterpret_cast<double*>(state->cpu.d)[index] = v;
33 }
34
TEST(Params,IntRes)35 TEST(Params, IntRes) {
36 ThreadState state{};
37
38 auto&& [ret] = GuestReturnReference<int()>(&state);
39 auto&& [retf] = GuestReturnReference<int (*)()>(&state);
40 auto&& [retv] = GuestReturnReference<int(...)>(&state);
41 auto&& [retfv] = GuestReturnReference<int (*)(...)>(&state);
42
43 ret = 123;
44 EXPECT_EQ(123u, state.cpu.r[0]);
45
46 retf = 234;
47 EXPECT_EQ(234u, state.cpu.r[0]);
48
49 retv = 345;
50 EXPECT_EQ(345u, state.cpu.r[0]);
51
52 retfv = 456;
53 EXPECT_EQ(456u, state.cpu.r[0]);
54 }
55
TEST(Params,SignedCharRes)56 TEST(Params, SignedCharRes) {
57 ThreadState state{};
58
59 state.cpu.r[0] = 0;
60
61 auto&& [ret] = GuestReturnReference<signed char()>(&state);
62 auto&& [retf] = GuestReturnReference<signed char (*)()>(&state);
63 auto&& [retv] = GuestReturnReference<signed char(...)>(&state);
64 auto&& [retfv] = GuestReturnReference<signed char (*)(...)>(&state);
65
66 ret = -1;
67 EXPECT_EQ(0xFFFFFFFFu, state.cpu.r[0]);
68
69 retf = -2;
70 EXPECT_EQ(0xFFFFFFFEu, state.cpu.r[0]);
71
72 retv = -3;
73 EXPECT_EQ(0xFFFFFFFDu, state.cpu.r[0]);
74
75 retfv = -4;
76 EXPECT_EQ(0xFFFFFFFCu, state.cpu.r[0]);
77 }
78
TEST(Params,PtrFloatFloatArgs)79 TEST(Params, PtrFloatFloatArgs) {
80 ThreadState state{};
81
82 static int x;
83
84 state.cpu.r[0] = bit_cast<uint32_t>(&x);
85 state.cpu.r[1] = bit_cast<uint32_t>(1.0f);
86 state.cpu.r[2] = bit_cast<uint32_t>(-.75f);
87
88 auto [arg1, arg2, arg3] = GuestParamsValues<void(int*, float, float)>(&state);
89 auto [arg1f, arg2f, arg3f] = GuestParamsValues<void (*)(int*, float, float)>(&state);
90 auto [arg1v, arg2v, arg3v] = GuestParamsValues<void(int*, float, float, ...)>(&state);
91 auto [arg1fv, arg2fv, arg3fv] = GuestParamsValues<void (*)(int*, float, float, ...)>(&state);
92
93 EXPECT_EQ(&x, arg1);
94 EXPECT_FLOAT_EQ(1.0f, arg2);
95 EXPECT_FLOAT_EQ(-.75f, arg3);
96
97 EXPECT_EQ(&x, arg1f);
98 EXPECT_FLOAT_EQ(1.0f, arg2f);
99 EXPECT_FLOAT_EQ(-.75f, arg3f);
100
101 EXPECT_EQ(&x, arg1v);
102 EXPECT_FLOAT_EQ(1.0f, arg2v);
103 EXPECT_FLOAT_EQ(-.75f, arg3v);
104
105 EXPECT_EQ(&x, arg1fv);
106 EXPECT_FLOAT_EQ(1.0f, arg2fv);
107 EXPECT_FLOAT_EQ(-.75f, arg3fv);
108 }
109
TEST(Params,PtrFloatFloatArgsVfp)110 TEST(Params, PtrFloatFloatArgsVfp) {
111 ThreadState state{};
112
113 static int x;
114
115 state.cpu.r[0] = bit_cast<uint32_t>(&x);
116 state.cpu.r[1] = bit_cast<uint32_t>(42.0f);
117 state.cpu.r[2] = 0xa3d70a3d; // -0.57 - bottom half
118 state.cpu.r[3] = 0xbfe23d70; // -0.57 - top half
119 SetVfpFloat(&state, 0, 1.0f); // s0
120 SetVfpDouble(&state, 1, -.75f); // d1
121
122 auto [arg1, arg2, arg3] =
123 GuestParamsValues<void(int*, float, double), GuestAbi::kAapcsVfp>(&state);
124 auto [arg1f, arg2f, arg3f] =
125 GuestParamsValues<void (*)(int*, float, double), GuestAbi::kAapcsVfp>(&state);
126 auto [arg1v, arg2v, arg3v] =
127 GuestParamsValues<void(int*, float, double, ...), GuestAbi::kAapcsVfp>(&state);
128 auto [arg1fv, arg2fv, arg3fv] =
129 GuestParamsValues<void (*)(int*, float, double, ...), GuestAbi::kAapcsVfp>(&state);
130
131 EXPECT_EQ(&x, arg1);
132 EXPECT_FLOAT_EQ(1.0f, arg2);
133 EXPECT_DOUBLE_EQ(-.75, arg3);
134
135 EXPECT_EQ(&x, arg1f);
136 EXPECT_FLOAT_EQ(1.0f, arg2f);
137 EXPECT_DOUBLE_EQ(-.75, arg3f);
138
139 // “Note: There are no VFP CPRCs in a variadic procedure” ⇦ from AAPCS
140 EXPECT_EQ(&x, arg1v);
141 EXPECT_FLOAT_EQ(42.0f, arg2v);
142 EXPECT_DOUBLE_EQ(-.57, arg3v);
143
144 EXPECT_EQ(&x, arg1fv);
145 EXPECT_FLOAT_EQ(42.0f, arg2fv);
146 EXPECT_DOUBLE_EQ(-.57, arg3fv);
147 }
148
TEST(Params,PtrIntPtrLongLongArgs)149 TEST(Params, PtrIntPtrLongLongArgs) {
150 ThreadState state{};
151
152 alignas(8) uint64_t stack[4];
153 state.cpu.r[13] = bit_cast<uint32_t>(&stack[0]);
154
155 static int x;
156 constexpr uint64_t kTestValue64 = 0xffff0000ffff0000ULL;
157
158 state.cpu.r[0] = bit_cast<uint32_t>(&x);
159 state.cpu.r[1] = bit_cast<uint32_t>(123);
160 state.cpu.r[2] = bit_cast<uint32_t>(&x);
161 stack[0] = kTestValue64;
162
163 auto [arg1, arg2, arg3, arg4] = GuestParamsValues<void(int*, int, int*, uint64_t)>(&state);
164 auto [arg1f, arg2f, arg3f, arg4f] =
165 GuestParamsValues<void (*)(int*, int, int*, uint64_t)>(&state);
166 auto [arg1v, arg2v, arg3v, arg4v] =
167 GuestParamsValues<void(int*, int, int*, uint64_t, ...)>(&state);
168 auto [arg1fv, arg2fv, arg3fv, arg4fv] =
169 GuestParamsValues<void (*)(int*, int, int*, uint64_t, ...)>(&state);
170
171 EXPECT_EQ(&x, arg1);
172 EXPECT_EQ(123, arg2);
173 EXPECT_EQ(&x, arg3);
174 EXPECT_EQ(kTestValue64, arg4);
175
176 EXPECT_EQ(&x, arg1f);
177 EXPECT_EQ(123, arg2f);
178 EXPECT_EQ(&x, arg3f);
179 EXPECT_EQ(kTestValue64, arg4f);
180
181 EXPECT_EQ(&x, arg1v);
182 EXPECT_EQ(123, arg2v);
183 EXPECT_EQ(&x, arg3v);
184 EXPECT_EQ(kTestValue64, arg4v);
185
186 EXPECT_EQ(&x, arg1fv);
187 EXPECT_EQ(123, arg2fv);
188 EXPECT_EQ(&x, arg3fv);
189 EXPECT_EQ(kTestValue64, arg4fv);
190 }
191
TEST(Params,LongLongArgHugeStructResult)192 TEST(Params, LongLongArgHugeStructResult) {
193 ThreadState state{};
194
195 struct Result {
196 uint64_t values[10];
197 } result{};
198
199 state.cpu.r[0] = bit_cast<uint32_t>(&result);
200 state.cpu.r[2] = 0xbeef;
201 state.cpu.r[3] = 0xdead;
202
203 auto [arg] = GuestParamsValues<Result(uint64_t)>(&state);
204
205 EXPECT_EQ(0xdead0000beefULL, arg);
206
207 auto&& [ret] = GuestReturnReference<Result(uint64_t)>(&state);
208
209 ret = Result{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
210
211 EXPECT_EQ(1U, result.values[0]);
212 EXPECT_EQ(2U, result.values[1]);
213 EXPECT_EQ(3U, result.values[2]);
214 EXPECT_EQ(4U, result.values[3]);
215 EXPECT_EQ(5U, result.values[4]);
216 EXPECT_EQ(6U, result.values[5]);
217 EXPECT_EQ(7U, result.values[6]);
218 EXPECT_EQ(8U, result.values[7]);
219 EXPECT_EQ(9U, result.values[8]);
220 EXPECT_EQ(10U, result.values[9]);
221 }
222
TEST(GuestVAListParams,PtrFloatFloatArgs)223 TEST(GuestVAListParams, PtrFloatFloatArgs) {
224 ThreadState state{};
225
226 static int x;
227
228 state.cpu.r[0] = bit_cast<uint32_t>(&x);
229 state.cpu.r[1] = bit_cast<uint32_t>(1.0f);
230 state.cpu.r[2] = bit_cast<uint32_t>(-.75f);
231
232 GuestVAListParams params = GuestParamsValues<void(...)>(&state);
233
234 EXPECT_EQ(&x, params.GetPointerParam<int>());
235 EXPECT_FLOAT_EQ(1.0f, params.GetParam<float>());
236 EXPECT_FLOAT_EQ(-.75f, params.GetParam<float>());
237 }
238
TEST(GuestVAListParams,PtrIntPtrLongLongArgs)239 TEST(GuestVAListParams, PtrIntPtrLongLongArgs) {
240 ThreadState state{};
241
242 alignas(8) uint64_t stack[4];
243 state.cpu.r[13] = bit_cast<uint32_t>(&stack[0]);
244
245 static int x;
246 constexpr uint64_t kTestValue64 = 0xffff0000ffff0000ULL;
247
248 state.cpu.r[0] = bit_cast<uint32_t>(&x);
249 state.cpu.r[1] = bit_cast<uint32_t>(123);
250 state.cpu.r[2] = bit_cast<uint32_t>(&x);
251 stack[0] = kTestValue64;
252
253 GuestVAListParams params = GuestParamsValues<void(...)>(&state);
254
255 EXPECT_EQ(&x, params.GetPointerParam<int>());
256 EXPECT_EQ(123, params.GetParam<int>());
257 EXPECT_EQ(&x, params.GetPointerParam<int>());
258 EXPECT_EQ(kTestValue64, params.GetParam<uint64_t>());
259 }
260
261 } // namespace
262
263 } // namespace berberis
264