VirtualBox

source: vbox/trunk/src/VBox/ValidationKit/utils/cpu/cidet-app.cpp@ 53579

Last change on this file since 53579 was 53579, checked in by vboxsync, 10 years ago

cidet: More code...

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 40.0 KB
Line 
1/* $Id: cidet-app.cpp 53579 2014-12-19 19:24:09Z vboxsync $ */
2/** @file
3 * CPU Instruction Decoding & Execution Tests - Ring-3 Driver Application.
4 */
5
6/*
7 * Copyright (C) 2014 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 */
26
27
28/*******************************************************************************
29* Header Files *
30*******************************************************************************/
31#include "cidet.h"
32
33#include <iprt/asm-amd64-x86.h>
34#include <iprt/buildconfig.h>
35#include <iprt/getopt.h>
36#include <iprt/initterm.h>
37#include <iprt/mem.h>
38#include <iprt/param.h>
39#include <iprt/rand.h>
40#include <iprt/stream.h>
41#include <iprt/string.h>
42#include <iprt/test.h>
43
44#ifdef RT_OS_WINDOWS
45# include <Windows.h>
46#else
47# define USE_SIGNALS
48# include <signal.h>
49# include <unistd.h>
50#endif
51
52
53/*******************************************************************************
54* Defined Constants And Macros *
55*******************************************************************************/
56/** @def CIDET_LEAVE_GS_ALONE
57 * Leave GS alone on 64-bit darwin (gs is 0, no ldt or gdt entry to load that'll
58 * restore the lower 32-bits of the base when saving and restoring the register).
59 */
60#if defined(RT_OS_DARWIN) && defined(RT_ARCH_AMD64)
61# define CIDET_LEAVE_GS_ALONE
62#endif
63
64
65/*******************************************************************************
66* Structures and Typedefs *
67*******************************************************************************/
68/**
69 * CIDET driver app buffer.
70 */
71typedef struct CIDETAPPBUF
72{
73 /** The buffer size. */
74 size_t cb;
75 /** The normal allocation.
76 * There is a fence page before this as well as at pbNormal+cb. */
77 uint8_t *pbNormal;
78 /** The low memory allocation (32-bit addressable if 64-bit host, 16-bit
79 * addressable if 32-bit host). */
80 uint8_t *pbLow;
81 /** Set if we're using the normal buffer, clear if it's the low one. */
82 bool fUsingNormal : 1;
83 /** Set if the buffer is armed, clear if mostly accessible. */
84 bool fArmed : 1;
85 /** Set if this is a code buffer. */
86 bool fIsCode : 1;
87 /** The memory protection for the pages (RTMEM_PROT_XXX). */
88 uint8_t fDefaultProt : 3;
89 /** The memory protection for the last page (RTMEM_PROT_XXX). */
90 uint8_t fLastPageProt : 3;
91 /** The buffer index. */
92 uint16_t idxCfg;
93} CIDETAPPBUF;
94/** Pointer to a CIDET driver app buffer. */
95typedef CIDETAPPBUF *PCIDETAPPBUF;
96
97/** Number of code buffers. */
98#define CIDETAPP_CODE_BUF_COUNT 1
99/** Number of data buffers. */
100#define CIDETAPP_DATA_BUF_COUNT 1
101
102
103/**
104 * CIDET driver app instance.
105 */
106typedef struct CIDETAPP
107{
108 /** The core structure. */
109 CIDETCORE Core;
110 /** The execute return context. */
111 CIDETCPUCTX ExecuteCtx;
112 /** Code buffers (runs parallel to g_aCodeBufCfgs). */
113 CIDETAPPBUF aCodeBuffers[CIDETAPP_CODE_BUF_COUNT];
114 /** Data buffers (runs parallel to g_aDataBufCfgs). */
115 CIDETAPPBUF aDataBuffers[CIDETAPP_DATA_BUF_COUNT];
116
117 /** The lowest stack address. */
118 uint8_t *pbStackLow;
119 /** The end of the stack allocation (highest address). */
120 uint8_t *pbStackEnd;
121 /** Stack size (= pbStackEnd - pbStackLow). */
122 uint32_t cbStack;
123} CIDETAPP;
124/** Pointer to a CIDET driver app instance. */
125typedef CIDETAPP *PCIDETAPP;
126/** Pointer to a pointer to a CIDET driver app instance. */
127typedef PCIDETAPP *PPCIDETAPP;
128
129
130/*******************************************************************************
131* Global Variables *
132*******************************************************************************/
133/** The test instance handle. */
134static RTTEST g_hTest;
135/** Points to the instance data while executing, NULL if not executing or if
136 * we've already handled the first exception while executing. */
137static PCIDETAPP volatile g_pExecutingThis;
138#ifdef USE_SIGNALS
139/** The default signal mask. */
140static sigset_t g_ProcSigMask;
141/** The alternative signal stack. */
142static stack_t g_AltStack;
143#endif
144
145
146/** Code buffer configurations (parallel to CIDETAPP::aCodeBuffers). */
147static CIDETBUFCFG g_aCodeBufCfgs[CIDETAPP_CODE_BUF_COUNT] =
148{
149 {
150 "Normal",
151 CIDETBUF_PROT_RWX | CIDETBUF_DPL_3 | CIDETBUF_DPL_SAME | CIDETBUF_SEG_ER | CIDETBUF_KIND_CODE,
152 },
153};
154
155/** Data buffer configurations (parallel to CIDETAPP::aDataBuffers). */
156static CIDETBUFCFG g_aDataBufCfgs[CIDETAPP_DATA_BUF_COUNT] =
157{
158 {
159 "Normal",
160 CIDETBUF_PROT_RWX | CIDETBUF_DPL_3 | CIDETBUF_DPL_SAME | CIDETBUF_SEG_RW | CIDETBUF_KIND_DATA,
161 },
162};
163
164
165/*******************************************************************************
166* Internal Functions *
167*******************************************************************************/
168DECLASM(void) CidetAppSaveAndRestoreCtx(void);
169DECLASM(void) CidetAppRestoreCtx(PCCIDETCPUCTX pRestoreCtx);
170DECLASM(void) CidetAppExecute(PCIDETCPUCTX pSaveCtx, PCCIDETCPUCTX pRestoreCtx);
171
172
173/*
174 *
175 *
176 * Exception and signal handling.
177 * Exception and signal handling.
178 * Exception and signal handling.
179 *
180 *
181 */
182
183#ifdef RT_OS_WINDOWS
184static int CidetAppXcptFilter(EXCEPTION_POINTERS *pXcptPtrs)
185{
186 /*
187 * Grab the this point. We expect at most one signal.
188 */
189 PCIDETAPP pThis = g_pExecutingThis;
190 g_pExecutingThis = NULL;
191 if (pThis == NULL)
192 {
193 /* we're up the infamous creek... */
194 for (;;) ExitProcess(2);
195 }
196
197 /*
198 * Gather CPU state information from the context structure.
199 */
200 CONTEXT *pSrcCtx = pXcptPtrs->ContextRecord;
201# ifdef RT_ARCH_AMD64
202 if ( (pSrcCtx->ContextFlags & (CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_SEGMENTS))
203 != (CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_SEGMENTS))
204 __debugbreak();
205 pThis->Core.ActualCtx.rip = pSrcCtx->Rip;
206 pThis->Core.ActualCtx.rfl = pSrcCtx->EFlags;
207 pThis->Core.ActualCtx.aGRegs[X86_GREG_xAX] = pSrcCtx->Rax;
208 pThis->Core.ActualCtx.aGRegs[X86_GREG_xCX] = pSrcCtx->Rcx;
209 pThis->Core.ActualCtx.aGRegs[X86_GREG_xDX] = pSrcCtx->Rdx;
210 pThis->Core.ActualCtx.aGRegs[X86_GREG_xBX] = pSrcCtx->Rbx;
211 pThis->Core.ActualCtx.aGRegs[X86_GREG_xSP] = pSrcCtx->Rsp;
212 pThis->Core.ActualCtx.aGRegs[X86_GREG_xBP] = pSrcCtx->Rbp;
213 pThis->Core.ActualCtx.aGRegs[X86_GREG_xSI] = pSrcCtx->Rsi;
214 pThis->Core.ActualCtx.aGRegs[X86_GREG_xDI] = pSrcCtx->Rdi;
215 pThis->Core.ActualCtx.aGRegs[X86_GREG_x8] = pSrcCtx->R8;
216 pThis->Core.ActualCtx.aGRegs[X86_GREG_x9] = pSrcCtx->R9;
217 pThis->Core.ActualCtx.aGRegs[X86_GREG_x10] = pSrcCtx->R10;
218 pThis->Core.ActualCtx.aGRegs[X86_GREG_x11] = pSrcCtx->R11;
219 pThis->Core.ActualCtx.aGRegs[X86_GREG_x12] = pSrcCtx->R12;
220 pThis->Core.ActualCtx.aGRegs[X86_GREG_x13] = pSrcCtx->R13;
221 pThis->Core.ActualCtx.aGRegs[X86_GREG_x14] = pSrcCtx->R14;
222 pThis->Core.ActualCtx.aGRegs[X86_GREG_x15] = pSrcCtx->R15;
223 pThis->Core.ActualCtx.aSRegs[X86_SREG_ES] = pSrcCtx->SegEs;
224 pThis->Core.ActualCtx.aSRegs[X86_SREG_CS] = pSrcCtx->SegCs;
225 pThis->Core.ActualCtx.aSRegs[X86_SREG_SS] = pSrcCtx->SegSs;
226 pThis->Core.ActualCtx.aSRegs[X86_SREG_DS] = pSrcCtx->SegDs;
227 pThis->Core.ActualCtx.aSRegs[X86_SREG_FS] = pSrcCtx->SegFs;
228 pThis->Core.ActualCtx.aSRegs[X86_SREG_GS] = pSrcCtx->SegGs;
229 if (pSrcCtx->ContextFlags & CONTEXT_FLOATING_POINT)
230 {
231 /* ... */
232 }
233 if (pSrcCtx->ContextFlags & CONTEXT_DEBUG_REGISTERS)
234 {
235 /* ... */
236 }
237
238# elif defined(RT_ARCH_X86)
239 if ( (pSrcCtx->ContextFlags & (CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_SEGMENTS))
240 != (CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_SEGMENTS))
241 __debugbreak();
242 pThis->Core.ActualCtx.rip = pSrcCtx->Eip;
243 pThis->Core.ActualCtx.rfl = pSrcCtx->EFlags;
244 pThis->Core.ActualCtx.aGRegs[X86_GREG_xAX] = pSrcCtx->Eax;
245 pThis->Core.ActualCtx.aGRegs[X86_GREG_xCX] = pSrcCtx->Ecx;
246 pThis->Core.ActualCtx.aGRegs[X86_GREG_xDX] = pSrcCtx->Edx;
247 pThis->Core.ActualCtx.aGRegs[X86_GREG_xBX] = pSrcCtx->Ebx;
248 pThis->Core.ActualCtx.aGRegs[X86_GREG_xSP] = pSrcCtx->Esp;
249 pThis->Core.ActualCtx.aGRegs[X86_GREG_xBP] = pSrcCtx->Ebp;
250 pThis->Core.ActualCtx.aGRegs[X86_GREG_xSI] = pSrcCtx->Esi;
251 pThis->Core.ActualCtx.aGRegs[X86_GREG_xDI] = pSrcCtx->Edi;
252 pThis->Core.ActualCtx.aGRegs[X86_GREG_x8] = 0;
253 pThis->Core.ActualCtx.aGRegs[X86_GREG_x9] = 0;
254 pThis->Core.ActualCtx.aGRegs[X86_GREG_x10] = 0;
255 pThis->Core.ActualCtx.aGRegs[X86_GREG_x11] = 0;
256 pThis->Core.ActualCtx.aGRegs[X86_GREG_x12] = 0;
257 pThis->Core.ActualCtx.aGRegs[X86_GREG_x13] = 0;
258 pThis->Core.ActualCtx.aGRegs[X86_GREG_x14] = 0;
259 pThis->Core.ActualCtx.aGRegs[X86_GREG_x15] = 0;
260 pThis->Core.ActualCtx.aSRegs[X86_SREG_ES] = pSrcCtx->SegEs;
261 pThis->Core.ActualCtx.aSRegs[X86_SREG_CS] = pSrcCtx->SegCs;
262 pThis->Core.ActualCtx.aSRegs[X86_SREG_SS] = pSrcCtx->SegSs;
263 pThis->Core.ActualCtx.aSRegs[X86_SREG_DS] = pSrcCtx->SegDs;
264 pThis->Core.ActualCtx.aSRegs[X86_SREG_FS] = pSrcCtx->SegFs;
265 pThis->Core.ActualCtx.aSRegs[X86_SREG_GS] = pSrcCtx->SegGs;
266 if (pSrcCtx->ContextFlags & CONTEXT_FLOATING_POINT)
267 {
268 /* ... */
269 }
270 if (pSrcCtx->ContextFlags & CONTEXT_EXTENDED_REGISTERS)
271 {
272 /* ... */
273 }
274 if (pSrcCtx->ContextFlags & CONTEXT_DEBUG_REGISTERS)
275 {
276 /* ... */
277 }
278# else
279# error "Not supported"
280# endif
281
282 /*
283 * Add/Adjust CPU state information according to the exception code.
284 */
285 pThis->Core.ActualCtx.uErr = UINT64_MAX;
286 switch (pXcptPtrs->ExceptionRecord->ExceptionCode)
287 {
288 case EXCEPTION_INT_DIVIDE_BY_ZERO:
289 pThis->Core.ActualCtx.uXcpt = X86_XCPT_DE;
290 break;
291 case EXCEPTION_SINGLE_STEP:
292 pThis->Core.ActualCtx.uXcpt = X86_XCPT_DB;
293 break;
294 case EXCEPTION_BREAKPOINT:
295 pThis->Core.ActualCtx.uXcpt = X86_XCPT_BP;
296 break;
297 case EXCEPTION_INT_OVERFLOW:
298 pThis->Core.ActualCtx.uXcpt = X86_XCPT_OF;
299 break;
300 case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
301 pThis->Core.ActualCtx.uXcpt = X86_XCPT_BR;
302 break;
303 case EXCEPTION_ILLEGAL_INSTRUCTION:
304 pThis->Core.ActualCtx.uXcpt = X86_XCPT_UD;
305 break;
306
307 case EXCEPTION_PRIV_INSTRUCTION:
308 pThis->Core.ActualCtx.uXcpt = X86_XCPT_GP;
309 pThis->Core.ActualCtx.uErr = 0;
310 break;
311
312 case EXCEPTION_ACCESS_VIOLATION:
313 {
314 pThis->Core.ActualCtx.uXcpt = X86_XCPT_PF;
315 pThis->Core.ActualCtx.cr2 = pXcptPtrs->ExceptionRecord->ExceptionInformation[1];
316 pThis->Core.ActualCtx.uErr = 0;
317 if (pXcptPtrs->ExceptionRecord->ExceptionInformation[0] == EXCEPTION_WRITE_FAULT)
318 pThis->Core.ActualCtx.uErr = X86_TRAP_PF_RW;
319 else if (pXcptPtrs->ExceptionRecord->ExceptionInformation[0] == EXCEPTION_EXECUTE_FAULT)
320 pThis->Core.ActualCtx.uErr = X86_TRAP_PF_ID;
321 else if (pXcptPtrs->ExceptionRecord->ExceptionInformation[0] != EXCEPTION_READ_FAULT)
322 AssertFatalFailed();
323
324 MEMORY_BASIC_INFORMATION MemInfo = {0};
325 if (VirtualQuery((PVOID)pXcptPtrs->ExceptionRecord->ExceptionInformation[1], &MemInfo, sizeof(MemInfo)) > 0)
326 switch (MemInfo.Protect & 0xff)
327 {
328 case PAGE_NOACCESS:
329 break;
330 case PAGE_READONLY:
331 case PAGE_READWRITE:
332 case PAGE_WRITECOPY:
333 case PAGE_EXECUTE:
334 case PAGE_EXECUTE_READ:
335 case PAGE_EXECUTE_READWRITE:
336 case PAGE_EXECUTE_WRITECOPY:
337 pThis->Core.ActualCtx.uErr |= X86_TRAP_PF_P;
338 break;
339 default:
340 AssertFatalFailed();
341 }
342 break;
343 }
344
345 case EXCEPTION_FLT_DENORMAL_OPERAND:
346 case EXCEPTION_FLT_DIVIDE_BY_ZERO:
347 case EXCEPTION_FLT_INEXACT_RESULT:
348 case EXCEPTION_FLT_INVALID_OPERATION:
349 case EXCEPTION_FLT_OVERFLOW:
350 case EXCEPTION_FLT_STACK_CHECK:
351 case EXCEPTION_FLT_UNDERFLOW:
352 pThis->Core.ActualCtx.uXcpt = X86_XCPT_MF;
353 break;
354
355 case EXCEPTION_DATATYPE_MISALIGNMENT:
356 pThis->Core.ActualCtx.uXcpt = X86_XCPT_AC;
357 break;
358
359 default:
360 pThis->Core.ActualCtx.uXcpt = pXcptPtrs->ExceptionRecord->ExceptionCode;
361 break;
362 }
363
364 /*
365 * Our own personal long jump implementation.
366 */
367 CidetAppRestoreCtx(&pThis->ExecuteCtx);
368
369 /* Won't return...*/
370 return EXCEPTION_EXECUTE_HANDLER;
371}
372
373
374/**
375 * Vectored exception handler.
376 *
377 * @returns Long jumps or terminates the process.
378 * @param pXcptPtrs The exception record.
379 */
380static LONG CALLBACK CidetAppVectoredXcptHandler(EXCEPTION_POINTERS *pXcptPtrs)
381{
382 RTStrmPrintf(g_pStdErr, "CidetAppVectoredXcptHandler!\n");
383 CidetAppXcptFilter(pXcptPtrs);
384
385 /* won't get here. */
386 return EXCEPTION_CONTINUE_SEARCH;
387}
388
389
390/**
391 * Unhandled exception filter.
392 *
393 * @returns Long jumps or terminates the process.
394 * @param pXcptPtrs The exception record.
395 */
396static LONG CALLBACK CidetAppUnhandledXcptFilter(EXCEPTION_POINTERS *pXcptPtrs)
397{
398 RTStrmPrintf(g_pStdErr, "CidetAppUnhandledXcptFilter!\n");
399 CidetAppXcptFilter(pXcptPtrs);
400
401 /* won't get here. */
402 return EXCEPTION_CONTINUE_SEARCH;
403}
404
405
406#elif defined(USE_SIGNALS)
407/**
408 * Signal handler.
409 */
410static void CidetAppSigHandler(int iSignal, siginfo_t *pSigInfo, void *pvCtx)
411{
412# if 1
413 RTStrmPrintf(g_pStdErr, "signal %d pSigInfo=%p pvCtx=%p", iSignal, pSigInfo, pvCtx);
414 if (pSigInfo)
415 RTStrmPrintf(g_pStdErr, " si_addr=%p si_code=%#x sival_ptr=%p sival_int=%d",
416 pSigInfo->si_addr, pSigInfo->si_code, pSigInfo->si_value.sival_ptr, pSigInfo->si_value.sival_int);
417 RTStrmPrintf(g_pStdErr, "\n");
418# endif
419
420 /*
421 * Grab the this point. We expect at most one signal.
422 */
423 PCIDETAPP pThis = g_pExecutingThis;
424 g_pExecutingThis = NULL;
425 if (pThis == NULL)
426 {
427 /* we're up the infamous creek... */
428 RTStrmPrintf(g_pStdErr, "Creek time!\n");
429 for (;;) _exit(2);
430 }
431
432 /*
433 * Gather all the CPU state information available.
434 */
435
436
437 /*
438 * Jump back to CidetAppCbExecute.
439 */
440 CidetAppRestoreCtx(&pThis->ExecuteCtx);
441}
442#endif
443
444
445
446/*
447 *
448 * Buffer handling
449 * Buffer handling
450 * Buffer handling
451 *
452 *
453 */
454
455static int cidetAppAllocateAndConfigureOneBuffer(PCIDETAPP pThis, PCIDETAPPBUF pBuf, uint16_t idxBuf, bool fIsCode,
456 uint32_t fFlags)
457{
458 static uint8_t const s_afBufProtToDefaultMemProt[] =
459 {
460 /* [0] = */ RTMEM_PROT_NONE,
461 /* [1] = */ RTMEM_PROT_READ | RTMEM_PROT_WRITE | RTMEM_PROT_EXEC,
462 /* [2] = */ RTMEM_PROT_READ | RTMEM_PROT_WRITE,
463 /* [3] = */ RTMEM_PROT_READ | RTMEM_PROT_EXEC,
464 /* [4] = */ RTMEM_PROT_READ,
465 /* [5] = */ RTMEM_PROT_READ | RTMEM_PROT_WRITE | RTMEM_PROT_EXEC,
466 /* [6] = */ RTMEM_PROT_READ | RTMEM_PROT_WRITE | RTMEM_PROT_EXEC,
467 /* [7] = */ RTMEM_PROT_READ | RTMEM_PROT_WRITE | RTMEM_PROT_EXEC,
468 /* [8] = */ RTMEM_PROT_NONE,
469 /* [9] = */ RTMEM_PROT_NONE,
470 /* [10] = */ RTMEM_PROT_NONE,
471 /* [11] = */ RTMEM_PROT_NONE,
472 /* [12] = */ RTMEM_PROT_NONE,
473 /* [13] = */ RTMEM_PROT_NONE,
474 /* [14] = */ RTMEM_PROT_NONE,
475 /* [15] = */ RTMEM_PROT_NONE,
476 };
477 static uint8_t const s_afBufProtToLastPageMemProt[] =
478 {
479 /* [0] = */ RTMEM_PROT_NONE,
480 /* [1] = */ RTMEM_PROT_READ | RTMEM_PROT_WRITE | RTMEM_PROT_EXEC,
481 /* [2] = */ RTMEM_PROT_READ | RTMEM_PROT_WRITE,
482 /* [3] = */ RTMEM_PROT_READ | RTMEM_PROT_EXEC,
483 /* [4] = */ RTMEM_PROT_READ,
484 /* [5] = */ RTMEM_PROT_NONE,
485 /* [6] = */ RTMEM_PROT_READ | RTMEM_PROT_WRITE,
486 /* [7] = */ RTMEM_PROT_READ,
487 /* [8] = */ RTMEM_PROT_NONE,
488 /* [9] = */ RTMEM_PROT_NONE,
489 /* [10] = */ RTMEM_PROT_NONE,
490 /* [11] = */ RTMEM_PROT_NONE,
491 /* [12] = */ RTMEM_PROT_NONE,
492 /* [13] = */ RTMEM_PROT_NONE,
493 /* [14] = */ RTMEM_PROT_NONE,
494 /* [15] = */ RTMEM_PROT_NONE,
495 };
496
497 int rc;
498 Assert(CIDETBUF_IS_CODE(fFlags) == fIsCode);
499 pBuf->fIsCode = fIsCode;
500 pBuf->idxCfg = idxBuf;
501 pBuf->fUsingNormal = true;
502 pBuf->fDefaultProt = s_afBufProtToDefaultMemProt[fFlags & CIDETBUF_PROT_MASK];
503 pBuf->fLastPageProt = s_afBufProtToLastPageMemProt[fFlags & CIDETBUF_PROT_MASK];
504 if (pBuf->fDefaultProt != RTMEM_PROT_NONE)
505 {
506 /*
507 * Allocate a 3 page buffer plus two fence pages.
508 */
509 pBuf->cb = fIsCode ? CIDET_CODE_BUF_SIZE : CIDET_DATA_BUF_SIZE;
510 pBuf->pbNormal = (uint8_t *)RTMemPageAlloc(PAGE_SIZE + pBuf->cb + PAGE_SIZE);
511 if (pBuf->pbNormal)
512 {
513 memset(pBuf->pbNormal, 0x55, PAGE_SIZE);
514 memset(pBuf->pbNormal + PAGE_SIZE, 0xcc, pBuf->cb);
515 memset(pBuf->pbNormal + PAGE_SIZE + pBuf->cb, 0x77, PAGE_SIZE);
516
517 /* Set up fence pages. */
518 rc = RTMemProtect(pBuf->pbNormal, PAGE_SIZE, RTMEM_PROT_NONE); /* fence */
519 if (RT_SUCCESS(rc))
520 rc = RTMemProtect(pBuf->pbNormal + PAGE_SIZE + pBuf->cb, PAGE_SIZE, RTMEM_PROT_NONE); /* fence */
521 pBuf->pbNormal += PAGE_SIZE;
522
523 /* Default protection + read + write. */
524 if (RT_SUCCESS(rc))
525 rc = RTMemProtect(pBuf->pbNormal, pBuf->cb, pBuf->fDefaultProt | RTMEM_PROT_READ | RTMEM_PROT_WRITE);
526
527 /*
528 * Allocate a low memory buffer or LDT if necessary.
529 */
530 if ( RT_SUCCESS(rc)
531 && (uintptr_t)pBuf->pbNormal + pBuf->cb > RT_BIT_64(sizeof(uintptr_t) / 2 * 8))
532 {
533 /** @todo Buffers for the other addressing mode. */
534 pBuf->pbLow = NULL;
535 }
536 else
537 pBuf->pbLow = pBuf->pbNormal;
538 if (RT_SUCCESS(rc))
539 return VINF_SUCCESS;
540
541 }
542 else
543 rc = RTTestIFailedRc(VERR_NO_PAGE_MEMORY, "Error allocating three pages.");
544 }
545 else
546 rc = RTTestIFailedRc(VERR_NO_PAGE_MEMORY, "Unsupported buffer config: fFlags=%#x, idxBuf=%u", fFlags, idxBuf);
547 return rc;
548}
549
550
551static void CidetAppDeleteBuffer(PCIDETAPPBUF pBuf)
552{
553 RTMemProtect(pBuf->pbNormal - PAGE_SIZE, PAGE_SIZE + pBuf->cb + PAGE_SIZE, RTMEM_PROT_READ | RTMEM_PROT_WRITE);
554 RTMemPageFree(pBuf->pbNormal - PAGE_SIZE, PAGE_SIZE + pBuf->cb + PAGE_SIZE);
555 if (pBuf->pbLow != pBuf->pbNormal && pBuf->pbLow)
556 {
557 RTMemProtect(pBuf->pbLow, pBuf->cb, RTMEM_PROT_READ | RTMEM_PROT_WRITE);
558 RTMemFreeEx(pBuf->pbLow, pBuf->cb);
559 }
560}
561
562
563static bool CidetAppArmBuf(PCIDETAPP pThis, PCIDETAPPBUF pAppBuf)
564{
565 uint8_t *pbUsingBuf = (pAppBuf->fUsingNormal ? pAppBuf->pbNormal : pAppBuf->pbLow);
566 if (pAppBuf->fLastPageProt == pAppBuf->fDefaultProt)
567 {
568 if ((pAppBuf->fDefaultProt & (RTMEM_PROT_READ | RTMEM_PROT_WRITE)) != (RTMEM_PROT_READ | RTMEM_PROT_WRITE))
569 RTTESTI_CHECK_RC_RET(RTMemProtect(pbUsingBuf, pAppBuf->cb, pAppBuf->fDefaultProt), VINF_SUCCESS, false);
570 }
571 else
572 {
573 if ((pAppBuf->fDefaultProt & (RTMEM_PROT_READ | RTMEM_PROT_WRITE)) != (RTMEM_PROT_READ | RTMEM_PROT_WRITE))
574 RTTESTI_CHECK_RC_RET(RTMemProtect(pbUsingBuf, pAppBuf->cb - PAGE_SIZE, pAppBuf->fDefaultProt), VINF_SUCCESS, false);
575 RTTESTI_CHECK_RC_RET(RTMemProtect(pbUsingBuf + pAppBuf->cb - PAGE_SIZE, PAGE_SIZE, pAppBuf->fLastPageProt),
576 VINF_SUCCESS, false);
577 }
578 pAppBuf->fArmed = true;
579 return true;
580}
581
582
583static bool CidetAppDearmBuf(PCIDETAPP pThis, PCIDETAPPBUF pAppBuf)
584{
585 uint8_t *pbUsingBuf = (pAppBuf->fUsingNormal ? pAppBuf->pbNormal : pAppBuf->pbLow);
586 int rc = RTMemProtect(pbUsingBuf, pAppBuf->cb, pAppBuf->fDefaultProt | RTMEM_PROT_READ | RTMEM_PROT_WRITE);
587 if (RT_FAILURE(rc))
588 {
589 RTTestIFailed("RTMemProtect failed on %s buf #%u: %Rrc", pAppBuf->fIsCode ? "code" : "data", pAppBuf->idxCfg, rc);
590 return false;
591 }
592 pAppBuf->fArmed = false;
593 return true;
594}
595
596
597/**
598 * @interface_method_impl{CIDETCORE::pfnReInitDataBuf}
599 */
600static DECLCALLBACK(bool) CidetAppCbReInitDataBuf(PCIDETCORE pThis, PCIDETBUF pBuf)
601{
602 PCIDETAPP pThisApp = (PCIDETAPP)pThis;
603 PCIDETAPPBUF pAppBuf = &pThisApp->aDataBuffers[pBuf->idxCfg];
604 Assert(CIDETBUF_IS_DATA(pBuf->pCfg->fFlags));
605
606 /*
607 * De-arm the buffer.
608 */
609 if (pAppBuf->fArmed)
610 if (RT_UNLIKELY(!CidetAppDearmBuf(pThisApp, pAppBuf)))
611 return false;
612
613 /*
614 * Check the allocation requirements.
615 */
616 if (RT_UNLIKELY((size_t)pBuf->off + pBuf->cb > pAppBuf->cb))
617 {
618 RTTestIFailed("Buffer too small; off=%#x cb=%#x pAppBuf->cb=%#x (%s)",
619 pBuf->off, pBuf->cb, pAppBuf->cb, pBuf->pCfg->pszName);
620 return false;
621 }
622
623 /*
624 * Do we need to use the low buffer? Check that we have one, if we need it.
625 */
626 bool fUseNormal = pThis->cbAddrMode == ARCH_BITS / 8;
627 if (!fUseNormal && !pAppBuf->pbLow)
628 return false;
629
630 /*
631 * Update the state.
632 */
633 pAppBuf->fUsingNormal = fUseNormal;
634
635 pBuf->offActive = pBuf->off;
636 pBuf->cbActive = pBuf->cb;
637 pBuf->cbPrologue = 0;
638 pBuf->cbEpilogue = 0;
639 pBuf->uSeg = UINT32_MAX;
640 pBuf->cbActiveSegLimit = UINT64_MAX;
641 pBuf->uSegBase = 0;
642 if (fUseNormal)
643 pBuf->uEffBufAddr = (uintptr_t)pAppBuf->pbNormal;
644 else
645 pBuf->uEffBufAddr = (uintptr_t)pAppBuf->pbLow;
646
647 return true;
648}
649
650
651/**
652 * @interface_method_impl{CIDETCORE::pfnSetupDataBuf}
653 */
654static DECLCALLBACK(bool) CidetAppCbSetupDataBuf(PCIDETCORE pThis, PCIDETBUF pBuf, void const *pvSrc)
655{
656 PCIDETAPP pThisApp = (PCIDETAPP)pThis;
657 PCIDETAPPBUF pAppBuf = &pThisApp->aDataBuffers[pBuf->idxCfg];
658 Assert(CIDETBUF_IS_DATA(pBuf->pCfg->fFlags));
659 Assert(!pAppBuf->fArmed);
660
661
662 /*
663 * Copy over the data.
664 */
665 uint8_t *pbUsingBuf = (pAppBuf->fUsingNormal ? pAppBuf->pbNormal : pAppBuf->pbLow);
666 memcpy(pbUsingBuf + pBuf->offActive, pvSrc, pBuf->cbActive);
667
668 /*
669 * Arm the buffer.
670 */
671 return CidetAppArmBuf(pThisApp, pAppBuf);
672}
673
674
675/**
676 * @interface_method_impl{CIDETCORE::pfnIsBufEqual}
677 */
678static DECLCALLBACK(bool) CidetAppCbIsBufEqual(PCIDETCORE pThis, struct CIDETBUF *pBuf, void const *pvExpected)
679{
680 PCIDETAPP pThisApp = (PCIDETAPP)pThis;
681 PCIDETAPPBUF pAppBuf = CIDETBUF_IS_CODE(pBuf->pCfg->fFlags)
682 ? &pThisApp->aCodeBuffers[pBuf->idxCfg]
683 : &pThisApp->aDataBuffers[pBuf->idxCfg];
684
685 /*
686 * Disarm the buffer if we can't read it all.
687 */
688 if ( pAppBuf->fArmed
689 && ( !(pAppBuf->fLastPageProt & RTMEM_PROT_READ)
690 || !(pAppBuf->fDefaultProt & RTMEM_PROT_READ)) )
691 if (RT_UNLIKELY(!CidetAppDearmBuf(pThisApp, pAppBuf)))
692 return false;
693
694 /*
695 * Do the comparing.
696 */
697 uint8_t *pbUsingBuf = (pAppBuf->fUsingNormal ? pAppBuf->pbNormal : pAppBuf->pbLow);
698 if (memcmp(pbUsingBuf + pBuf->offActive, pvExpected, pBuf->cbActive) != 0)
699 {
700 /** @todo RTMEM_PROT_NONE may kill content on some hosts... */
701 return false;
702 }
703
704 /** @todo check padding. */
705 return true;
706}
707
708
709/*
710 *
711 * Code buffer, prologue, epilogue, and execution.
712 * Code buffer, prologue, epilogue, and execution.
713 * Code buffer, prologue, epilogue, and execution.
714 *
715 *
716 */
717
718
719/**
720 * @interface_method_impl{CIDETCORE::pfnReInitCodeBuf}
721 */
722static DECLCALLBACK(bool) CidetAppCbReInitCodeBuf(PCIDETCORE pThis, PCIDETBUF pBuf)
723{
724 PCIDETAPP pThisApp = (PCIDETAPP)pThis;
725 PCIDETAPPBUF pAppBuf = &pThisApp->aCodeBuffers[pBuf->idxCfg];
726 Assert(CIDETBUF_IS_CODE(pBuf->pCfg->fFlags));
727 Assert(pAppBuf->fUsingNormal);
728
729 /*
730 * De-arm the buffer.
731 */
732 if (pAppBuf->fArmed)
733 if (RT_UNLIKELY(!CidetAppDearmBuf(pThisApp, pAppBuf)))
734 return false;
735
736 /*
737 * Determin the prologue and epilogue sizes.
738 */
739 uint16_t cbPrologue = 0;
740 uint16_t cbEpilogue = ARCH_BITS == 64 ? 0x56 : 0x4e;
741 if (pThis->InCtx.fTrickyStack)
742 cbEpilogue = 16;
743
744 /*
745 * Check the allocation requirements.
746 */
747 if (RT_UNLIKELY( cbPrologue > pBuf->off
748 || (size_t)pBuf->off + pBuf->cb + cbEpilogue > pAppBuf->cb))
749 {
750 RTTestIFailed("Buffer too small; off=%#x cb=%#x cbPro=%#x cbEpi=%#x pAppBuf->cb=%#x (%s)",
751 pBuf->off, pBuf->cb, cbPrologue, cbEpilogue, pAppBuf->cb, pBuf->pCfg->pszName);
752 return false;
753 }
754
755 /*
756 * Update the state.
757 */
758 pAppBuf->fUsingNormal = true;
759
760 pBuf->cbActive = pBuf->cb;
761 pBuf->offActive = pBuf->off;
762 pBuf->cbPrologue = cbPrologue;
763 pBuf->cbEpilogue = cbEpilogue;
764 pBuf->uSeg = UINT32_MAX;
765 pBuf->cbActiveSegLimit = UINT64_MAX;
766 pBuf->uSegBase = 0;
767 pBuf->uEffBufAddr = (uintptr_t)pAppBuf->pbNormal;
768
769 return true;
770}
771
772
773/**
774 * @interface_method_impl{CIDETCORE::pfnSetupCodeBuf}
775 */
776static DECLCALLBACK(bool) CidetAppCbSetupCodeBuf(PCIDETCORE pThis, PCIDETBUF pBuf, void const *pvInstr)
777{
778 PCIDETAPP pThisApp = (PCIDETAPP)pThis;
779 PCIDETAPPBUF pAppBuf =&pThisApp->aCodeBuffers[pBuf->idxCfg];
780 Assert(CIDETBUF_IS_CODE(pBuf->pCfg->fFlags));
781 Assert(pAppBuf->fUsingNormal);
782 Assert(!pAppBuf->fArmed);
783
784 /*
785 * Emit prologue code.
786 */
787 uint8_t *pbDst = pAppBuf->pbNormal + pBuf->offActive - pBuf->cbPrologue;
788
789 /*
790 * Copy over the code.
791 */
792 Assert(pbDst == &pAppBuf->pbNormal[pBuf->offActive]);
793 memcpy(pbDst, pvInstr, pBuf->cbActive);
794 pbDst += pBuf->cbActive;
795
796 /*
797 * Emit epilogue code.
798 */
799 if (!pThis->InCtx.fTrickyStack)
800 {
801 /*
802 * The stack is reasonably good, do minimal work.
803 *
804 * Note! Ideally, we would just fill in 16 int3s here and check that
805 * we hit the first right one. However, if we wish to run this
806 * code with IEM, we better skip unnecessary trips to ring-0.
807 */
808 uint8_t * const pbStartEpilogue = pbDst;
809
810 /* jmp $+6 */
811 *pbDst++ = 0xeb;
812 *pbDst++ = 0x06; /* This is a push es, so if the decoder is one off, we'll hit the int 3 below. */
813
814 /* Six int3s for trapping incorrectly decoded instructions. */
815 *pbDst++ = 0xcc;
816 *pbDst++ = 0xcc;
817 *pbDst++ = 0xcc;
818 *pbDst++ = 0xcc;
819 *pbDst++ = 0xcc;
820 *pbDst++ = 0xcc;
821
822 /* push rip / call $+0 */
823 *pbDst++ = 0xe8;
824 *pbDst++ = 0x00;
825 *pbDst++ = 0x00;
826 *pbDst++ = 0x00;
827 *pbDst++ = 0x00;
828 uint8_t offRipAdjust = (uint8_t)(uintptr_t)(pbStartEpilogue - pbDst);
829
830 /* push xCX */
831 *pbDst++ = 0x51;
832
833 /* mov xCX, [xSP + xCB] */
834 *pbDst++ = 0x48;
835 *pbDst++ = 0x8b;
836 *pbDst++ = 0x4c;
837 *pbDst++ = 0x24;
838 *pbDst++ = sizeof(uintptr_t);
839
840 /* lea xCX, [xCX - 24] */
841 *pbDst++ = 0x48;
842 *pbDst++ = 0x8d;
843 *pbDst++ = 0x49;
844 *pbDst++ = offRipAdjust;
845
846 /* mov xCX, [xSP + xCB] */
847 *pbDst++ = 0x48;
848 *pbDst++ = 0x89;
849 *pbDst++ = 0x4c;
850 *pbDst++ = 0x24;
851 *pbDst++ = sizeof(uintptr_t);
852
853 /* mov xCX, &pThis->ActualCtx */
854#ifdef RT_ARCH_AMD64
855 *pbDst++ = 0x48;
856#endif
857 *pbDst++ = 0xb9;
858 *(uintptr_t *)pbDst = (uintptr_t)&pThisApp->Core.ActualCtx;
859 pbDst += sizeof(uintptr_t);
860
861 /* pop [ss:rcx + ActualCtx.aGRegs[X86_GREG_xCX]] */
862 *pbDst++ = 0x36;
863 *pbDst++ = 0x8f;
864 *pbDst++ = 0x41;
865 *pbDst++ = RT_OFFSETOF(CIDETCPUCTX, aGRegs[X86_GREG_xCX]);
866 Assert(RT_OFFSETOF(CIDETCPUCTX, aGRegs[X86_GREG_xCX]) < 0x7f);
867
868 /* mov [ss:rcx + ActualCtx.aGRegs[X86_GREG_xDX]], rdx */
869 *pbDst++ = 0x36;
870#ifdef RT_ARCH_AMD64
871 *pbDst++ = 0x48;
872#endif
873 *pbDst++ = 0x89;
874 *pbDst++ = 0x51;
875 *pbDst++ = RT_OFFSETOF(CIDETCPUCTX, aGRegs[X86_GREG_xDX]);
876 Assert(RT_OFFSETOF(CIDETCPUCTX, aGRegs[X86_GREG_xDX]) < 0x7f);
877
878 /* mov [ss:rcx + ActualCtx.aSRegs[X86_GREG_DS]], ds */
879 *pbDst++ = 0x36;
880 *pbDst++ = 0x8c;
881 *pbDst++ = 0x99;
882 *(uint32_t *)pbDst = RT_OFFSETOF(CIDETCPUCTX, aSRegs[X86_SREG_DS]);
883 pbDst += sizeof(uint32_t);
884
885 /* mov edx, 0XXYYh */
886 *pbDst++ = 0xba;
887 *(uint32_t *)pbDst = pThisApp->Core.InTemplateCtx.aSRegs[X86_SREG_DS];
888 pbDst += sizeof(uint32_t);
889
890 /* mov ds, dx */
891 *pbDst++ = 0x8e;
892 *pbDst++ = 0xda;
893
894 /* mov xDX, &pThisApp->ExecuteCtx */
895#ifdef RT_ARCH_AMD64
896 *pbDst++ = 0x48;
897#endif
898 *pbDst++ = 0xba;
899 *(uintptr_t *)pbDst = (uintptr_t)&pThisApp->ExecuteCtx;
900 pbDst += sizeof(uintptr_t);
901
902#ifdef RT_ARCH_AMD64
903 /* jmp [cs:$ wrt rip] */
904 *pbDst++ = 0xff;
905 *pbDst++ = 0x25;
906 *(uint32_t *)pbDst = 0;
907 pbDst += sizeof(uint32_t);
908#else
909 /* jmp NAME(CidetAppSaveAndRestoreCtx) */
910 *pbDst++ = 0xb9;
911#endif
912 *(uintptr_t *)pbDst = (uintptr_t)CidetAppSaveAndRestoreCtx;
913 pbDst += sizeof(uintptr_t);
914
915 /* int3 */
916 *pbDst++ = 0xcc;
917 }
918 else
919 {
920 /*
921 * Tricky stack, so just make it raise #UD after a successful run.
922 */
923 *pbDst++ = 0xf0; /* lock prefix */
924 //*pbDst++ = 0xcc; /* lock prefix */
925 memset(pbDst, 0xcc, 15); /* int3 */
926 pbDst += 15;
927 }
928
929 AssertMsg(pbDst == &pAppBuf->pbNormal[pBuf->offActive + pBuf->cb + pBuf->cbEpilogue],
930 ("cbEpilogue=%#x, actual %#x\n", pBuf->cbEpilogue, pbDst - &pAppBuf->pbNormal[pBuf->offActive + pBuf->cb]));
931
932 /*
933 * Arm the buffer.
934 */
935 return CidetAppArmBuf(pThisApp, pAppBuf);
936}
937
938
939/**
940 * @interface_method_impl{CIDETCORE::pfnExecute}
941 */
942static DECLCALLBACK(bool) CidetAppCbExecute(PCIDETCORE pThis)
943{
944#if defined(RT_OS_WINDOWS) || defined(RT_OS_DARWIN)
945 /* Skip tricky stack because windows cannot dispatch exception if RSP/ESP is bad. */
946 if (pThis->InCtx.fTrickyStack)
947 return false;
948#endif
949
950 g_pExecutingThis = (PCIDETAPP)pThis;
951#ifdef RT_OS_WINDOWS
952 __try
953 {
954 CidetAppExecute(&((PCIDETAPP)pThis)->ExecuteCtx, &pThis->InCtx);
955 }
956 __except (CidetAppXcptFilter(GetExceptionInformation()))
957 {
958 /* Won't end up here... */
959 }
960 g_pExecutingThis = NULL;
961#else
962 CidetAppExecute(&((PCIDETAPP)pThis)->ExecuteCtx, &pThis->InCtx);
963 if (g_pExecutingThis)
964 g_pExecutingThis = NULL;
965 else
966 {
967 RTTESTI_CHECK_RC(sigprocmask(SIG_SETMASK, &g_ProcSigMask, NULL), 0);
968 RTTESTI_CHECK_RC(sigaltstack(&g_AltStack, NULL), 0);
969 }
970#endif
971
972 return true;
973}
974
975
976
977
978/*
979 *
980 *
981 * CIDET Application.
982 * CIDET Application.
983 * CIDET Application.
984 *
985 *
986 */
987
988
989/**
990 * @interface_method_impl{CIDETCORE::pfnSetupBuf}
991 */
992static DECLCALLBACK(void) CidetAppCbFailureV(PCIDETCORE pThis, const char *pszMsg, va_list va)
993{
994 RTTestIFailedV(pszMsg, va);
995}
996
997
998static int cidetAppAllocateAndConfigureBuffers(PCIDETAPP pThis)
999{
1000 /*
1001 * Code buffers.
1002 */
1003 for (uint32_t i = 0; i < RT_ELEMENTS(pThis->aCodeBuffers); i++)
1004 {
1005 int rc = cidetAppAllocateAndConfigureOneBuffer(pThis, &pThis->aCodeBuffers[i], i, true /*fCode*/,
1006 g_aCodeBufCfgs[i].fFlags);
1007 if (RT_FAILURE(rc))
1008 return rc;
1009 }
1010
1011 /*
1012 * Data buffers.
1013 */
1014 for (uint32_t i = 0; i < RT_ELEMENTS(pThis->aDataBuffers); i++)
1015 {
1016 int rc = cidetAppAllocateAndConfigureOneBuffer(pThis, &pThis->aDataBuffers[i], i, false /*fCode*/,
1017 g_aDataBufCfgs[i].fFlags);
1018 if (RT_FAILURE(rc))
1019 return rc;
1020 }
1021
1022 /*
1023 * Stack.
1024 */
1025 pThis->cbStack = _32K;
1026 pThis->pbStackLow = (uint8_t *)RTMemPageAlloc(pThis->cbStack);
1027 if (!pThis->pbStackLow)
1028 {
1029 RTTestIFailed("Failed to allocate %u bytes for stack\n", pThis->cbStack);
1030 return false;
1031 }
1032 pThis->pbStackEnd = pThis->pbStackLow + pThis->cbStack;
1033
1034 return true;
1035}
1036
1037
1038static int CidetAppCreate(PPCIDETAPP ppThis)
1039{
1040 *ppThis = NULL;
1041
1042 PCIDETAPP pThis = (PCIDETAPP)RTMemAlloc(sizeof(*pThis));
1043 if (!pThis)
1044 return RTTestIFailedRc(VERR_NO_MEMORY, "Error allocating %zu bytes.", sizeof(*pThis));
1045
1046 /* Create a random source. */
1047 RTRAND hRand;
1048 int rc = RTRandAdvCreateParkMiller(&hRand);
1049 if (RT_SUCCESS(rc))
1050 {
1051 uint64_t uSeed = ASMReadTSC();
1052 rc = RTRandAdvSeed(hRand, uSeed);
1053 if (RT_SUCCESS(rc))
1054 RTTestIPrintf(RTTESTLVL_ALWAYS, "Random seed %#llx\n", uSeed);
1055
1056 /* Initialize the CIDET structure. */
1057 rc = CidetCoreInit(&pThis->Core, hRand);
1058 if (RT_SUCCESS(rc))
1059 {
1060 pThis->Core.pfnReInitDataBuf = CidetAppCbReInitDataBuf;
1061 pThis->Core.pfnSetupDataBuf = CidetAppCbSetupDataBuf;
1062 pThis->Core.pfnIsBufEqual = CidetAppCbIsBufEqual;
1063 pThis->Core.pfnReInitCodeBuf = CidetAppCbReInitCodeBuf;
1064 pThis->Core.pfnSetupCodeBuf = CidetAppCbSetupCodeBuf;
1065 pThis->Core.pfnExecute = CidetAppCbExecute;
1066 pThis->Core.pfnFailure = CidetAppCbFailureV;
1067
1068 pThis->Core.paCodeBufConfigs = g_aCodeBufCfgs;
1069 pThis->Core.cCodeBufConfigs = CIDETAPP_CODE_BUF_COUNT;
1070 pThis->Core.paDataBufConfigs = g_aDataBufCfgs;
1071 pThis->Core.cDataBufConfigs = CIDETAPP_DATA_BUF_COUNT;
1072
1073 rc = cidetAppAllocateAndConfigureBuffers(pThis);
1074 if (RT_SUCCESS(rc))
1075 {
1076 rc = CidetCoreSetTargetMode(&pThis->Core, ARCH_BITS == 32 ? CIDETMODE_PP_32 : CIDETMODE_LM_64);
1077 if (RT_SUCCESS(rc))
1078 {
1079 pThis->Core.InTemplateCtx.aSRegs[X86_SREG_CS] = ASMGetCS();
1080 pThis->Core.InTemplateCtx.aSRegs[X86_SREG_DS] = ASMGetDS();
1081 pThis->Core.InTemplateCtx.aSRegs[X86_SREG_ES] = ASMGetES();
1082 pThis->Core.InTemplateCtx.aSRegs[X86_SREG_FS] = ASMGetFS();
1083 pThis->Core.InTemplateCtx.aSRegs[X86_SREG_GS] = ASMGetGS();
1084 pThis->Core.InTemplateCtx.aSRegs[X86_SREG_SS] = ASMGetSS();
1085 pThis->Core.InTemplateCtx.aGRegs[X86_GREG_xSP] = (uintptr_t)pThis->pbStackEnd - 64;
1086
1087 pThis->Core.fTestCfg |= CIDET_TESTCFG_SEG_PRF_CS;
1088 pThis->Core.fTestCfg |= CIDET_TESTCFG_SEG_PRF_DS;
1089 pThis->Core.fTestCfg |= CIDET_TESTCFG_SEG_PRF_ES;
1090#if !defined(RT_OS_WINDOWS)
1091 pThis->Core.fTestCfg |= CIDET_TESTCFG_SEG_PRF_FS;
1092#endif
1093#if !defined(CIDET_LEAVE_GS_ALONE)
1094 pThis->Core.fTestCfg |= CIDET_TESTCFG_SEG_PRF_GS;
1095#endif
1096
1097 *ppThis = pThis;
1098 return VINF_SUCCESS;
1099 }
1100 rc = RTTestIFailedRc(rc, "Error setting target mode: %Rrc", rc);
1101 }
1102 CidetCoreDelete(&pThis->Core);
1103 }
1104 else
1105 {
1106 rc = RTTestIFailedRc(rc, "CidetCoreInit failed: %Rrc", rc);
1107 RTRandAdvDestroy(hRand);
1108 }
1109 }
1110 else
1111 rc = RTTestIFailedRc(rc, "RTRandAdvCreate failed: %Rrc", rc);
1112 RTMemFree(pThis);
1113 return rc;
1114}
1115
1116
1117static void CidetAppDestroy(PCIDETAPP pThis)
1118{
1119 CidetCoreDelete(&pThis->Core);
1120
1121 for (uint32_t i = 0; i < RT_ELEMENTS(pThis->aCodeBuffers); i++)
1122 CidetAppDeleteBuffer(&pThis->aCodeBuffers[i]);
1123 for (uint32_t i = 0; i < RT_ELEMENTS(pThis->aDataBuffers); i++)
1124 CidetAppDeleteBuffer(&pThis->aDataBuffers[i]);
1125 RTMemPageFree(pThis->pbStackLow, pThis->cbStack);
1126
1127 RTMemFree(pThis);
1128}
1129
1130
1131static void CidetAppTestBunch(PCIDETAPP pThis, PCCIDETINSTR paInstructions, uint32_t cInstructions, const char *pszBunchName)
1132{
1133 for (uint32_t iInstr = 0; iInstr < cInstructions; iInstr++)
1134 {
1135 RTTestSubF(g_hTest, "%s - %s", pszBunchName, paInstructions[iInstr].pszMnemonic);
1136 CidetCoreTestInstruction(&pThis->Core, &paInstructions[iInstr]);
1137 }
1138}
1139
1140
1141int main(int argc, char **argv)
1142{
1143 /*
1144 * Initialize the runtime.
1145 */
1146 RTEXITCODE rcExit = RTTestInitExAndCreate(argc, &argv, 0, "cidet-app", &g_hTest);
1147 if (rcExit != RTEXITCODE_SUCCESS)
1148 return rcExit;
1149
1150 /*
1151 * Parse arguments.
1152 */
1153 static const RTGETOPTDEF s_aOptions[] =
1154 {
1155 { "--noop", 'n', RTGETOPT_REQ_NOTHING },
1156 };
1157
1158 int chOpt;
1159 RTGETOPTUNION ValueUnion;
1160 RTGETOPTSTATE GetState;
1161 RTGetOptInit(&GetState, argc, argv, s_aOptions, RT_ELEMENTS(s_aOptions), 1, 0);
1162 while ((chOpt = RTGetOpt(&GetState, &ValueUnion)))
1163 {
1164 switch (chOpt)
1165 {
1166 case 'n':
1167 break;
1168
1169 case 'h':
1170 RTPrintf("usage: %s\n", argv[0]);
1171 return RTEXITCODE_SUCCESS;
1172
1173 case 'V':
1174 RTPrintf("%sr%d\n", RTBldCfgVersion(), RTBldCfgRevision());
1175 return RTEXITCODE_SUCCESS;
1176
1177 default:
1178 return RTGetOptPrintError(chOpt, &ValueUnion);
1179 }
1180 }
1181
1182#ifdef USE_SIGNALS
1183 /*
1184 * Set up signal handlers with alternate stack.
1185 */
1186 /* Get the default signal mask. */
1187 RTTESTI_CHECK_RC_RET(sigprocmask(SIG_BLOCK, NULL, &g_ProcSigMask), 0, RTEXITCODE_FAILURE);
1188
1189 /* Alternative stack so we can play with esp/rsp. */
1190 RT_ZERO(g_AltStack);
1191 g_AltStack.ss_flags = 0;
1192# ifdef SIGSTKSZ
1193 g_AltStack.ss_size = RT_MAX(SIGSTKSZ, _128K);
1194# else
1195 g_AltStack.ss_size = _128K;
1196# endif
1197 g_AltStack.ss_sp = RTMemPageAlloc(g_AltStack.ss_size);
1198 RTTESTI_CHECK_RET(g_AltStack.ss_sp != NULL, RTEXITCODE_FAILURE);
1199 RTTESTI_CHECK_RC_RET(sigaltstack(&g_AltStack, NULL), 0, RTEXITCODE_FAILURE);
1200
1201 /* Default signal action config. */
1202 struct sigaction Act;
1203 RT_ZERO(Act);
1204 Act.sa_sigaction = CidetAppSigHandler;
1205 Act.sa_flags = SA_SIGINFO | SA_ONSTACK;
1206 sigfillset(&Act.sa_mask);
1207
1208 /* Hook the signals we might need. */
1209 sigaction(SIGILL, &Act, NULL);
1210 sigaction(SIGTRAP, &Act, NULL);
1211# ifdef SIGEMT
1212 sigaction(SIGEMT, &Act, NULL);
1213# endif
1214 sigaction(SIGFPE, &Act, NULL);
1215 sigaction(SIGBUS, &Act, NULL);
1216 sigaction(SIGSEGV, &Act, NULL);
1217
1218#elif defined(RT_OS_WINDOWS)
1219 /*
1220 * Register vectored exception handler and override the default unhandled
1221 * exception filter, just to be on the safe side...
1222 */
1223 RTTESTI_CHECK(AddVectoredExceptionHandler(1 /* first */, CidetAppVectoredXcptHandler) != NULL);
1224 SetUnhandledExceptionFilter(CidetAppUnhandledXcptFilter);
1225#endif
1226
1227 /*
1228 * Do the work.
1229 */
1230 RTTestBanner(g_hTest);
1231
1232 PCIDETAPP pThis;
1233 int rc = CidetAppCreate(&pThis);
1234 if (RT_SUCCESS(rc))
1235 {
1236 CidetAppTestBunch(pThis, g_aCidetInstructions1, g_cCidetInstructions1, "First Bunch");
1237
1238 CidetAppDestroy(pThis);
1239 }
1240
1241 return RTTestSummaryAndDestroy(g_hTest);
1242}
1243
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette