Git conversion: Make reactos the root directory, move rosapps, rostests, wallpapers into modules, and delete rossubsys.

This commit is contained in:
Colin Finck 2017-10-03 07:45:34 +00:00
parent b94e2d8ca0
commit c2c66aff7d
24198 changed files with 0 additions and 37285 deletions

View file

@ -0,0 +1,81 @@
/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS Run-Time Library
* PURPOSE: Debug Routines
* FILE: lib/rtl/amd64/debug_asm.S
* PROGRAMER: Timo Kreuzer (timo.kreuzer@reactos.org)
*/
#include <asm.inc>
/* GLOBALS ****************************************************************/
PUBLIC DbgBreakPoint
PUBLIC DbgBreakPointWithStatus
PUBLIC DbgUserBreakPoint
PUBLIC DebugService
PUBLIC DebugService2
PUBLIC DbgBreakPointNoBugCheck
PUBLIC RtlpBreakWithStatusInstruction
/* FUNCTIONS ***************************************************************/
.code64
.PROC DbgBreakPointNoBugCheck
.endprolog
int 3
ret
.ENDP
DbgUserBreakPoint:
.PROC DbgBreakPoint
.endprolog
int 3
ret
.ENDP
.PROC DbgBreakPointWithStatus
.endprolog
mov eax, ecx
.ENDP
.PROC RtlpBreakWithStatusInstruction
.endprolog
int 3
ret
.ENDP
DebugService2:
ret
/* Call the interrupt */
// mov eax, [rbp+8]
// int 0x2D
// int 3
/******************************************************************************
* NTSTATUS NTAPI DebugService(
* IN ULONG Service, // <rcx> = [rsp + 8]
* IN PVOID Buffer, // <rdx> = [rsp + 16]
* IN ULONG Length, // <r8> = [rsp + 24]
* IN PVOID Argument1, // <r9> = [rsp + 32]
* IN PVOID Argument2); // [rsp + 40]
*/
DebugService:
/* Prepare registers for interrupt */
mov eax, ecx // Service
mov rcx, rdx // Buffer
mov edx, r8d // Length
mov r8, r9 // Argument1
mov r9, [rsp + 40] // Argument2
/* Call the Interrupt */
int HEX(2D)
int 3
/* Return */
ret
END

View file

@ -0,0 +1,103 @@
/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS Runtime Library (RTL)
* FILE: lib/rtl/amd64/except_asm.S
* PURPOSE: Exception support for AMD64
* PROGRAMMERS: Timo Kreuzer (timo.kreuzer@reactos.org)
*/
/* INCLUDES ******************************************************************/
#include <asm.inc>
#include <ksamd64.inc>
/* FUNCTIONS *****************************************************************/
.code64
/*
* VOID NTAPI
* RtlCaptureContext(
* PCONTEXT ContextRecord); <rcx>
*/
PUBLIC RtlCaptureContext
.PROC RtlCaptureContext
/* Push rflags */
pushfq
.ALLOCSTACK 8
.ENDPROLOG
/* Save the basic register context */
mov [rcx + CONTEXT_Rax], rax
mov [rcx + CONTEXT_Rcx], rcx
mov [rcx + CONTEXT_Rdx], rdx
/* Load rflags into rax */
mov rax, [rsp]
mov [rcx + CONTEXT_Rbx], rbx
mov [rcx + CONTEXT_Rsi], rsi
mov [rcx + CONTEXT_Rdi], rdi
/* Store rflags */
mov [rcx + CONTEXT_EFlags], rax
mov [rcx + CONTEXT_Rbp], rbp
mov [rcx + CONTEXT_R8], r8
mov [rcx + CONTEXT_R9], r9
/* Load former stack pointer in rax */
lea rax, [rsp + 16]
mov [rcx + CONTEXT_R10], r10
mov [rcx + CONTEXT_R11], r11
mov [rcx + CONTEXT_R12], r12
/* Store stack pointer */
mov [rcx + CONTEXT_Rsp], rax
mov [rcx + CONTEXT_R13], r13
mov [rcx + CONTEXT_R14], r14
mov [rcx + CONTEXT_R15], r15
/* Load return address in rax */
mov rax, [rsp + 8]
/* Safe segment selectors */
mov [rcx + CONTEXT_SegCs], cs
mov [rcx + CONTEXT_SegDs], ds
mov [rcx + CONTEXT_SegEs], es
mov [rcx + CONTEXT_SegFs], fs
mov [rcx + CONTEXT_SegGs], gs
mov [rcx + CONTEXT_SegSs], ss
/* Store return address */
mov [rcx + CONTEXT_Rip], rax
/* Safe xmm registers */
movdqa [rcx + CONTEXT_Xmm0], xmm0
movdqa [rcx + CONTEXT_Xmm1], xmm1
movdqa [rcx + CONTEXT_Xmm2], xmm2
movdqa [rcx + CONTEXT_Xmm3], xmm3
movdqa [rcx + CONTEXT_Xmm4], xmm4
movdqa [rcx + CONTEXT_Xmm5], xmm5
movdqa [rcx + CONTEXT_Xmm6], xmm6
movdqa [rcx + CONTEXT_Xmm7], xmm7
movdqa [rcx + CONTEXT_Xmm8], xmm8
movdqa [rcx + CONTEXT_Xmm9], xmm9
movdqa [rcx + CONTEXT_Xmm10], xmm10
movdqa [rcx + CONTEXT_Xmm11], xmm11
movdqa [rcx + CONTEXT_Xmm12], xmm12
movdqa [rcx + CONTEXT_Xmm13], xmm13
movdqa [rcx + CONTEXT_Xmm14], xmm14
movdqa [rcx + CONTEXT_Xmm15], xmm15
/* Cleanup stack and return */
add rsp, 8
ret
.ENDP
END

View file

@ -0,0 +1,87 @@
/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS Run-Time Library
* PURPOSE: Memory functions for amd64
* FILE: lib/rtl/amd64/rtlmem.S
* PROGRAMER: Timo Kreuzer (timo.kreuzer@reactos.org)
*/
/* INCLUDES ******************************************************************/
#include <asm.inc>
/* FUNCTIONS *****************************************************************/
.code64
/* SIZE_T
* RtlCompareMemory(
* IN CONST VOID *Source1, <rcx>
* IN CONST VOID *Source2, <rdx>
* IN SIZE_T Length <r8>
* );
*/
.proc RtlCompareMemory
/* Save registers */
push rsi
.pushreg rsi
push rdi
.pushreg rdi
.ENDPROLOG
/* Setup registers for compare */
mov rsi, rcx
mov rdi, rdx
/* Clear direction flag */
cli
/* Get number of qwords */
mov rcx, r8
shr rcx, 3
jz RtlCompareMemory2
/* Compare qwords */
repe cmpsq
jnz RtlCompareMemory4
RtlCompareMemory2:
/* Compare rest */
mov rcx, r8
and rcx, 7
jz RtlCompareMemory3
repe cmpsb
jnz RtlCompareMemory5
RtlCompareMemory3:
/* All equal */
/* Return the full count */
mov rax, rcx
jmp RtlCompareMemory6
RtlCompareMemory4:
/* Not equal after comparing qwords */
/* Compare the last qword */
sub rsi, 8
sub rdi, 8
mov rcx, 8
repe cmpsb
RtlCompareMemory5:
/* Not equal after comparing bytes */
/* Return difference */
sub rdi, rdx
dec rdi
mov rax, rdi
RtlCompareMemory6:
/* Cleanup and return */
pop rdi
pop rsi
ret
.endp
END

433
sdk/lib/rtl/amd64/slist.S Normal file
View file

@ -0,0 +1,433 @@
/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS system libraries
* FILE: lib/rtl/amd64/slist.S
* PURPOSE: Rtl Interlocked Functions for amd64
* PROGRAMMERS: Timo Kreuzer
*/
#include <asm.inc>
#include <ksamd64.inc>
EXTERN RtlpUse16ByteSLists:BYTE
/*
typedef union DECLSPEC_ALIGN(16) _SLIST_HEADER
{
struct
{
ULONGLONG Alignment;
ULONGLONG Region;
};
struct
{
ULONGLONG Depth:16;
ULONGLONG Sequence:9;
ULONGLONG NextEntry:39;
ULONGLONG HeaderType:1;
ULONGLONG Init:1;
ULONGLONG Reserved:59;
ULONGLONG Region:3;
} Header8;
struct
{
ULONGLONG Depth:16;
ULONGLONG Sequence:48;
ULONGLONG HeaderType:1;
ULONGLONG Init:1;
ULONGLONG Reserved:2;
ULONGLONG NextEntry:60;
} Header16;
struct
{
ULONGLONG Depth:16;
ULONGLONG Sequence:48;
ULONGLONG HeaderType:1;
ULONGLONG Reserved:3;
ULONGLONG NextEntry:60;
} HeaderX64;
} SLIST_HEADER, *PSLIST_HEADER;
*/
#define SLIST8A_DEPTH_MASK HEX(000000000000FFFF)
#define SLIST8A_DEPTH_INC HEX(0000000000000001)
#define SLIST8A_SEQUENCE_MASK HEX(0000000001FF0000)
#define SLIST8A_SEQUENCE_INC HEX(0000000000010000)
#define SLIST8A_NEXTENTRY_MASK HEX(FFFFFFFFFE000000)
#define SLIST8A_NEXTENTRY_SHIFT 21
#define SLIST8B_HEADERTYPE_MASK HEX(0000000000000001)
#define SLIST8B_INIT_MASK HEX(0000000000000002)
#define SLIST8B_REGION_MASK HEX(E000000000000000)
#define SLIST8_POINTER_MASK HEX(000007FFFFFFFFFF)
#define SLIST16A_DEPTH_MASK HEX(000000000000FFFF)
#define SLIST16A_DEPTH_INC HEX(0000000000000001)
#define SLIST16A_SEQUENCE_MASK HEX(FFFFFFFFFFFF0000)
#define SLIST16A_SEQUENCE_INC HEX(0000000000010000)
#define SLIST16B_HEADERTYPE_MASK HEX(0000000000000001)
#define SLIST16B_INIT_MASK HEX(0000000000000002)
#define SLIST16B_NEXTENTRY_MASK HEX(FFFFFFFFFFFFFFF0)
/* FUNCTIONS ****************************************************************/
.code64
PUBLIC ExpInterlockedPopEntrySList
PUBLIC ExpInterlockedPopEntrySListResume
PUBLIC ExpInterlockedPopEntrySListFault
PUBLIC ExpInterlockedPopEntrySListEnd
PUBLIC ExpInterlockedPopEntrySListResume16
PUBLIC ExpInterlockedPopEntrySListFault16
PUBLIC ExpInterlockedPopEntrySListEnd16
PUBLIC ExpInterlockedPushEntrySList
PUBLIC ExpInterlockedFlushSList
PUBLIC RtlInterlockedFlushSList
PUBLIC RtlInterlockedPopEntrySList
PUBLIC RtlInterlockedPushEntrySList
/* PSLIST_ENTRY
* NTAPI
* RtlInterlockedPopEntrySList(
* IN PSLIST_HEADER ListHead);
*/
RtlInterlockedPopEntrySList:
ExpInterlockedPopEntrySList:
/* Load ListHead->Region into rdx */
mov rdx, [rcx + 8]
/* Load ListHead->Alignment into rax */
mov rax, [rcx]
/* Check for 16 byte SList support */
cmp byte ptr [RtlpUse16ByteSLists], 0
jne RtlInterlockedPopEntrySList16
/* Use the 8 byte header */
ExpInterlockedPopEntrySListResume:
/* Check if ListHead->NextEntry is NULL */
mov r9, rax
and r9, SLIST8A_NEXTENTRY_MASK
jz RtlInterlockedPopEntrySListEmpty
/* Copy Depth and Sequence number and adjust Depth */
lea r8, [rax - SLIST8A_DEPTH_INC]
and r8, (SLIST8A_SEQUENCE_MASK OR SLIST8A_DEPTH_MASK)
/* Create a pointer template from rcx in rdx */
mov rdx, (NOT SLIST8_POINTER_MASK)
and rdx, rcx
/* Shift the NextEntry pointer */
shr r9, SLIST8A_NEXTENTRY_SHIFT
/* Combine to new pointer in rdx */
or rdx, r9
ExpInterlockedPopEntrySListFault:
/* Load the next NextEntry pointer to r9 */
mov r9, [rdx]
/* Shift bits in place */
shl r9, SLIST8A_NEXTENTRY_SHIFT
/* Combine into r8 */
or r8, r9
ExpInterlockedPopEntrySListEnd:
/* If [rcx] equals rax, exchange it with r8 */
lock cmpxchg [rcx], r8
/* If not equal, retry with rax, being the content of [rcx] now */
jne ExpInterlockedPopEntrySListResume
/* Shift the pointer bits in place */
and rax, SLIST8A_NEXTENTRY_MASK
shr rax, SLIST8A_NEXTENTRY_SHIFT
/* Use rcx as pointer template */
mov rdx, (NOT SLIST8_POINTER_MASK)
and rdx, rcx
/* Combine result and return */
or rax, rdx
ret
RtlInterlockedPopEntrySListEmpty:
xor rax, rax
ret
RtlInterlockedPopEntrySList16:
/* This is a 16 byte header
rcx == ListHead
rdx == ListHead->Region
rax == ListHead->Alignment */
/* Save rbx */
push rbx
/* Copy rcx to r8, as we need rcx for the exchange */
mov r8, rcx
ExpInterlockedPopEntrySListResume16:
/* Set r9 = ListHead->NextEntry and check if it is NULL */
mov r9, rdx
and r9, SLIST16B_NEXTENTRY_MASK
jz RtlInterlockedPopEntrySListEmpty16
ExpInterlockedPopEntrySListFault16:
/* Set NewListHead.Next = ListHead->NextEntry->Next */
mov rcx, [r9]
/* Set NewListHead.HeaderType = 1 and NewListHead.Init = 1 */
or rcx, (SLIST16B_HEADERTYPE_MASK or SLIST16B_INIT_MASK)
/* Copy Depth and Sequence number and adjust Depth */
lea rbx, [rax - SLIST16A_DEPTH_INC]
ExpInterlockedPopEntrySListEnd16:
/* If [r8] equals rdx:rax, exchange it with rcx:rbx */
lock cmpxchg16b [r8]
/* If not equal, retry with rdx:rax, being the content of [r8] now */
jne ExpInterlockedPopEntrySListResume16
/* Copy the old NextEntry pointer to rax */
mov rax, rdx
and rax, SLIST16B_NEXTENTRY_MASK
/* Return */
pop rbx
ret
RtlInterlockedPopEntrySListEmpty16:
xor rax, rax
pop rbx
ret
/* PSLIST_ENTRY
* NTAPI
* RtlInterlockedPushEntrySList(
* IN PSLIST_HEADER ListHead,
* IN PSLIST_ENTRY ListEntry);
*/
RtlInterlockedPushEntrySList:
ExpInterlockedPushEntrySList:
#if DBG
/* Make sure the ListEntry is 16 bytes aligned */
test rdx, HEX(0F)
jz ExpInterlockedPushEntrySListChecked
/* Not aligned, raise an assertion */
int HEX(2C)
ExpInterlockedPushEntrySListChecked:
/* Make sure RtlpUse16ByteSLists is initialized */
cmp byte ptr [RtlpUse16ByteSLists], HEX(FF)
jne ExpInterlockedPushEntrySListChecked2
/* Not initialized, raise an assertion */
int HEX(2C)
ExpInterlockedPushEntrySListChecked2:
#endif
/* Load ListHead->Alignment into rax */
mov rax, [rcx]
/* Load ListHead->Region into r9 */
mov r9, [rcx + 8]
/* Check for 16 byte SList support */
cmp byte ptr [RtlpUse16ByteSLists], 0
jne RtlInterlockedPushEntrySList16
/* Use the 8 byte header */
RtlInterlockedPushEntrySListLoop:
/* Get ListHead->NextEntry */
mov r8, rax
and r8, SLIST8A_NEXTENTRY_MASK
jz RtlInterlockedPushEntrySListEmpty
/* Shift the NextEntry pointer */
shr r8, SLIST8A_NEXTENTRY_SHIFT
/* Create a pointer template from rcx in rdx */
mov r9, (NOT SLIST8_POINTER_MASK)
and r9, rcx
/* Combine to new pointer and save as ListEntry->NextEntry */
or r8, r9
RtlInterlockedPushEntrySListEmpty:
/* Store the NextEntry pointer in the new ListEntry */
mov [rdx], r8
/* Shift and mask the new ListEntry pointer */
mov r8, rdx
shl r8, SLIST8A_NEXTENTRY_SHIFT
and r8, SLIST8A_NEXTENTRY_MASK
/* Copy and adjust depth and sequence number */
lea r9, [rax + SLIST8A_DEPTH_INC + SLIST8A_SEQUENCE_INC]
and r9, SLIST8A_SEQUENCE_MASK OR SLIST8A_DEPTH_MASK
/* Combine to exchange value in r8 */
or r8, r9
/* Save the NextEntry in r9 */
mov r9, [rdx]
/* If [rcx] equals rax, exchange it with r8 */
lock cmpxchg [rcx], r8
/* If not equal, retry with rax, being the content of [rcx] now */
jne RtlInterlockedPushEntrySListLoop
/* Return the old NextEntry pointer */
mov rax, r9
ret
RtlInterlockedPushEntrySList16:
/* This is a 16 byte header
rcx = ListHead
rdx = ListEntry
rax = ListHead->Alignment
r9 = ListHead->Region */
/* Save rbx */
push rbx
/* Copy rcx/rdx to r8/r9, as we need rcx/rdx for the exchange */
mov r8, rcx
mov r9, rdx
/* Set NewListHead.NextEntry = ListEntry */
mov rcx, rdx
/* Set NewListHead.HeaderType = 1 and NewListHead.Init = 1 */
or rcx, (SLIST16B_HEADERTYPE_MASK or SLIST16B_INIT_MASK)
/* Set rdx = ListHead->Region */
mov rdx, [r8 + 8]
RtlInterlockedPushEntrySListLoop16:
/* r8 = ListHead
r9 = ListEntry
rax = ListHead->Alignment
rdx = ListHead->Region
*/
/* Move ListHead->NextEntry to rbx */
mov rbx, rdx
and rbx, SLIST16B_NEXTENTRY_MASK
/* Store next pointer in ListEntry->Next */
mov [r9], rbx
/* Copy and increment Depth and Sequence number to rbx */
lea rbx, [rax + SLIST16A_DEPTH_INC + SLIST16A_SEQUENCE_INC]
/* If [r8] equals rdx:rax, exchange it with rcx:rbx */
lock cmpxchg16b [r8]
/* If not equal, retry with rdx:rax, being the content of [r8] now */
jne RtlInterlockedPushEntrySListLoop16
/* Copy the old NextEntry pointer to rax */
mov rax, rdx
and rax, SLIST16B_NEXTENTRY_MASK
/* Return */
pop rbx
ret
/* PSLIST_ENTRY
* NTAPI
* RtlInterlockedFlushSList(
* IN PSLIST_HEADER ListHead);
*/
RtlInterlockedFlushSList:
ExpInterlockedFlushSList:
/* Load ListHead->Region into rdx */
mov rdx, [rcx + 8]
/* Load ListHead->Alignment into rax */
mov rax, [rcx]
/* Check for 16 byte SList support */
cmp byte ptr [RtlpUse16ByteSLists], 0
jne RtlInterlockedFlushSList16
/* Use the 8 byte header */
RtlInterlockedFlushSListLoop:
/* Zero NewListHead.Alignment */
xor r8, r8
/* If [rcx] equals rax, exchange it with r8 */
lock cmpxchg [rcx], r8
/* If not equal, retry with rax, being the content of [rcx] now */
jne RtlInterlockedFlushSListLoop
/* Create a pointer template from rcx in rdx */
mov rdx, (NOT SLIST8_POINTER_MASK)
and rdx, rcx
/* Load the old NextEntry pointer into rax */
and rax, SLIST8A_NEXTENTRY_MASK
shr rax, SLIST8A_NEXTENTRY_SHIFT
/* Combine result and return */
or rax, rdx
ret
RtlInterlockedFlushSList16:
/* We have a 16 byte header
rcx = ListHead
rax = ListHead->Alignment
rdx = ListHead->Region
*/
/* Save rbx */
push rbx
/* Load ListHead into r8, as we need rcx for the exchange */
mov r8, rcx
/* Initialize an ampty NewListHead in rcx:rbx */
xor rbx, rbx
mov rcx, (SLIST16B_HEADERTYPE_MASK or SLIST16B_INIT_MASK)
RtlInterlockedFlushSListLoop16:
/* If [r8] equals rdx:rax, exchange it with rcx:rbx */
lock cmpxchg16b [r8]
/* If not equal, retry with rdx:rax, being the content of [r8] now */
jne RtlInterlockedFlushSListLoop16
/* Copy the old NextEntry pointer to rax */
mov rax, rdx
and rax, SLIST16B_NEXTENTRY_MASK
/* Return */
pop rbx
ret
END

116
sdk/lib/rtl/amd64/stubs.c Normal file
View file

@ -0,0 +1,116 @@
/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS Run-Time Library
* PURPOSE: AMD64 stubs
* FILE: lib/rtl/amd64/stubs.c
* PROGRAMMERS: Stefan Ginsberg (stefan.ginsberg@reactos.org)
*/
/* INCLUDES *****************************************************************/
#include <rtl.h>
#define NDEBUG
#include <debug.h>
#include "amd64/ketypes.h"
/* PUBLIC FUNCTIONS **********************************************************/
/*
* @unimplemented
*/
VOID
NTAPI
RtlInitializeContext(IN HANDLE ProcessHandle,
OUT PCONTEXT ThreadContext,
IN PVOID ThreadStartParam OPTIONAL,
IN PTHREAD_START_ROUTINE ThreadStartAddress,
IN PINITIAL_TEB StackBase)
{
ThreadContext->Rax = 0;
ThreadContext->Rbx = 0;
ThreadContext->Rcx = (ULONG64)ThreadStartParam;
ThreadContext->Rdx = 0;
ThreadContext->Rsi = 0;
ThreadContext->Rdi = 0;
ThreadContext->Rbp = 0;
ThreadContext->R8 = 0;
ThreadContext->R9 = 0;
ThreadContext->R10 = 0;
ThreadContext->R11 = 0;
ThreadContext->R12 = 0;
/* Set the Selectors */
if ((LONG64)ThreadStartAddress < 0)
{
/* Initialize kernel mode segments */
ThreadContext->SegCs = KGDT64_R0_CODE;
ThreadContext->SegDs = KGDT64_R3_DATA;
ThreadContext->SegEs = KGDT64_R3_DATA;
ThreadContext->SegFs = KGDT64_R3_CMTEB;
ThreadContext->SegGs = KGDT64_R3_DATA;
ThreadContext->SegSs = KGDT64_R0_DATA;
}
else
{
/* Initialize user mode segments */
ThreadContext->SegCs = KGDT64_R3_CODE | RPL_MASK;
ThreadContext->SegDs = KGDT64_R3_DATA | RPL_MASK;
ThreadContext->SegEs = KGDT64_R3_DATA | RPL_MASK;
ThreadContext->SegFs = KGDT64_R3_CMTEB | RPL_MASK;
ThreadContext->SegGs = KGDT64_R3_DATA | RPL_MASK;
ThreadContext->SegSs = KGDT64_R3_DATA | RPL_MASK;
}
/* Enable Interrupts */
ThreadContext->EFlags = EFLAGS_INTERRUPT_MASK;
/* Settings passed */
ThreadContext->Rip = (ULONG64)ThreadStartAddress;
ThreadContext->Rsp = (ULONG64)StackBase - 6 * sizeof(PVOID);
/* Align stack by 16 and substract 8 (unaligned on function entry) */
ThreadContext->Rsp &= ~15;
ThreadContext->Rsp -= 8;
/* Only the basic Context is initialized */
ThreadContext->ContextFlags = CONTEXT_CONTROL |
CONTEXT_INTEGER |
CONTEXT_SEGMENTS;
return;
}
/*
* @unimplemented
*/
PVOID
NTAPI
RtlpGetExceptionAddress(VOID)
{
UNIMPLEMENTED;
return NULL;
}
/*
* @unimplemented
*/
BOOLEAN
NTAPI
RtlDispatchException(IN PEXCEPTION_RECORD ExceptionRecord,
IN PCONTEXT Context)
{
UNIMPLEMENTED;
return FALSE;
}
NTSYSAPI
VOID
RtlRestoreContext(
PCONTEXT ContextRecord,
PEXCEPTION_RECORD ExceptionRecord)
{
UNIMPLEMENTED;
}

694
sdk/lib/rtl/amd64/unwind.c Normal file
View file

@ -0,0 +1,694 @@
/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS system libraries
* PURPOSE: Unwinding related functions
* PROGRAMMER: Timo Kreuzer (timo.kreuzer@reactos.org)
*/
/* INCLUDES *****************************************************************/
#include <rtl.h>
#define NDEBUG
#include <debug.h>
#define UNWIND_HISTORY_TABLE_NONE 0
#define UNWIND_HISTORY_TABLE_GLOBAL 1
#define UNWIND_HISTORY_TABLE_LOCAL 2
#define UWOP_PUSH_NONVOL 0
#define UWOP_ALLOC_LARGE 1
#define UWOP_ALLOC_SMALL 2
#define UWOP_SET_FPREG 3
#define UWOP_SAVE_NONVOL 4
#define UWOP_SAVE_NONVOL_FAR 5
#define UWOP_SAVE_XMM 6
#define UWOP_SAVE_XMM_FAR 7
#define UWOP_SAVE_XMM128 8
#define UWOP_SAVE_XMM128_FAR 9
#define UWOP_PUSH_MACHFRAME 10
#define UNW_FLAG_NHANDLER 0
#define UNW_FLAG_EHANDLER 1
#define UNW_FLAG_UHANDLER 2
#define UNW_FLAG_CHAININFO 4
typedef unsigned char UBYTE;
typedef union _UNWIND_CODE
{
struct
{
UBYTE CodeOffset;
UBYTE UnwindOp:4;
UBYTE OpInfo:4;
};
USHORT FrameOffset;
} UNWIND_CODE, *PUNWIND_CODE;
typedef struct _UNWIND_INFO
{
UBYTE Version:3;
UBYTE Flags:5;
UBYTE SizeOfProlog;
UBYTE CountOfCodes;
UBYTE FrameRegister:4;
UBYTE FrameOffset:4;
UNWIND_CODE UnwindCode[1];
/* union {
OPTIONAL ULONG ExceptionHandler;
OPTIONAL ULONG FunctionEntry;
};
OPTIONAL ULONG ExceptionData[];
*/
} UNWIND_INFO, *PUNWIND_INFO;
/* FUNCTIONS *****************************************************************/
/*! RtlLookupFunctionTable
* \brief Locates the table of RUNTIME_FUNCTION entries for a code address.
* \param ControlPc
* Address of the code, for which the table should be searched.
* \param ImageBase
* Pointer to a DWORD64 that receives the base address of the
* corresponding executable image.
* \param Length
* Pointer to an ULONG that receives the number of table entries
* present in the table.
*/
PRUNTIME_FUNCTION
NTAPI
RtlLookupFunctionTable(
IN DWORD64 ControlPc,
OUT PDWORD64 ImageBase,
OUT PULONG Length)
{
PVOID Table;
ULONG Size;
/* Find corresponding file header from code address */
if (!RtlPcToFileHeader((PVOID)ControlPc, (PVOID*)ImageBase))
{
/* Nothing found */
return NULL;
}
/* Locate the exception directory */
Table = RtlImageDirectoryEntryToData((PVOID)*ImageBase,
TRUE,
IMAGE_DIRECTORY_ENTRY_EXCEPTION,
&Size);
/* Return the number of entries */
*Length = Size / sizeof(RUNTIME_FUNCTION);
/* Return the address of the table */
return Table;
}
/*! RtlLookupFunctionEntry
* \brief Locates the RUNTIME_FUNCTION entry corresponding to a code address.
* \ref http://msdn.microsoft.com/en-us/library/ms680597(VS.85).aspx
* \todo Implement HistoryTable
*/
PRUNTIME_FUNCTION
NTAPI
RtlLookupFunctionEntry(
IN DWORD64 ControlPc,
OUT PDWORD64 ImageBase,
OUT PUNWIND_HISTORY_TABLE HistoryTable)
{
PRUNTIME_FUNCTION FunctionTable, FunctionEntry;
ULONG TableLength;
ULONG IndexLo, IndexHi, IndexMid;
/* Find the corresponding table */
FunctionTable = RtlLookupFunctionTable(ControlPc, ImageBase, &TableLength);
/* Fail, if no table is found */
if (!FunctionTable)
{
return NULL;
}
/* Use relative virtual address */
ControlPc -= *ImageBase;
/* Do a binary search */
IndexLo = 0;
IndexHi = TableLength;
while (IndexHi > IndexLo)
{
IndexMid = (IndexLo + IndexHi) / 2;
FunctionEntry = &FunctionTable[IndexMid];
if (ControlPc < FunctionEntry->BeginAddress)
{
/* Continue search in lower half */
IndexHi = IndexMid;
}
else if (ControlPc >= FunctionEntry->EndAddress)
{
/* Continue search in upper half */
IndexLo = IndexMid + 1;
}
else
{
/* ControlPc is within limits, return entry */
return FunctionEntry;
}
}
/* Nothing found, return NULL */
return NULL;
}
BOOLEAN
NTAPI
RtlAddFunctionTable(
IN PRUNTIME_FUNCTION FunctionTable,
IN DWORD EntryCount,
IN DWORD64 BaseAddress)
{
UNIMPLEMENTED;
return FALSE;
}
BOOLEAN
NTAPI
RtlDeleteFunctionTable(
IN PRUNTIME_FUNCTION FunctionTable)
{
UNIMPLEMENTED;
return FALSE;
}
BOOLEAN
NTAPI
RtlInstallFunctionTableCallback(
IN DWORD64 TableIdentifier,
IN DWORD64 BaseAddress,
IN DWORD Length,
IN PGET_RUNTIME_FUNCTION_CALLBACK Callback,
IN PVOID Context,
IN PCWSTR OutOfProcessCallbackDll)
{
UNIMPLEMENTED;
return FALSE;
}
void
FORCEINLINE
SetReg(PCONTEXT Context, BYTE Reg, DWORD64 Value)
{
((DWORD64*)(&Context->Rax))[Reg] = Value;
}
DWORD64
FORCEINLINE
GetReg(PCONTEXT Context, BYTE Reg)
{
return ((DWORD64*)(&Context->Rax))[Reg];
}
void
FORCEINLINE
PopReg(PCONTEXT Context, BYTE Reg)
{
DWORD64 Value = *(DWORD64*)Context->Rsp;
Context->Rsp += 8;
SetReg(Context, Reg, Value);
}
/*! RtlpTryToUnwindEpilog
* \brief Helper function that tries to unwind epilog instructions.
* \return TRUE if we have been in an epilog and it could be unwound.
* FALSE if the instructions were not allowed for an epilog.
* \ref
* http://msdn.microsoft.com/en-us/library/8ydc79k6(VS.80).aspx
* http://msdn.microsoft.com/en-us/library/tawsa7cb.aspx
* \todo
* - Test and compare with Windows behaviour
*/
BOOLEAN
static
__inline
RtlpTryToUnwindEpilog(
PCONTEXT Context,
ULONG64 ImageBase,
PRUNTIME_FUNCTION FunctionEntry)
{
CONTEXT LocalContext;
BYTE *InstrPtr;
DWORD Instr;
BYTE Reg, Mod;
ULONG64 EndAddress;
/* Make a local copy of the context */
LocalContext = *Context;
InstrPtr = (BYTE*)LocalContext.Rip;
/* Check if first instruction of epilog is "add rsp, x" */
Instr = *(DWORD*)InstrPtr;
if ( (Instr & 0x00fffdff) == 0x00c48148 )
{
if ( (Instr & 0x0000ff00) == 0x8300 )
{
/* This is "add rsp, 0x??" */
LocalContext.Rsp += Instr >> 24;
InstrPtr += 4;
}
else
{
/* This is "add rsp, 0x???????? */
LocalContext.Rsp += *(DWORD*)(InstrPtr + 3);
InstrPtr += 7;
}
}
/* Check if first instruction of epilog is "lea rsp, ..." */
else if ( (Instr & 0x38fffe) == 0x208d48 )
{
/* Get the register */
Reg = ((Instr << 8) | (Instr >> 16)) & 0x7;
LocalContext.Rsp = GetReg(&LocalContext, Reg);
/* Get adressing mode */
Mod = (Instr >> 22) & 0x3;
if (Mod == 0)
{
/* No displacement */
InstrPtr += 3;
}
else if (Mod == 1)
{
/* 1 byte displacement */
LocalContext.Rsp += Instr >> 24;
InstrPtr += 4;
}
else if (Mod == 2)
{
/* 4 bytes displacement */
LocalContext.Rsp += *(DWORD*)(InstrPtr + 3);
InstrPtr += 7;
}
}
/* Loop the following instructions before the ret */
EndAddress = FunctionEntry->EndAddress + ImageBase - 1;
while ((DWORD64)InstrPtr < EndAddress)
{
Instr = *(DWORD*)InstrPtr;
/* Check for a simple pop */
if ( (Instr & 0xf8) == 0x58 )
{
/* Opcode pops a basic register from stack */
Reg = Instr & 0x7;
PopReg(&LocalContext, Reg);
InstrPtr++;
continue;
}
/* Check for REX + pop */
if ( (Instr & 0xf8fb) == 0x5841 )
{
/* Opcode is pop r8 .. r15 */
Reg = ((Instr >> 8) & 0x7) + 8;
PopReg(&LocalContext, Reg);
InstrPtr += 2;
continue;
}
/* Opcode not allowed for Epilog */
return FALSE;
}
/* Check if we are at the ret instruction */
if ((DWORD64)InstrPtr != EndAddress)
{
/* If we went past the end of the function, something is broken! */
ASSERT((DWORD64)InstrPtr <= EndAddress);
return FALSE;
}
/* Make sure this is really a ret instruction */
if (*InstrPtr != 0xc3)
{
ASSERT(FALSE);
return FALSE;
}
/* Unwind is finished, pop new Rip from Stack */
LocalContext.Rip = *(DWORD64*)LocalContext.Rsp;
LocalContext.Rsp += sizeof(DWORD64);
*Context = LocalContext;
return TRUE;
}
PEXCEPTION_ROUTINE
NTAPI
RtlVirtualUnwind(
IN ULONG HandlerType,
IN ULONG64 ImageBase,
IN ULONG64 ControlPc,
IN PRUNTIME_FUNCTION FunctionEntry,
IN OUT PCONTEXT Context,
OUT PVOID *HandlerData,
OUT PULONG64 EstablisherFrame,
IN OUT PKNONVOLATILE_CONTEXT_POINTERS ContextPointers)
{
PUNWIND_INFO UnwindInfo;
ULONG_PTR CodeOffset;
ULONG i;
UNWIND_CODE UnwindCode;
BYTE Reg;
/* Use relative virtual address */
ControlPc -= ImageBase;
/* Sanity checks */
if ( (ControlPc < FunctionEntry->BeginAddress) ||
(ControlPc >= FunctionEntry->EndAddress) )
{
return NULL;
}
/* Get a pointer to the unwind info */
UnwindInfo = RVA(ImageBase, FunctionEntry->UnwindData);
/* Calculate relative offset to function start */
CodeOffset = ControlPc - FunctionEntry->BeginAddress;
/* Check if we are in the function epilog and try to finish it */
if (CodeOffset > UnwindInfo->SizeOfProlog)
{
if (RtlpTryToUnwindEpilog(Context, ImageBase, FunctionEntry))
{
/* There's no exception routine */
return NULL;
}
}
/* Skip all Ops with an offset greater than the current Offset */
i = 0;
while (i < UnwindInfo->CountOfCodes &&
CodeOffset < UnwindInfo->UnwindCode[i].CodeOffset)
{
UnwindCode = UnwindInfo->UnwindCode[i];
switch (UnwindCode.UnwindOp)
{
case UWOP_SAVE_NONVOL:
case UWOP_SAVE_XMM:
case UWOP_SAVE_XMM128:
i += 2;
break;
case UWOP_SAVE_NONVOL_FAR:
case UWOP_SAVE_XMM_FAR:
case UWOP_SAVE_XMM128_FAR:
i += 3;
break;
case UWOP_ALLOC_LARGE:
i += UnwindCode.OpInfo ? 3 : 2;
break;
default:
i++;
}
}
/* Process the remaining unwind ops */
while (i < UnwindInfo->CountOfCodes)
{
UnwindCode = UnwindInfo->UnwindCode[i];
switch (UnwindCode.UnwindOp)
{
case UWOP_PUSH_NONVOL:
Reg = UnwindCode.OpInfo;
SetReg(Context, Reg, *(DWORD64*)Context->Rsp);
Context->Rsp += sizeof(DWORD64);
i++;
break;
case UWOP_ALLOC_LARGE:
if (UnwindCode.OpInfo)
{
ULONG Offset = *(ULONG*)(&UnwindInfo->UnwindCode[i+1]);
Context->Rsp += Offset;
i += 3;
}
else
{
USHORT Offset = UnwindInfo->UnwindCode[i+1].FrameOffset;
Context->Rsp += Offset * 8;
i += 2;
}
break;
case UWOP_ALLOC_SMALL:
Context->Rsp += (UnwindCode.OpInfo + 1) * 8;
i++;
break;
case UWOP_SET_FPREG:
i++;
break;
case UWOP_SAVE_NONVOL:
i += 2;
break;
case UWOP_SAVE_NONVOL_FAR:
i += 3;
break;
case UWOP_SAVE_XMM:
i += 2;
break;
case UWOP_SAVE_XMM_FAR:
i += 3;
break;
case UWOP_SAVE_XMM128:
i += 2;
break;
case UWOP_SAVE_XMM128_FAR:
i += 3;
break;
case UWOP_PUSH_MACHFRAME:
i += 1;
break;
}
}
/* Unwind is finished, pop new Rip from Stack */
Context->Rip = *(DWORD64*)Context->Rsp;
Context->Rsp += sizeof(DWORD64);
return 0;
}
VOID
NTAPI
RtlUnwindEx(
IN ULONG64 TargetFrame,
IN ULONG64 TargetIp,
IN PEXCEPTION_RECORD ExceptionRecord,
IN PVOID ReturnValue,
OUT PCONTEXT OriginalContext,
IN PUNWIND_HISTORY_TABLE HistoryTable)
{
UNIMPLEMENTED;
return;
}
VOID
NTAPI
RtlUnwind(
IN PVOID TargetFrame,
IN PVOID TargetIp,
IN PEXCEPTION_RECORD ExceptionRecord,
IN PVOID ReturnValue)
{
UNIMPLEMENTED;
return;
}
ULONG
NTAPI
RtlWalkFrameChain(OUT PVOID *Callers,
IN ULONG Count,
IN ULONG Flags)
{
CONTEXT Context;
ULONG64 ControlPc, ImageBase, EstablisherFrame;
ULONG64 StackLow, StackHigh;
PVOID HandlerData;
ULONG i, FramesToSkip;
PRUNTIME_FUNCTION FunctionEntry;
DPRINT("Enter RtlWalkFrameChain\n");
/* The upper bits in Flags define how many frames to skip */
FramesToSkip = Flags >> 8;
/* Capture the current Context */
RtlCaptureContext(&Context);
ControlPc = Context.Rip;
/* Get the stack limits */
RtlpGetStackLimits(&StackLow, &StackHigh);
/* Check if we want the user-mode stack frame */
if (Flags & 1)
{
}
/* Loop the frames */
for (i = 0; i < FramesToSkip + Count; i++)
{
/* Lookup the FunctionEntry for the current ControlPc */
FunctionEntry = RtlLookupFunctionEntry(ControlPc, &ImageBase, NULL);
/* Is this a leaf function? */
if (!FunctionEntry)
{
Context.Rip = *(DWORD64*)Context.Rsp;
Context.Rsp += sizeof(DWORD64);
DPRINT("leaf funtion, new Rip = %p, new Rsp = %p\n", (PVOID)Context.Rip, (PVOID)Context.Rsp);
}
else
{
RtlVirtualUnwind(0,
ImageBase,
ControlPc,
FunctionEntry,
&Context,
&HandlerData,
&EstablisherFrame,
NULL);
DPRINT("normal funtion, new Rip = %p, new Rsp = %p\n", (PVOID)Context.Rip, (PVOID)Context.Rsp);
}
/* Check if new Rip is valid */
if (!Context.Rip)
{
break;
}
/* Check, if we have left our stack */
if ((Context.Rsp < StackLow) || (Context.Rsp > StackHigh))
{
break;
}
/* Continue with new Rip */
ControlPc = Context.Rip;
/* Save value, if we are past the frames to skip */
if (i >= FramesToSkip)
{
Callers[i - FramesToSkip] = (PVOID)ControlPc;
}
}
DPRINT("RtlWalkFrameChain returns %ld\n", i);
return i;
}
/*! RtlGetCallersAddress
* \ref http://undocumented.ntinternals.net/UserMode/Undocumented%20Functions/Debug/RtlGetCallersAddress.html
*/
#undef RtlGetCallersAddress
VOID
NTAPI
RtlGetCallersAddress(
OUT PVOID *CallersAddress,
OUT PVOID *CallersCaller )
{
PVOID Callers[4];
ULONG Number;
/* Get callers:
* RtlWalkFrameChain -> RtlGetCallersAddress -> x -> y */
Number = RtlWalkFrameChain(Callers, 4, 0);
*CallersAddress = (Number >= 3) ? Callers[2] : NULL;
*CallersCaller = (Number == 4) ? Callers[3] : NULL;
return;
}
// FIXME: move to different file
VOID
NTAPI
RtlRaiseException(IN PEXCEPTION_RECORD ExceptionRecord)
{
CONTEXT Context;
NTSTATUS Status = STATUS_INVALID_DISPOSITION;
ULONG64 ImageBase;
PRUNTIME_FUNCTION FunctionEntry;
PVOID HandlerData;
ULONG64 EstablisherFrame;
/* Capture the context */
RtlCaptureContext(&Context);
/* Get the function entry for this function */
FunctionEntry = RtlLookupFunctionEntry(Context.Rip,
&ImageBase,
NULL);
/* Check if we found it */
if (FunctionEntry)
{
/* Unwind to the caller of this function */
RtlVirtualUnwind(UNW_FLAG_NHANDLER,
ImageBase,
Context.Rip,
FunctionEntry,
&Context,
&HandlerData,
&EstablisherFrame,
NULL);
/* Save the exception address */
ExceptionRecord->ExceptionAddress = (PVOID)Context.Rip;
/* Write the context flag */
Context.ContextFlags = CONTEXT_FULL;
/* Check if user mode debugger is active */
if (RtlpCheckForActiveDebugger())
{
/* Raise an exception immediately */
Status = ZwRaiseException(ExceptionRecord, &Context, TRUE);
}
else
{
/* Dispatch the exception and check if we should continue */
if (!RtlDispatchException(ExceptionRecord, &Context))
{
/* Raise the exception */
Status = ZwRaiseException(ExceptionRecord, &Context, FALSE);
}
else
{
/* Continue, go back to previous context */
Status = ZwContinue(&Context, FALSE);
}
}
}
/* If we returned, raise a status */
RtlRaiseStatus(Status);
}