VirtualBox

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

Last change on this file since 69300 was 69111, checked in by vboxsync, 7 years ago

(C) year

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 46.7 KB
Line 
1/* $Id: cidet-app.cpp 69111 2017-10-17 14:26:02Z vboxsync $ */
2/** @file
3 * CPU Instruction Decoding & Execution Tests - Ring-3 Driver Application.
4 */
5
6/*
7 * Copyright (C) 2014-2017 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 <iprt/win/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)) || defined(DOXYGEN_RUNNING)
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 RT_NOREF_PV(pThis);
569 static uint8_t const s_afBufProtToDefaultMemProt[] =
570 {
571 /* [0] = */ RTMEM_PROT_NONE,
572 /* [1] = */ RTMEM_PROT_READ | RTMEM_PROT_WRITE | RTMEM_PROT_EXEC,
573 /* [2] = */ RTMEM_PROT_READ | RTMEM_PROT_WRITE,
574 /* [3] = */ RTMEM_PROT_READ | RTMEM_PROT_EXEC,
575 /* [4] = */ RTMEM_PROT_READ,
576 /* [5] = */ RTMEM_PROT_READ | RTMEM_PROT_WRITE | RTMEM_PROT_EXEC,
577 /* [6] = */ RTMEM_PROT_READ | RTMEM_PROT_WRITE | RTMEM_PROT_EXEC,
578 /* [7] = */ RTMEM_PROT_READ | RTMEM_PROT_WRITE | RTMEM_PROT_EXEC,
579 /* [8] = */ RTMEM_PROT_NONE,
580 /* [9] = */ RTMEM_PROT_NONE,
581 /* [10] = */ RTMEM_PROT_NONE,
582 /* [11] = */ RTMEM_PROT_NONE,
583 /* [12] = */ RTMEM_PROT_NONE,
584 /* [13] = */ RTMEM_PROT_NONE,
585 /* [14] = */ RTMEM_PROT_NONE,
586 /* [15] = */ RTMEM_PROT_NONE,
587 };
588 static uint8_t const s_afBufProtToLastPageMemProt[] =
589 {
590 /* [0] = */ RTMEM_PROT_NONE,
591 /* [1] = */ RTMEM_PROT_READ | RTMEM_PROT_WRITE | RTMEM_PROT_EXEC,
592 /* [2] = */ RTMEM_PROT_READ | RTMEM_PROT_WRITE,
593 /* [3] = */ RTMEM_PROT_READ | RTMEM_PROT_EXEC,
594 /* [4] = */ RTMEM_PROT_READ,
595 /* [5] = */ RTMEM_PROT_NONE,
596 /* [6] = */ RTMEM_PROT_READ | RTMEM_PROT_WRITE,
597 /* [7] = */ RTMEM_PROT_READ,
598 /* [8] = */ RTMEM_PROT_NONE,
599 /* [9] = */ RTMEM_PROT_NONE,
600 /* [10] = */ RTMEM_PROT_NONE,
601 /* [11] = */ RTMEM_PROT_NONE,
602 /* [12] = */ RTMEM_PROT_NONE,
603 /* [13] = */ RTMEM_PROT_NONE,
604 /* [14] = */ RTMEM_PROT_NONE,
605 /* [15] = */ RTMEM_PROT_NONE,
606 };
607
608 int rc;
609 Assert(CIDETBUF_IS_CODE(fFlags) == fIsCode);
610 pBuf->fIsCode = fIsCode;
611 pBuf->idxCfg = idxBuf;
612 pBuf->fUsingNormal = true;
613 pBuf->fDefaultProt = s_afBufProtToDefaultMemProt[fFlags & CIDETBUF_PROT_MASK];
614 pBuf->fLastPageProt = s_afBufProtToLastPageMemProt[fFlags & CIDETBUF_PROT_MASK];
615 if (pBuf->fDefaultProt != RTMEM_PROT_NONE)
616 {
617 /*
618 * Allocate a 3 page buffer plus two fence pages.
619 */
620 pBuf->cb = fIsCode ? CIDET_CODE_BUF_SIZE : CIDET_DATA_BUF_SIZE;
621 pBuf->pbNormal = (uint8_t *)RTMemPageAlloc(PAGE_SIZE + pBuf->cb + PAGE_SIZE);
622 if (pBuf->pbNormal)
623 {
624 memset(pBuf->pbNormal, 0x55, PAGE_SIZE);
625 memset(pBuf->pbNormal + PAGE_SIZE, 0xcc, pBuf->cb);
626 memset(pBuf->pbNormal + PAGE_SIZE + pBuf->cb, 0x77, PAGE_SIZE);
627
628 /* Set up fence pages. */
629 rc = RTMemProtect(pBuf->pbNormal, PAGE_SIZE, RTMEM_PROT_NONE); /* fence */
630 if (RT_SUCCESS(rc))
631 rc = RTMemProtect(pBuf->pbNormal + PAGE_SIZE + pBuf->cb, PAGE_SIZE, RTMEM_PROT_NONE); /* fence */
632 pBuf->pbNormal += PAGE_SIZE;
633
634 /* Default protection + read + write. */
635 if (RT_SUCCESS(rc))
636 rc = RTMemProtect(pBuf->pbNormal, pBuf->cb, pBuf->fDefaultProt | RTMEM_PROT_READ | RTMEM_PROT_WRITE);
637
638 /*
639 * Allocate a low memory buffer or LDT if necessary.
640 */
641 if ( RT_SUCCESS(rc)
642 && (uintptr_t)pBuf->pbNormal + pBuf->cb > RT_BIT_64(sizeof(uintptr_t) / 2 * 8))
643 {
644 /** @todo Buffers for the other addressing mode. */
645 pBuf->pbLow = NULL;
646 }
647 else
648 pBuf->pbLow = pBuf->pbNormal;
649 if (RT_SUCCESS(rc))
650 return VINF_SUCCESS;
651
652 }
653 else
654 rc = RTTestIFailedRc(VERR_NO_PAGE_MEMORY, "Error allocating three pages.");
655 }
656 else
657 rc = RTTestIFailedRc(VERR_NO_PAGE_MEMORY, "Unsupported buffer config: fFlags=%#x, idxBuf=%u", fFlags, idxBuf);
658 return rc;
659}
660
661
662static void CidetAppDeleteBuffer(PCIDETAPPBUF pBuf)
663{
664 RTMemProtect(pBuf->pbNormal - PAGE_SIZE, PAGE_SIZE + pBuf->cb + PAGE_SIZE, RTMEM_PROT_READ | RTMEM_PROT_WRITE);
665 RTMemPageFree(pBuf->pbNormal - PAGE_SIZE, PAGE_SIZE + pBuf->cb + PAGE_SIZE);
666 if (pBuf->pbLow != pBuf->pbNormal && pBuf->pbLow)
667 {
668 RTMemProtect(pBuf->pbLow, pBuf->cb, RTMEM_PROT_READ | RTMEM_PROT_WRITE);
669 RTMemFreeEx(pBuf->pbLow, pBuf->cb);
670 }
671}
672
673
674static bool CidetAppArmBuf(PCIDETAPP pThis, PCIDETAPPBUF pAppBuf)
675{
676 RT_NOREF_PV(pThis);
677 uint8_t *pbUsingBuf = (pAppBuf->fUsingNormal ? pAppBuf->pbNormal : pAppBuf->pbLow);
678 if (pAppBuf->fLastPageProt == pAppBuf->fDefaultProt)
679 {
680 if ((pAppBuf->fDefaultProt & (RTMEM_PROT_READ | RTMEM_PROT_WRITE)) != (RTMEM_PROT_READ | RTMEM_PROT_WRITE))
681 RTTESTI_CHECK_RC_RET(RTMemProtect(pbUsingBuf, pAppBuf->cb, pAppBuf->fDefaultProt), VINF_SUCCESS, false);
682 }
683 else
684 {
685 if ((pAppBuf->fDefaultProt & (RTMEM_PROT_READ | RTMEM_PROT_WRITE)) != (RTMEM_PROT_READ | RTMEM_PROT_WRITE))
686 RTTESTI_CHECK_RC_RET(RTMemProtect(pbUsingBuf, pAppBuf->cb - PAGE_SIZE, pAppBuf->fDefaultProt), VINF_SUCCESS, false);
687 RTTESTI_CHECK_RC_RET(RTMemProtect(pbUsingBuf + pAppBuf->cb - PAGE_SIZE, PAGE_SIZE, pAppBuf->fLastPageProt),
688 VINF_SUCCESS, false);
689 }
690 pAppBuf->fArmed = true;
691 return true;
692}
693
694
695static bool CidetAppDearmBuf(PCIDETAPP pThis, PCIDETAPPBUF pAppBuf)
696{
697 RT_NOREF_PV(pThis);
698 uint8_t *pbUsingBuf = (pAppBuf->fUsingNormal ? pAppBuf->pbNormal : pAppBuf->pbLow);
699 int rc = RTMemProtect(pbUsingBuf, pAppBuf->cb, pAppBuf->fDefaultProt | RTMEM_PROT_READ | RTMEM_PROT_WRITE);
700 if (RT_FAILURE(rc))
701 {
702 RTTestIFailed("RTMemProtect failed on %s buf #%u: %Rrc", pAppBuf->fIsCode ? "code" : "data", pAppBuf->idxCfg, rc);
703 return false;
704 }
705 pAppBuf->fArmed = false;
706 return true;
707}
708
709
710/**
711 * @interface_method_impl{CIDETCORE,pfnReInitDataBuf}
712 */
713static DECLCALLBACK(bool) CidetAppCbReInitDataBuf(PCIDETCORE pThis, PCIDETBUF pBuf)
714{
715 PCIDETAPP pThisApp = (PCIDETAPP)pThis;
716 PCIDETAPPBUF pAppBuf = &pThisApp->aDataBuffers[pBuf->idxCfg];
717 Assert(CIDETBUF_IS_DATA(pBuf->pCfg->fFlags));
718
719 /*
720 * De-arm the buffer.
721 */
722 if (pAppBuf->fArmed)
723 if (RT_UNLIKELY(!CidetAppDearmBuf(pThisApp, pAppBuf)))
724 return false;
725
726 /*
727 * Check the allocation requirements.
728 */
729 if (RT_UNLIKELY((size_t)pBuf->off + pBuf->cb > pAppBuf->cb))
730 {
731 RTTestIFailed("Buffer too small; off=%#x cb=%#x pAppBuf->cb=%#x (%s)",
732 pBuf->off, pBuf->cb, pAppBuf->cb, pBuf->pCfg->pszName);
733 return false;
734 }
735
736 /*
737 * Do we need to use the low buffer? Check that we have one, if we need it.
738 */
739 bool fUseNormal = pThis->cbAddrMode == ARCH_BITS / 8;
740 if (!fUseNormal && !pAppBuf->pbLow)
741 return false;
742
743 /*
744 * Update the state.
745 */
746 pAppBuf->fUsingNormal = fUseNormal;
747
748 pBuf->offActive = pBuf->off;
749 pBuf->cbActive = pBuf->cb;
750 pBuf->cbPrologue = 0;
751 pBuf->cbEpilogue = 0;
752 pBuf->uSeg = UINT32_MAX;
753 pBuf->cbActiveSegLimit = UINT64_MAX;
754 pBuf->uSegBase = 0;
755 if (fUseNormal)
756 pBuf->uEffBufAddr = (uintptr_t)pAppBuf->pbNormal;
757 else
758 pBuf->uEffBufAddr = (uintptr_t)pAppBuf->pbLow;
759
760 return true;
761}
762
763
764/**
765 * @interface_method_impl{CIDETCORE,pfnSetupDataBuf}
766 */
767static DECLCALLBACK(bool) CidetAppCbSetupDataBuf(PCIDETCORE pThis, PCIDETBUF pBuf, void const *pvSrc)
768{
769 PCIDETAPP pThisApp = (PCIDETAPP)pThis;
770 PCIDETAPPBUF pAppBuf = &pThisApp->aDataBuffers[pBuf->idxCfg];
771 Assert(CIDETBUF_IS_DATA(pBuf->pCfg->fFlags));
772 Assert(!pAppBuf->fArmed);
773
774
775 /*
776 * Copy over the data.
777 */
778 uint8_t *pbUsingBuf = (pAppBuf->fUsingNormal ? pAppBuf->pbNormal : pAppBuf->pbLow);
779 memcpy(pbUsingBuf + pBuf->offActive, pvSrc, pBuf->cbActive);
780
781 /*
782 * Arm the buffer.
783 */
784 return CidetAppArmBuf(pThisApp, pAppBuf);
785}
786
787
788/**
789 * @interface_method_impl{CIDETCORE,pfnIsBufEqual}
790 */
791static DECLCALLBACK(bool) CidetAppCbIsBufEqual(PCIDETCORE pThis, struct CIDETBUF *pBuf, void const *pvExpected)
792{
793 PCIDETAPP pThisApp = (PCIDETAPP)pThis;
794 PCIDETAPPBUF pAppBuf = CIDETBUF_IS_CODE(pBuf->pCfg->fFlags)
795 ? &pThisApp->aCodeBuffers[pBuf->idxCfg]
796 : &pThisApp->aDataBuffers[pBuf->idxCfg];
797
798 /*
799 * Disarm the buffer if we can't read it all.
800 */
801 if ( pAppBuf->fArmed
802 && ( !(pAppBuf->fLastPageProt & RTMEM_PROT_READ)
803 || !(pAppBuf->fDefaultProt & RTMEM_PROT_READ)) )
804 if (RT_UNLIKELY(!CidetAppDearmBuf(pThisApp, pAppBuf)))
805 return false;
806
807 /*
808 * Do the comparing.
809 */
810 uint8_t *pbUsingBuf = (pAppBuf->fUsingNormal ? pAppBuf->pbNormal : pAppBuf->pbLow);
811 if (memcmp(pbUsingBuf + pBuf->offActive, pvExpected, pBuf->cbActive) != 0)
812 {
813 /** @todo RTMEM_PROT_NONE may kill content on some hosts... */
814 return false;
815 }
816
817 /** @todo check padding. */
818 return true;
819}
820
821
822/*
823 *
824 * Code buffer, prologue, epilogue, and execution.
825 * Code buffer, prologue, epilogue, and execution.
826 * Code buffer, prologue, epilogue, and execution.
827 *
828 *
829 */
830
831
832/**
833 * @interface_method_impl{CIDETCORE,pfnReInitCodeBuf}
834 */
835static DECLCALLBACK(bool) CidetAppCbReInitCodeBuf(PCIDETCORE pThis, PCIDETBUF pBuf)
836{
837 PCIDETAPP pThisApp = (PCIDETAPP)pThis;
838 PCIDETAPPBUF pAppBuf = &pThisApp->aCodeBuffers[pBuf->idxCfg];
839 Assert(CIDETBUF_IS_CODE(pBuf->pCfg->fFlags));
840 Assert(pAppBuf->fUsingNormal);
841
842 /*
843 * De-arm the buffer.
844 */
845 if (pAppBuf->fArmed)
846 if (RT_UNLIKELY(!CidetAppDearmBuf(pThisApp, pAppBuf)))
847 return false;
848
849 /*
850 * Determin the prologue and epilogue sizes.
851 */
852 uint16_t cbPrologue = 0;
853 uint16_t cbEpilogue = ARCH_BITS == 64 ? 0x56 : 0x4e;
854 if (pThis->InCtx.fTrickyStack)
855 cbEpilogue = 16;
856
857 /*
858 * Check the allocation requirements.
859 */
860 if (RT_UNLIKELY( cbPrologue > pBuf->off
861 || (size_t)pBuf->off + pBuf->cb + cbEpilogue > pAppBuf->cb))
862 {
863 RTTestIFailed("Buffer too small; off=%#x cb=%#x cbPro=%#x cbEpi=%#x pAppBuf->cb=%#x (%s)",
864 pBuf->off, pBuf->cb, cbPrologue, cbEpilogue, pAppBuf->cb, pBuf->pCfg->pszName);
865 return false;
866 }
867
868 /*
869 * Update the state.
870 */
871 pAppBuf->fUsingNormal = true;
872
873 pBuf->cbActive = pBuf->cb;
874 pBuf->offActive = pBuf->off;
875 pBuf->cbPrologue = cbPrologue;
876 pBuf->cbEpilogue = cbEpilogue;
877 pBuf->uSeg = UINT32_MAX;
878 pBuf->cbActiveSegLimit = UINT64_MAX;
879 pBuf->uSegBase = 0;
880 pBuf->uEffBufAddr = (uintptr_t)pAppBuf->pbNormal;
881
882 return true;
883}
884
885
886/**
887 * @interface_method_impl{CIDETCORE,pfnSetupCodeBuf}
888 */
889static DECLCALLBACK(bool) CidetAppCbSetupCodeBuf(PCIDETCORE pThis, PCIDETBUF pBuf, void const *pvInstr)
890{
891 PCIDETAPP pThisApp = (PCIDETAPP)pThis;
892 PCIDETAPPBUF pAppBuf =&pThisApp->aCodeBuffers[pBuf->idxCfg];
893 Assert(CIDETBUF_IS_CODE(pBuf->pCfg->fFlags));
894 Assert(pAppBuf->fUsingNormal);
895 Assert(!pAppBuf->fArmed);
896
897 /*
898 * Emit prologue code.
899 */
900 uint8_t *pbDst = pAppBuf->pbNormal + pBuf->offActive - pBuf->cbPrologue;
901
902 /*
903 * Copy over the code.
904 */
905 Assert(pbDst == &pAppBuf->pbNormal[pBuf->offActive]);
906 memcpy(pbDst, pvInstr, pBuf->cbActive);
907 pbDst += pBuf->cbActive;
908
909 /*
910 * Emit epilogue code.
911 */
912 if (!pThis->InCtx.fTrickyStack)
913 {
914 /*
915 * The stack is reasonably good, do minimal work.
916 *
917 * Note! Ideally, we would just fill in 16 int3s here and check that
918 * we hit the first right one. However, if we wish to run this
919 * code with IEM, we better skip unnecessary trips to ring-0.
920 */
921 uint8_t * const pbStartEpilogue = pbDst;
922
923 /* jmp $+6 */
924 *pbDst++ = 0xeb;
925 *pbDst++ = 0x06; /* This is a push es, so if the decoder is one off, we'll hit the int 3 below. */
926
927 /* Six int3s for trapping incorrectly decoded instructions. */
928 *pbDst++ = 0xcc;
929 *pbDst++ = 0xcc;
930 *pbDst++ = 0xcc;
931 *pbDst++ = 0xcc;
932 *pbDst++ = 0xcc;
933 *pbDst++ = 0xcc;
934
935 /* push rip / call $+0 */
936 *pbDst++ = 0xe8;
937 *pbDst++ = 0x00;
938 *pbDst++ = 0x00;
939 *pbDst++ = 0x00;
940 *pbDst++ = 0x00;
941 uint8_t offRipAdjust = (uint8_t)(uintptr_t)(pbStartEpilogue - pbDst);
942
943 /* push xCX */
944 *pbDst++ = 0x51;
945
946 /* mov xCX, [xSP + xCB] */
947 *pbDst++ = 0x48;
948 *pbDst++ = 0x8b;
949 *pbDst++ = 0x4c;
950 *pbDst++ = 0x24;
951 *pbDst++ = sizeof(uintptr_t);
952
953 /* lea xCX, [xCX - 24] */
954 *pbDst++ = 0x48;
955 *pbDst++ = 0x8d;
956 *pbDst++ = 0x49;
957 *pbDst++ = offRipAdjust;
958
959 /* mov xCX, [xSP + xCB] */
960 *pbDst++ = 0x48;
961 *pbDst++ = 0x89;
962 *pbDst++ = 0x4c;
963 *pbDst++ = 0x24;
964 *pbDst++ = sizeof(uintptr_t);
965
966 /* mov xCX, &pThis->ActualCtx */
967#ifdef RT_ARCH_AMD64
968 *pbDst++ = 0x48;
969#endif
970 *pbDst++ = 0xb9;
971 *(uintptr_t *)pbDst = (uintptr_t)&pThisApp->Core.ActualCtx;
972 pbDst += sizeof(uintptr_t);
973
974 /* pop [ss:rcx + ActualCtx.aGRegs[X86_GREG_xCX]] */
975 *pbDst++ = 0x36;
976 *pbDst++ = 0x8f;
977 *pbDst++ = 0x41;
978 *pbDst++ = RT_OFFSETOF(CIDETCPUCTX, aGRegs[X86_GREG_xCX]);
979 Assert(RT_OFFSETOF(CIDETCPUCTX, aGRegs[X86_GREG_xCX]) < 0x7f);
980
981 /* mov [ss:rcx + ActualCtx.aGRegs[X86_GREG_xDX]], rdx */
982 *pbDst++ = 0x36;
983#ifdef RT_ARCH_AMD64
984 *pbDst++ = 0x48;
985#endif
986 *pbDst++ = 0x89;
987 *pbDst++ = 0x51;
988 *pbDst++ = RT_OFFSETOF(CIDETCPUCTX, aGRegs[X86_GREG_xDX]);
989 Assert(RT_OFFSETOF(CIDETCPUCTX, aGRegs[X86_GREG_xDX]) < 0x7f);
990
991 /* mov [ss:rcx + ActualCtx.aSRegs[X86_GREG_DS]], ds */
992 *pbDst++ = 0x36;
993 *pbDst++ = 0x8c;
994 *pbDst++ = 0x99;
995 *(uint32_t *)pbDst = RT_OFFSETOF(CIDETCPUCTX, aSRegs[X86_SREG_DS]);
996 pbDst += sizeof(uint32_t);
997
998 /* mov edx, 0XXYYh */
999 *pbDst++ = 0xba;
1000 *(uint32_t *)pbDst = pThisApp->Core.InTemplateCtx.aSRegs[X86_SREG_DS];
1001 pbDst += sizeof(uint32_t);
1002
1003 /* mov ds, dx */
1004 *pbDst++ = 0x8e;
1005 *pbDst++ = 0xda;
1006
1007 /* mov xDX, &pThisApp->ExecuteCtx */
1008#ifdef RT_ARCH_AMD64
1009 *pbDst++ = 0x48;
1010#endif
1011 *pbDst++ = 0xba;
1012 *(uintptr_t *)pbDst = (uintptr_t)&pThisApp->ExecuteCtx;
1013 pbDst += sizeof(uintptr_t);
1014
1015#ifdef RT_ARCH_AMD64
1016 /* jmp [cs:$ wrt rip] */
1017 *pbDst++ = 0xff;
1018 *pbDst++ = 0x25;
1019 *(uint32_t *)pbDst = 0;
1020 pbDst += sizeof(uint32_t);
1021#else
1022 /* jmp NAME(CidetAppSaveAndRestoreCtx) */
1023 *pbDst++ = 0xb9;
1024#endif
1025 *(uintptr_t *)pbDst = (uintptr_t)CidetAppSaveAndRestoreCtx;
1026 pbDst += sizeof(uintptr_t);
1027
1028 /* int3 */
1029 *pbDst++ = 0xcc;
1030
1031 pThisApp->fUsingLockedInt3 = false;
1032
1033 }
1034 else
1035 {
1036 /*
1037 * Tricky stack, so just make it raise #UD after a successful run.
1038 */
1039 *pbDst++ = 0xf0; /* lock prefix */
1040 memset(pbDst, 0xcc, 15); /* int3 */
1041 pbDst += 15;
1042
1043 pThisApp->fUsingLockedInt3 = true;
1044 }
1045
1046 AssertMsg(pbDst == &pAppBuf->pbNormal[pBuf->offActive + pBuf->cb + pBuf->cbEpilogue],
1047 ("cbEpilogue=%#x, actual %#x\n", pBuf->cbEpilogue, pbDst - &pAppBuf->pbNormal[pBuf->offActive + pBuf->cb]));
1048
1049 /*
1050 * Arm the buffer.
1051 */
1052 return CidetAppArmBuf(pThisApp, pAppBuf);
1053}
1054
1055
1056/**
1057 * @interface_method_impl{CIDETCORE,pfnExecute}
1058 */
1059static DECLCALLBACK(bool) CidetAppCbExecute(PCIDETCORE pThis)
1060{
1061#if defined(RT_OS_WINDOWS) || defined(RT_OS_DARWIN)
1062 /* Skip tricky stack because windows cannot dispatch exception if RSP/ESP is bad. */
1063 if (pThis->InCtx.fTrickyStack)
1064 return false;
1065#endif
1066
1067 g_pExecutingThis = (PCIDETAPP)pThis;
1068#ifdef RT_OS_WINDOWS
1069 __try
1070 {
1071 CidetAppExecute(&((PCIDETAPP)pThis)->ExecuteCtx, &pThis->InCtx);
1072 }
1073 __except (CidetAppXcptFilter(GetExceptionInformation()))
1074 {
1075 /* Won't end up here... */
1076 }
1077 g_pExecutingThis = NULL;
1078#else
1079 CidetAppExecute(&((PCIDETAPP)pThis)->ExecuteCtx, &pThis->InCtx);
1080 if (g_pExecutingThis)
1081 g_pExecutingThis = NULL;
1082 else
1083 {
1084 RTTESTI_CHECK_RC(sigprocmask(SIG_SETMASK, &g_ProcSigMask, NULL), 0);
1085 RTTESTI_CHECK_RC(sigaltstack(&g_AltStack, NULL), 0);
1086 }
1087#endif
1088
1089 return true;
1090}
1091
1092
1093
1094
1095/*
1096 *
1097 *
1098 * CIDET Application.
1099 * CIDET Application.
1100 * CIDET Application.
1101 *
1102 *
1103 */
1104
1105
1106/**
1107 * @interface_method_impl{CIDETCORE,pfnFailure}
1108 */
1109static DECLCALLBACK(void) CidetAppCbFailureV(PCIDETCORE pThis, const char *pszFormat, va_list va)
1110{
1111 RT_NOREF_PV(pThis);
1112 RTTestIFailedV(pszFormat, va);
1113}
1114
1115
1116static int cidetAppAllocateAndConfigureBuffers(PCIDETAPP pThis)
1117{
1118 /*
1119 * Code buffers.
1120 */
1121 for (uint32_t i = 0; i < RT_ELEMENTS(pThis->aCodeBuffers); i++)
1122 {
1123 int rc = cidetAppAllocateAndConfigureOneBuffer(pThis, &pThis->aCodeBuffers[i], i, true /*fCode*/,
1124 g_aCodeBufCfgs[i].fFlags);
1125 if (RT_FAILURE(rc))
1126 return rc;
1127 }
1128
1129 /*
1130 * Data buffers.
1131 */
1132 for (uint32_t i = 0; i < RT_ELEMENTS(pThis->aDataBuffers); i++)
1133 {
1134 int rc = cidetAppAllocateAndConfigureOneBuffer(pThis, &pThis->aDataBuffers[i], i, false /*fCode*/,
1135 g_aDataBufCfgs[i].fFlags);
1136 if (RT_FAILURE(rc))
1137 return rc;
1138 }
1139
1140 /*
1141 * Stack.
1142 */
1143 pThis->cbStack = _32K;
1144 pThis->pbStackLow = (uint8_t *)RTMemPageAlloc(pThis->cbStack);
1145 if (!pThis->pbStackLow)
1146 {
1147 RTTestIFailed("Failed to allocate %u bytes for stack\n", pThis->cbStack);
1148 return false;
1149 }
1150 pThis->pbStackEnd = pThis->pbStackLow + pThis->cbStack;
1151
1152 return true;
1153}
1154
1155
1156static int CidetAppCreate(PPCIDETAPP ppThis)
1157{
1158 *ppThis = NULL;
1159
1160 PCIDETAPP pThis = (PCIDETAPP)RTMemAlloc(sizeof(*pThis));
1161 if (!pThis)
1162 return RTTestIFailedRc(VERR_NO_MEMORY, "Error allocating %zu bytes.", sizeof(*pThis));
1163
1164 /* Create a random source. */
1165 RTRAND hRand;
1166 int rc = RTRandAdvCreateParkMiller(&hRand);
1167 if (RT_SUCCESS(rc))
1168 {
1169 uint64_t uSeed = ASMReadTSC();
1170 rc = RTRandAdvSeed(hRand, uSeed);
1171 if (RT_SUCCESS(rc))
1172 RTTestIPrintf(RTTESTLVL_ALWAYS, "Random seed %#llx\n", uSeed);
1173
1174 /* Initialize the CIDET structure. */
1175 rc = CidetCoreInit(&pThis->Core, hRand);
1176 if (RT_SUCCESS(rc))
1177 {
1178 pThis->Core.pfnReInitDataBuf = CidetAppCbReInitDataBuf;
1179 pThis->Core.pfnSetupDataBuf = CidetAppCbSetupDataBuf;
1180 pThis->Core.pfnIsBufEqual = CidetAppCbIsBufEqual;
1181 pThis->Core.pfnReInitCodeBuf = CidetAppCbReInitCodeBuf;
1182 pThis->Core.pfnSetupCodeBuf = CidetAppCbSetupCodeBuf;
1183 pThis->Core.pfnExecute = CidetAppCbExecute;
1184 pThis->Core.pfnFailure = CidetAppCbFailureV;
1185
1186 pThis->Core.paCodeBufConfigs = g_aCodeBufCfgs;
1187 pThis->Core.cCodeBufConfigs = CIDETAPP_CODE_BUF_COUNT;
1188 pThis->Core.paDataBufConfigs = g_aDataBufCfgs;
1189 pThis->Core.cDataBufConfigs = CIDETAPP_DATA_BUF_COUNT;
1190
1191 rc = cidetAppAllocateAndConfigureBuffers(pThis);
1192 if (RT_SUCCESS(rc))
1193 {
1194 rc = CidetCoreSetTargetMode(&pThis->Core, ARCH_BITS == 32 ? CIDETMODE_PP_32 : CIDETMODE_LM_64);
1195 if (RT_SUCCESS(rc))
1196 {
1197 pThis->Core.InTemplateCtx.aSRegs[X86_SREG_CS] = ASMGetCS();
1198 pThis->Core.InTemplateCtx.aSRegs[X86_SREG_DS] = ASMGetDS();
1199 pThis->Core.InTemplateCtx.aSRegs[X86_SREG_ES] = ASMGetES();
1200 pThis->Core.InTemplateCtx.aSRegs[X86_SREG_FS] = ASMGetFS();
1201 pThis->Core.InTemplateCtx.aSRegs[X86_SREG_GS] = ASMGetGS();
1202 pThis->Core.InTemplateCtx.aSRegs[X86_SREG_SS] = ASMGetSS();
1203 pThis->Core.InTemplateCtx.aGRegs[X86_GREG_xSP] = (uintptr_t)pThis->pbStackEnd - 64;
1204
1205 pThis->Core.fTestCfg |= CIDET_TESTCFG_SEG_PRF_CS;
1206 pThis->Core.fTestCfg |= CIDET_TESTCFG_SEG_PRF_DS;
1207 pThis->Core.fTestCfg |= CIDET_TESTCFG_SEG_PRF_ES;
1208#if !defined(RT_OS_WINDOWS)
1209 pThis->Core.fTestCfg |= CIDET_TESTCFG_SEG_PRF_FS;
1210#endif
1211#if !defined(CIDET_LEAVE_GS_ALONE)
1212 pThis->Core.fTestCfg |= CIDET_TESTCFG_SEG_PRF_GS;
1213#endif
1214
1215 *ppThis = pThis;
1216 return VINF_SUCCESS;
1217 }
1218 rc = RTTestIFailedRc(rc, "Error setting target mode: %Rrc", rc);
1219 }
1220 CidetCoreDelete(&pThis->Core);
1221 }
1222 else
1223 {
1224 rc = RTTestIFailedRc(rc, "CidetCoreInit failed: %Rrc", rc);
1225 RTRandAdvDestroy(hRand);
1226 }
1227 }
1228 else
1229 rc = RTTestIFailedRc(rc, "RTRandAdvCreate failed: %Rrc", rc);
1230 RTMemFree(pThis);
1231 return rc;
1232}
1233
1234
1235static void CidetAppDestroy(PCIDETAPP pThis)
1236{
1237 CidetCoreDelete(&pThis->Core);
1238
1239 for (uint32_t i = 0; i < RT_ELEMENTS(pThis->aCodeBuffers); i++)
1240 CidetAppDeleteBuffer(&pThis->aCodeBuffers[i]);
1241 for (uint32_t i = 0; i < RT_ELEMENTS(pThis->aDataBuffers); i++)
1242 CidetAppDeleteBuffer(&pThis->aDataBuffers[i]);
1243 RTMemPageFree(pThis->pbStackLow, pThis->cbStack);
1244
1245 RTMemFree(pThis);
1246}
1247
1248
1249static void CidetAppTestBunch(PCIDETAPP pThis, PCCIDETINSTR paInstructions, uint32_t cInstructions, const char *pszBunchName)
1250{
1251 for (uint32_t iInstr = 0; iInstr < cInstructions; iInstr++)
1252 {
1253 RTTestSubF(g_hTest, "%s - %s", pszBunchName, paInstructions[iInstr].pszMnemonic);
1254 CidetCoreTestInstruction(&pThis->Core, &paInstructions[iInstr]);
1255 }
1256}
1257
1258
1259int main(int argc, char **argv)
1260{
1261 /*
1262 * Initialize the runtime.
1263 */
1264 RTEXITCODE rcExit = RTTestInitExAndCreate(argc, &argv, 0, "cidet-app", &g_hTest);
1265 if (rcExit != RTEXITCODE_SUCCESS)
1266 return rcExit;
1267
1268 /*
1269 * Parse arguments.
1270 */
1271 static const RTGETOPTDEF s_aOptions[] =
1272 {
1273 { "--noop", 'n', RTGETOPT_REQ_NOTHING },
1274 };
1275
1276 int chOpt;
1277 RTGETOPTUNION ValueUnion;
1278 RTGETOPTSTATE GetState;
1279 RTGetOptInit(&GetState, argc, argv, s_aOptions, RT_ELEMENTS(s_aOptions), 1, 0);
1280 while ((chOpt = RTGetOpt(&GetState, &ValueUnion)))
1281 {
1282 switch (chOpt)
1283 {
1284 case 'n':
1285 break;
1286
1287 case 'h':
1288 RTPrintf("usage: %s\n", argv[0]);
1289 return RTEXITCODE_SUCCESS;
1290
1291 case 'V':
1292 RTPrintf("%sr%d\n", RTBldCfgVersion(), RTBldCfgRevision());
1293 return RTEXITCODE_SUCCESS;
1294
1295 default:
1296 return RTGetOptPrintError(chOpt, &ValueUnion);
1297 }
1298 }
1299
1300#ifdef USE_SIGNALS
1301 /*
1302 * Set up signal handlers with alternate stack.
1303 */
1304 /* Get the default signal mask. */
1305 RTTESTI_CHECK_RC_RET(sigprocmask(SIG_BLOCK, NULL, &g_ProcSigMask), 0, RTEXITCODE_FAILURE);
1306
1307 /* Alternative stack so we can play with esp/rsp. */
1308 RT_ZERO(g_AltStack);
1309 g_AltStack.ss_flags = 0;
1310# ifdef SIGSTKSZ
1311 g_AltStack.ss_size = RT_MAX(SIGSTKSZ, _128K);
1312# else
1313 g_AltStack.ss_size = _128K;
1314# endif
1315#ifdef RT_OS_FREEBSD
1316 g_AltStack.ss_sp = (char *)RTMemPageAlloc(g_AltStack.ss_size);
1317#else
1318 g_AltStack.ss_sp = RTMemPageAlloc(g_AltStack.ss_size);
1319#endif
1320 RTTESTI_CHECK_RET(g_AltStack.ss_sp != NULL, RTEXITCODE_FAILURE);
1321 RTTESTI_CHECK_RC_RET(sigaltstack(&g_AltStack, NULL), 0, RTEXITCODE_FAILURE);
1322
1323 /* Default signal action config. */
1324 struct sigaction Act;
1325 RT_ZERO(Act);
1326 Act.sa_sigaction = CidetAppSigHandler;
1327 Act.sa_flags = SA_SIGINFO | SA_ONSTACK;
1328 sigfillset(&Act.sa_mask);
1329
1330 /* Hook the signals we might need. */
1331 sigaction(SIGILL, &Act, NULL);
1332 sigaction(SIGTRAP, &Act, NULL);
1333# ifdef SIGEMT
1334 sigaction(SIGEMT, &Act, NULL);
1335# endif
1336 sigaction(SIGFPE, &Act, NULL);
1337 sigaction(SIGBUS, &Act, NULL);
1338 sigaction(SIGSEGV, &Act, NULL);
1339
1340#elif defined(RT_OS_WINDOWS)
1341 /*
1342 * Register vectored exception handler and override the default unhandled
1343 * exception filter, just to be on the safe side...
1344 */
1345 RTTESTI_CHECK(AddVectoredExceptionHandler(1 /* first */, CidetAppVectoredXcptHandler) != NULL);
1346 SetUnhandledExceptionFilter(CidetAppUnhandledXcptFilter);
1347#endif
1348
1349 /*
1350 * Do the work.
1351 */
1352 RTTestBanner(g_hTest);
1353
1354 PCIDETAPP pThis;
1355 int rc = CidetAppCreate(&pThis);
1356 if (RT_SUCCESS(rc))
1357 {
1358 CidetAppTestBunch(pThis, g_aCidetInstructions1, g_cCidetInstructions1, "First Bunch");
1359
1360 CidetAppDestroy(pThis);
1361 }
1362
1363 return RTTestSummaryAndDestroy(g_hTest);
1364}
1365
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