VirtualBox

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

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

Assorted fixes for FreeBSD hosts, VBox compiles and runs again without further patches (tested on 10.1 amd64 )

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

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