1 : // Copyright 2012 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 <windows.h> // NOLINT
16 : #include <objbase.h> // NOLINT
17 : #include <winnt.h> // NOLINT
18 :
19 : #include <math.h>
20 : #include <stdio.h>
21 : #include <time.h>
22 :
23 : #include <cstdlib>
24 :
25 : // Bring in a data import from export_dll.dll. This will cause a global data
26 : // symbol to be emitted pointing to the import entry, but with the type we give
27 : // here. If the type is bigger than the entire import table then the data
28 : // symbol will be bigger than the block it resolves to. The data must be
29 : // explicitly marked dllimport otherwise the linker will treat it as a code
30 : // symbol and create a thunk for it.
31 m : __declspec(dllimport) extern int kExportedData[1024];
32 :
33 : // A handful of TLS variables, to cause TLS fixups to appear.
34 m : __declspec(thread) int tls_int = 42;
35 m : __declspec(thread) int tls_array[64] = { 0 };
36 m : __declspec(thread) char tls_string_buffer[512] = { 0 };
37 m : __declspec(thread) double tls_double = 3.5;
38 :
39 : // A dummy TLS Initialization callback handler.
40 m : VOID NTAPI MyTlsCallback(PVOID instance, DWORD reason, PVOID reserved) {
41 m : ::time(NULL);
42 m : }
43 :
44 : // Declare a TLS initializer callback to the linker.
45 : #pragma section(".CRT$XLY",long,read)
46 m : extern "C" __declspec(allocate(".CRT$XLY"))
47 m : PIMAGE_TLS_CALLBACK _xl_y1 = MyTlsCallback;
48 :
49 m : extern "C" __declspec(allocate(".CRT$XLY"))
50 m : PIMAGE_TLS_CALLBACK _xl_y2 = MyTlsCallback;
51 :
52 : // Use both mechanisms for importing functions (explicitly hinted with
53 : // 'dllimport' and not) so that both code generation mechanisms are present
54 : // in the final binary and subsequently tested by our decomposer.
55 m : __declspec(dllimport) extern int function1();
56 m : extern int function2();
57 m : extern int function3();
58 :
59 : #pragma auto_inline(off)
60 :
61 m : DWORD WINAPI TestExport(size_t buf_len, char* buf) {
62 m : static const char kTestString[] =
63 m : "The quick brown fox jumped over the lazy dog";
64 :
65 m : ::strncpy(buf, kTestString, buf_len);
66 :
67 m : return 0;
68 m : }
69 :
70 m : DWORD WINAPI BringInOle32DelayLib() {
71 : // Reference this from Ole32 to pull in something.
72 m : ::CoInitialize(NULL);
73 :
74 m : return 0;
75 m : }
76 :
77 m : const char* BoolToString(bool value) {
78 m : return value ? "true" : "false";
79 m : }
80 :
81 m : int FunctionWithInlineAssembly() {
82 m : static int datum = 0;
83 m : __asm {
84 m : mov eax, [datum];
85 m : add eax, 1;
86 m : mov [datum], eax;
87 m : }
88 m : return datum;
89 m : }
90 :
91 : #pragma auto_inline()
92 :
93 m : BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, LPVOID reserved) {
94 : // The goal of the following weird code is to thwart any optimizations
95 : // that the compiler might try.
96 :
97 : // Put a series of calls in order. In general, expect they'll show up in
98 : // the same order when we search for references.
99 m : function1();
100 m : function1();
101 m : function3();
102 m : function2();
103 m : function2();
104 m : function3();
105 m : function1();
106 m : function1();
107 :
108 m : int foo = FunctionWithInlineAssembly();
109 m : foo += kExportedData[0];
110 :
111 : // We modify the exported data. If imports are improperly thunked this will
112 : // cause us to write junk all over any created thunks and should hopefully
113 : // cause the instrumented test_dll to explode.
114 m : for (size_t i = 0; i < sizeof(kExportedData) / sizeof(kExportedData[0]); ++i)
115 m : kExportedData[i] = i;
116 :
117 : // The following odd code and switch statement are to outsmart the
118 : // optimizer and coerce it to generate a case and jump table pair.
119 : // On decomposition, we expect to find and label the case and jump
120 : // tables individually.
121 m : wchar_t c = rand() % static_cast<wchar_t>(-1);
122 :
123 : // We also need to coerce the optimizer into keeping around kExportedData and
124 : // FunctionWithInlineAssembly.
125 m : c ^= static_cast<wchar_t>(foo);
126 :
127 m : bool is_whitespace = false;
128 m : bool is_qwerty = false;
129 m : bool is_asdfgh = false;
130 m : bool is_upper_case = false;
131 m : bool is_other = false;
132 :
133 : // Switch over the UTF16 character space.
134 m : switch (c) {
135 m : case L'Q':
136 m : case L'W':
137 m : case L'E':
138 m : case L'R':
139 m : case L'T':
140 m : case L'Y':
141 m : is_qwerty = true;
142 m : is_upper_case = true;
143 m : break;
144 :
145 m : case L'q':
146 m : case L'w':
147 m : case L'e':
148 m : case L'r':
149 m : case L't':
150 m : case L'y':
151 m : is_qwerty = true;
152 m : is_upper_case = false;
153 m : break;
154 :
155 m : case L'A':
156 m : case L'S':
157 m : case L'D':
158 m : case L'F':
159 m : case L'G':
160 m : case L'H':
161 m : is_asdfgh = true;
162 m : is_upper_case = true;
163 m : break;
164 :
165 m : case L'a':
166 m : case L's':
167 m : case L'd':
168 m : case L'f':
169 m : case L'g':
170 m : case L'h':
171 m : is_asdfgh = true;
172 m : is_upper_case = false;
173 m : break;
174 :
175 m : case ' ':
176 m : case '\t':
177 m : case '\r':
178 m : case '\n':
179 m : is_whitespace = true;
180 m : break;
181 :
182 m : default:
183 m : is_other = true;
184 m : break;
185 m : }
186 :
187 m : char buffer[1024] = {'\0'};
188 m : ::memset(buffer, 0, sizeof(buffer));
189 m : ::_snprintf(buffer,
190 m : sizeof(buffer) - 1,
191 m : "is_qwerty=%s\nis_asdfgh=%s\nis_upper_case=%s\nis_whitespace=%s\n"
192 m : "is_other=%s",
193 m : BoolToString(is_qwerty),
194 m : BoolToString(is_asdfgh),
195 m : BoolToString(is_upper_case),
196 m : BoolToString(is_whitespace),
197 m : BoolToString(is_other));
198 :
199 m : TestExport(sizeof(buffer), buffer);
200 :
201 : // This code generates a simple jump table with no case table following it.
202 :
203 m : int n = rand();
204 :
205 m : switch (n % 3) {
206 m : case 0:
207 m : n += function1();
208 m : break;
209 m : case 1:
210 m : n += function2();
211 m : break;
212 m : case 2:
213 m : n += function3();
214 m : break;
215 m : case 3:
216 m : n -= function1();
217 m : break;
218 m : case 4:
219 m : n -= function2();
220 m : break;
221 m : case 5:
222 m : n -= function3();
223 m : break;
224 m : }
225 :
226 : // The following odd code and switch statement are to outsmart the
227 : // optimizer and coerce it to generate another case and jump table
228 : // pair. On decomposition, we expect to find and label the case
229 : // and jump tables individually.
230 :
231 : // Access the TLS data so that some TLS FIXUPs are produced.
232 m : n += tls_int;
233 m : n += tls_array[0];
234 m : n += tls_string_buffer[0];
235 m : n += static_cast<int>(tls_double);
236 :
237 : // The case table is a 20X expanded switch on n mod 7.
238 m : switch (n % 140) {
239 m : case 0:
240 m : case 7:
241 m : case 14:
242 m : case 21:
243 m : case 28:
244 m : case 35:
245 m : case 42:
246 m : case 49:
247 m : case 56:
248 m : case 63:
249 m : case 70:
250 m : case 77:
251 m : case 84:
252 m : case 91:
253 m : case 98:
254 m : case 105:
255 m : case 112:
256 m : case 119:
257 m : case 126:
258 m : case 133:
259 m : return reinterpret_cast<BOOL>(
260 m : function1() + strstr("hello world", "hello"));
261 :
262 m : case 1:
263 m : case 8:
264 m : case 15:
265 m : case 22:
266 m : case 29:
267 m : case 36:
268 m : case 43:
269 m : case 50:
270 m : case 57:
271 m : case 64:
272 m : case 71:
273 m : case 78:
274 m : case 85:
275 m : case 92:
276 m : case 99:
277 m : case 106:
278 m : case 113:
279 m : case 120:
280 m : case 127:
281 m : case 134:
282 m : return static_cast<BOOL>(function2() + strlen("foobar"));
283 :
284 m : case 2:
285 m : case 9:
286 m : case 16:
287 m : case 23:
288 m : case 30:
289 m : case 37:
290 m : case 44:
291 m : case 51:
292 m : case 58:
293 m : case 65:
294 m : case 72:
295 m : case 79:
296 m : case 86:
297 m : case 93:
298 m : case 100:
299 m : case 107:
300 m : case 114:
301 m : case 121:
302 m : case 128:
303 m : case 135:
304 m : return static_cast<BOOL>(function3() + clock());
305 :
306 m : case 3:
307 m : case 10:
308 m : case 17:
309 m : case 24:
310 m : case 31:
311 m : case 38:
312 m : case 45:
313 m : case 52:
314 m : case 59:
315 m : case 66:
316 m : case 73:
317 m : case 80:
318 m : case 87:
319 m : case 94:
320 m : case 101:
321 m : case 108:
322 m : case 115:
323 m : case 122:
324 m : case 129:
325 m : case 136:
326 m : return static_cast<BOOL>(function1() + function2() +
327 m : reinterpret_cast<int>(memchr("hello", 'e', 5)));
328 :
329 m : case 4:
330 m : case 11:
331 m : case 18:
332 m : case 25:
333 m : case 32:
334 m : case 39:
335 m : case 46:
336 m : case 53:
337 m : case 60:
338 m : case 67:
339 m : case 74:
340 m : case 81:
341 m : case 88:
342 m : case 95:
343 m : case 102:
344 m : case 109:
345 m : case 116:
346 m : case 123:
347 m : case 130:
348 m : case 137:
349 m : return static_cast<BOOL>(function1() + function3() + abs(-3));
350 :
351 m : case 5:
352 m : case 12:
353 m : case 19:
354 m : case 26:
355 m : case 33:
356 m : case 40:
357 m : case 47:
358 m : case 54:
359 m : case 61:
360 m : case 68:
361 m : case 75:
362 m : case 82:
363 m : case 89:
364 m : case 96:
365 m : case 103:
366 m : case 110:
367 m : case 117:
368 m : case 124:
369 m : case 131:
370 m : case 138:
371 m : return static_cast<BOOL>(
372 m : function2() + function3() + static_cast<int>(floor(1.3)));
373 :
374 m : case 6:
375 m : case 13:
376 m : case 20:
377 m : case 27:
378 m : case 34:
379 m : case 41:
380 m : case 48:
381 m : case 55:
382 m : case 62:
383 m : case 69:
384 m : case 76:
385 m : case 83:
386 m : case 90:
387 m : case 97:
388 m : case 104:
389 m : case 111:
390 m : case 118:
391 m : case 125:
392 m : case 132:
393 m : case 139:
394 m : return static_cast<BOOL>(
395 m : function1() + function2() + function3() + atoi("7"));
396 m : }
397 m : }
398 :
399 m : void used_operation() {
400 m : function1();
401 m : function2();
402 m : function3();
403 m : }
404 :
405 : // This won't be called.
406 m : void unused_operation() {
407 m : char dummy[512];
408 m : TestExport(sizeof(dummy), dummy);
409 m : }
410 :
411 m : class Used {
412 m : public:
413 m : Used() {}
414 m : virtual ~Used() {}
415 m : virtual void M() {
416 m : used_operation();
417 m : }
418 m : };
419 :
420 : // Unused::M() won't be called.
421 m : class Unused : public Used {
422 m : public:
423 m : virtual void M() {
424 m : unused_operation();
425 m : }
426 m : };
427 :
428 m : void CALLBACK TestUnusedFuncs(HWND unused_window,
429 m : HINSTANCE unused_instance,
430 m : LPSTR unused_cmd_line,
431 m : int unused_show) {
432 m : bool call_it = time(NULL) > 10000; // true unless you play with the clock.
433 :
434 m : (call_it ? used_operation : unused_operation)();
435 :
436 m : Used a;
437 m : Unused b;
438 m : (call_it ? &a : &b)->M();
439 m : }
|