mirror of
https://github.com/reactos/reactos.git
synced 2025-08-02 06:05:48 +00:00
Git conversion: Make reactos the root directory, move rosapps, rostests, wallpapers into modules, and delete rossubsys.
This commit is contained in:
parent
b94e2d8ca0
commit
c2c66aff7d
24198 changed files with 0 additions and 37285 deletions
81
sdk/lib/rtl/amd64/debug_asm.S
Normal file
81
sdk/lib/rtl/amd64/debug_asm.S
Normal 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
|
103
sdk/lib/rtl/amd64/except_asm.S
Normal file
103
sdk/lib/rtl/amd64/except_asm.S
Normal 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
|
||||
|
||||
|
87
sdk/lib/rtl/amd64/rtlmem.S
Normal file
87
sdk/lib/rtl/amd64/rtlmem.S
Normal 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
433
sdk/lib/rtl/amd64/slist.S
Normal 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
116
sdk/lib/rtl/amd64/stubs.c
Normal 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
694
sdk/lib/rtl/amd64/unwind.c
Normal 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);
|
||||
}
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue