mirror of
https://github.com/reactos/reactos.git
synced 2025-08-03 18:35:41 +00:00
[RTL]
Merge from amd64 branch 35738,37004,37308,37324,37330,37331,37332,37370,37419,37424,37425,37428,37473,37492,37844,37911,37987,40604,41006,43686,43951,43953,43980,43993,44001,44289,44295,44296,44428,44966,44967,44968 - Implement amd64 specific RTL functions: RtlLookupFunctionTable, RtlLookupFunctionEntry, RtlCaptureContext, RtlVirtualUnwind, RtlWalkFrameChain, RtlGetCallersAddress, RtlRaiseException (Timo Kreuzer) - Implement amd64 asm functions: RtlCompareMemory, DebugService, RtlInterlockedPopEntrySList, RtlInterlockedPushEntrySList and RtlInterlockedFlushSList (Timo Kreuzer) - Don't use double in rtl's sprintf / swprintf, use double_t union instead. (Stefan Ginsberg) svn path=/trunk/; revision=44970
This commit is contained in:
parent
0c5fed9d71
commit
2736e830ea
12 changed files with 1429 additions and 79 deletions
79
reactos/lib/rtl/amd64/debug_asm.S
Normal file
79
reactos/lib/rtl/amd64/debug_asm.S
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
/*
|
||||||
|
* COPYRIGHT: See COPYING in the top level directory
|
||||||
|
* PROJECT: ReactOS Run-Time Library
|
||||||
|
* PURPOSE: Debug Routines
|
||||||
|
* FILE: lib/rtl/i386/debug.S
|
||||||
|
* PROGRAMER: Alex Ionescu (alex@relsoft.net)
|
||||||
|
*/
|
||||||
|
|
||||||
|
.intel_syntax noprefix
|
||||||
|
|
||||||
|
/* GLOBALS ****************************************************************/
|
||||||
|
|
||||||
|
.globl _DbgBreakPoint
|
||||||
|
.globl _DbgBreakPointWithStatus
|
||||||
|
.globl _DbgUserBreakPoint
|
||||||
|
.globl _DebugService
|
||||||
|
.globl _DebugService2
|
||||||
|
.globl _DbgBreakPointNoBugCheck
|
||||||
|
.globl _RtlpBreakWithStatusInstruction
|
||||||
|
|
||||||
|
/* FUNCTIONS ***************************************************************/
|
||||||
|
|
||||||
|
.func DbgBreakPointNoBugCheck
|
||||||
|
_DbgBreakPointNoBugCheck:
|
||||||
|
int 3
|
||||||
|
ret
|
||||||
|
.endfunc
|
||||||
|
|
||||||
|
.func DbgBreakPoint
|
||||||
|
_DbgBreakPoint:
|
||||||
|
_DbgUserBreakPoint:
|
||||||
|
int 3
|
||||||
|
ret
|
||||||
|
.endfunc
|
||||||
|
|
||||||
|
.func DbgBreakPointWithStatus
|
||||||
|
_DbgBreakPointWithStatus:
|
||||||
|
mov eax, ecx
|
||||||
|
|
||||||
|
_RtlpBreakWithStatusInstruction:
|
||||||
|
int 3
|
||||||
|
ret
|
||||||
|
.endfunc
|
||||||
|
|
||||||
|
.func DebugService2
|
||||||
|
_DebugService2:
|
||||||
|
ret
|
||||||
|
/* Call the interrupt */
|
||||||
|
// mov eax, [rbp+8]
|
||||||
|
// int 0x2D
|
||||||
|
// int 3
|
||||||
|
|
||||||
|
.endfunc
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
* 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]
|
||||||
|
*/
|
||||||
|
.func DebugService
|
||||||
|
_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 0x2D
|
||||||
|
int 3
|
||||||
|
|
||||||
|
/* Return */
|
||||||
|
ret
|
||||||
|
.endfunc
|
100
reactos/lib/rtl/amd64/except_asm.S
Normal file
100
reactos/lib/rtl/amd64/except_asm.S
Normal file
|
@ -0,0 +1,100 @@
|
||||||
|
/*
|
||||||
|
* 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 <ndk/asm.h>
|
||||||
|
.intel_syntax noprefix
|
||||||
|
|
||||||
|
/* FUNCTIONS *****************************************************************/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* VOID NTAPI
|
||||||
|
* RtlCaptureContext(
|
||||||
|
* PCONTEXT ContextRecord); <rcx>
|
||||||
|
*/
|
||||||
|
.func RtlCaptureContext
|
||||||
|
.global _RtlCaptureContext
|
||||||
|
_RtlCaptureContext:
|
||||||
|
.cfi_startproc
|
||||||
|
|
||||||
|
/* Push rflags */
|
||||||
|
pushfq
|
||||||
|
.cfi_adjust_cfa_offset 8
|
||||||
|
|
||||||
|
/* 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 + 0x10]
|
||||||
|
|
||||||
|
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
|
||||||
|
.cfi_endproc
|
||||||
|
.endfunc
|
||||||
|
|
78
reactos/lib/rtl/amd64/rtlmem.S
Normal file
78
reactos/lib/rtl/amd64/rtlmem.S
Normal file
|
@ -0,0 +1,78 @@
|
||||||
|
/*
|
||||||
|
* COPYRIGHT: See COPYING in the top level directory
|
||||||
|
* PROJECT: ReactOS Run-Time Library
|
||||||
|
* PURPOSE: Memory functions for amd64
|
||||||
|
* FILE: lib/rtl/i386/rtlswap.S
|
||||||
|
* PROGRAMER: Timo Kreuzer (timo.kreuzer@reactos.org)
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* INCLUDES ******************************************************************/
|
||||||
|
|
||||||
|
#include <ndk/amd64/asmmacro.S>
|
||||||
|
|
||||||
|
/* FUNCTIONS *****************************************************************/
|
||||||
|
.intel_syntax noprefix
|
||||||
|
|
||||||
|
/* 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
|
||||||
|
|
||||||
|
/* 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 2f
|
||||||
|
|
||||||
|
/* Compare qwords */
|
||||||
|
repe cmpsq
|
||||||
|
jnz 4f
|
||||||
|
|
||||||
|
2: /* Compare rest */
|
||||||
|
mov rcx, r8
|
||||||
|
and rcx, 7
|
||||||
|
jz 3f
|
||||||
|
|
||||||
|
repe cmpsb
|
||||||
|
jnz 5f
|
||||||
|
|
||||||
|
3: /* All equal */
|
||||||
|
/* Return the full count */
|
||||||
|
mov rax, rcx
|
||||||
|
jmp 6f
|
||||||
|
|
||||||
|
4: /* Not equal after comparing qwords */
|
||||||
|
/* Compare the last qword */
|
||||||
|
sub rsi, 8
|
||||||
|
sub rdi, 8
|
||||||
|
mov rcx, 8
|
||||||
|
repe cmpsb
|
||||||
|
|
||||||
|
5: /* Not equal after comparing bytes */
|
||||||
|
/* Return difference */
|
||||||
|
sub rdi, rdx
|
||||||
|
dec rdi
|
||||||
|
mov rax, rdi
|
||||||
|
|
||||||
|
6: /* Cleanup and return */
|
||||||
|
pop rdi
|
||||||
|
pop rsi
|
||||||
|
ret
|
||||||
|
.endproc
|
||||||
|
|
343
reactos/lib/rtl/amd64/slist.S
Normal file
343
reactos/lib/rtl/amd64/slist.S
Normal file
|
@ -0,0 +1,343 @@
|
||||||
|
/*
|
||||||
|
* COPYRIGHT: See COPYING in the top level directory
|
||||||
|
* PROJECT: ReactOS system libraries
|
||||||
|
* FILE: lib/rtl/amd64/interlck.S
|
||||||
|
* PURPOSE: Rtl Interlocked Functions for amd64
|
||||||
|
* PROGRAMMERS: Timo Kreuzer
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <ndk/asm.h>
|
||||||
|
#include <ndk/amd64/asmmacro.S>
|
||||||
|
.intel_syntax noprefix
|
||||||
|
|
||||||
|
#define SLIST8A_DEPTH_MASK 0x000000000000FFFF
|
||||||
|
#define SLIST8A_DEPTH_INC 0x0000000000000001
|
||||||
|
#define SLIST8A_SEQUENCE_MASK 0x0000000001FF0000
|
||||||
|
#define SLIST8A_SEQUENCE_INC 0x0000000000010000
|
||||||
|
#define SLIST8A_NEXTENTRY_MASK 0xFFFFFFFFFE000000
|
||||||
|
#define SLIST8A_NEXTENTRY_SHIFT 21
|
||||||
|
#define SLIST8B_HEADERTYPE_MASK 0x0000000000000001
|
||||||
|
#define SLIST8B_INIT_MASK 0x0000000000000002
|
||||||
|
#define SLIST8B_REGION_MASK 0xE000000000000000
|
||||||
|
#define SLIST8_POINTER_MASK 0x000007FFFFFFFFF0
|
||||||
|
|
||||||
|
#define SLIST16A_DEPTH_MASK 0x000000000000FFFF
|
||||||
|
#define SLIST16A_DEPTH_INC 0x0000000000000001
|
||||||
|
#define SLIST16A_SEQUENCE_MASK 0xFFFFFFFFFFFF0000
|
||||||
|
#define SLIST16A_SEQUENCE_INC 0x0000000000010000
|
||||||
|
#define SLIST16B_HEADERTYPE_MASK 0x0000000000000001
|
||||||
|
#define SLIST16B_INIT_MASK 0x0000000000000002
|
||||||
|
#define SLIST16B_NEXTENTY_MASK 0xFFFFFFFFFFFFFFF0
|
||||||
|
|
||||||
|
|
||||||
|
/* FUNCTIONS ****************************************************************/
|
||||||
|
|
||||||
|
.global _ExpInterlockedPopEntrySList
|
||||||
|
.global _ExpInterlockedPopEntrySListResume
|
||||||
|
.global _ExpInterlockedPopEntrySListFault
|
||||||
|
.global _ExpInterlockedPopEntrySListEnd
|
||||||
|
.global _ExpInterlockedPopEntrySListResume16
|
||||||
|
.global _ExpInterlockedPopEntrySListFault16
|
||||||
|
.global _ExpInterlockedPopEntrySListEnd16
|
||||||
|
.global _ExpInterlockedPushEntrySList
|
||||||
|
.global _ExpInterlockedFlushSList
|
||||||
|
|
||||||
|
/* PSLIST_ENTRY
|
||||||
|
* NTAPI
|
||||||
|
* RtlInterlockedPopEntrySList(
|
||||||
|
* IN PSLIST_HEADER ListHead);
|
||||||
|
*/
|
||||||
|
.proc RtlInterlockedPopEntrySList
|
||||||
|
_ExpInterlockedPopEntrySList:
|
||||||
|
|
||||||
|
/* Load ListHead->Region into rdx */
|
||||||
|
mov rdx, [rcx + 8]
|
||||||
|
|
||||||
|
/* Load ListHead->Alignment into rax */
|
||||||
|
mov rax, [rcx]
|
||||||
|
|
||||||
|
/* Check what kind of header this is */
|
||||||
|
test rdx, SLIST8B_HEADERTYPE_MASK
|
||||||
|
jnz _RtlInterlockedPopEntrySList16
|
||||||
|
|
||||||
|
/* We have an 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 | SLIST8A_DEPTH_MASK
|
||||||
|
|
||||||
|
/* Create a pointer template from rcx in rdx */
|
||||||
|
mov rdx, ~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 */
|
||||||
|
jnz _ExpInterlockedPopEntrySListResume
|
||||||
|
|
||||||
|
/* Shift the pointer bits in place */
|
||||||
|
and rax, SLIST8A_NEXTENTRY_MASK
|
||||||
|
shr rax, SLIST8A_NEXTENTRY_SHIFT
|
||||||
|
|
||||||
|
/* Use rcx as pointer template */
|
||||||
|
mov rdx, ~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 */
|
||||||
|
|
||||||
|
/* Save rbx */
|
||||||
|
push rbx
|
||||||
|
|
||||||
|
/* Copy rcx to r8, as we need rcx for the exchange */
|
||||||
|
mov r8, rcx
|
||||||
|
|
||||||
|
_ExpInterlockedPopEntrySListResume16:
|
||||||
|
|
||||||
|
/* Check if ListHead->NextEntry is NULL */
|
||||||
|
mov r9, rdx
|
||||||
|
and r9, SLIST16B_NEXTENTY_MASK
|
||||||
|
jz _RtlInterlockedPopEntrySListEmpty16
|
||||||
|
|
||||||
|
_ExpInterlockedPopEntrySListFault16:
|
||||||
|
|
||||||
|
/* Get next pointer */
|
||||||
|
mov rcx, [r9]
|
||||||
|
|
||||||
|
/* Set ListHead->HeaderType = 1 and ListHead->Init = 1 */
|
||||||
|
or rcx, 0x3
|
||||||
|
|
||||||
|
/* 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 */
|
||||||
|
jnz _ExpInterlockedPopEntrySListResume16
|
||||||
|
|
||||||
|
/* Copy the old NextEntry pointer to rax */
|
||||||
|
mov rax, rdx
|
||||||
|
and rax, SLIST16B_NEXTENTY_MASK
|
||||||
|
|
||||||
|
/* Return */
|
||||||
|
pop rbx
|
||||||
|
ret
|
||||||
|
|
||||||
|
_RtlInterlockedPopEntrySListEmpty16:
|
||||||
|
xor rax, rax
|
||||||
|
pop rbx
|
||||||
|
ret
|
||||||
|
|
||||||
|
.endproc
|
||||||
|
|
||||||
|
|
||||||
|
/* PSLIST_ENTRY
|
||||||
|
* NTAPI
|
||||||
|
* RtlInterlockedPushEntrySList(
|
||||||
|
* IN PSLIST_HEADER ListHead,
|
||||||
|
* IN PSLIST_ENTRY ListEntry);
|
||||||
|
*/
|
||||||
|
.proc RtlInterlockedPushEntrySList
|
||||||
|
_ExpInterlockedPushEntrySList:
|
||||||
|
|
||||||
|
/* Load ListHead->Alignment into rax */
|
||||||
|
mov rax, [rcx]
|
||||||
|
|
||||||
|
/* Load ListHead->Region into rdx */
|
||||||
|
mov r9, [rcx + 8]
|
||||||
|
|
||||||
|
/* Check what kind of header this is */
|
||||||
|
test r9, SLIST8B_HEADERTYPE_MASK
|
||||||
|
jnz _RtlInterlockedPushEntrySList16
|
||||||
|
|
||||||
|
/* We have an 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, ~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 | 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 */
|
||||||
|
jnz _RtlInterlockedPushEntrySListLoop
|
||||||
|
|
||||||
|
/* Return the old NextEntry pointer */
|
||||||
|
mov rax, r9
|
||||||
|
ret
|
||||||
|
|
||||||
|
_RtlInterlockedPushEntrySList16:
|
||||||
|
/* This is a 16 byte header */
|
||||||
|
|
||||||
|
/* 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 ListHead->HeaderType = 1 and ListHead->Init = 1 */
|
||||||
|
mov rcx, rdx
|
||||||
|
or rcx, 0x3
|
||||||
|
|
||||||
|
mov rdx, [r8 + 8]
|
||||||
|
|
||||||
|
_RtlInterlockedPushEntrySListLoop16:
|
||||||
|
|
||||||
|
/* Move ListHead->NextEntry to rbx */
|
||||||
|
mov rbx, rdx
|
||||||
|
and rbx, SLIST16B_NEXTENTY_MASK
|
||||||
|
|
||||||
|
/* Store next pointer in ListEntry->NextEntry */
|
||||||
|
mov [r9], rbx
|
||||||
|
|
||||||
|
/* Copy Depth and Sequence number and adjust Depth */
|
||||||
|
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 */
|
||||||
|
jnz _RtlInterlockedPushEntrySListLoop16
|
||||||
|
|
||||||
|
/* Copy the old NextEntry pointer to rax */
|
||||||
|
mov rax, rdx
|
||||||
|
and rax, SLIST16B_NEXTENTY_MASK
|
||||||
|
|
||||||
|
/* Return */
|
||||||
|
pop rbx
|
||||||
|
ret
|
||||||
|
|
||||||
|
.endproc
|
||||||
|
|
||||||
|
/* PSLIST_ENTRY
|
||||||
|
* NTAPI
|
||||||
|
* RtlInterlockedFlushSList(
|
||||||
|
* IN PSINGLE_LIST_ENTRY ListHead);
|
||||||
|
*/
|
||||||
|
.proc RtlInterlockedFlushSList
|
||||||
|
_ExpInterlockedFlushSList:
|
||||||
|
|
||||||
|
/* Load ListHead->Region into rdx */
|
||||||
|
mov rax, [rcx + 8]
|
||||||
|
|
||||||
|
/* Check what kind of header this is */
|
||||||
|
test rax, SLIST8B_HEADERTYPE_MASK
|
||||||
|
jnz _RtlInterlockedFlushSList16
|
||||||
|
|
||||||
|
/* We have an 8 byte header */
|
||||||
|
|
||||||
|
_RtlInterlockedFlushSListLoop:
|
||||||
|
|
||||||
|
/* Zero ListHead->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 */
|
||||||
|
jnz _RtlInterlockedFlushSListLoop
|
||||||
|
|
||||||
|
/* Use rcx as pointer template */
|
||||||
|
mov rdx, ~SLIST8_POINTER_MASK
|
||||||
|
or rdx, rcx
|
||||||
|
|
||||||
|
/* Combine result and return */
|
||||||
|
or rax, rdx
|
||||||
|
ret
|
||||||
|
|
||||||
|
_RtlInterlockedFlushSList16:
|
||||||
|
/* We have a 16 byte header */
|
||||||
|
push rbx
|
||||||
|
|
||||||
|
mov rdx, [rcx + 8]
|
||||||
|
xor rbx, rbx
|
||||||
|
mov rcx, 0x3
|
||||||
|
|
||||||
|
_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 */
|
||||||
|
jnz _RtlInterlockedFlushSListLoop16
|
||||||
|
|
||||||
|
/* Copy the old NextEntry pointer to rax */
|
||||||
|
mov rax, rdx
|
||||||
|
and rax, SLIST16B_NEXTENTY_MASK
|
||||||
|
|
||||||
|
/* Return */
|
||||||
|
pop rbx
|
||||||
|
ret
|
||||||
|
|
||||||
|
.endproc
|
53
reactos/lib/rtl/amd64/stubs.c
Normal file
53
reactos/lib/rtl/amd64/stubs.c
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
/*
|
||||||
|
* 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>
|
||||||
|
|
||||||
|
/* PUBLIC FUNCTIONS **********************************************************/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @unimplemented
|
||||||
|
*/
|
||||||
|
VOID
|
||||||
|
NTAPI
|
||||||
|
RtlInitializeContext(IN HANDLE ProcessHandle,
|
||||||
|
OUT PCONTEXT ThreadContext,
|
||||||
|
IN PVOID ThreadStartParam OPTIONAL,
|
||||||
|
IN PTHREAD_START_ROUTINE ThreadStartAddress,
|
||||||
|
IN PINITIAL_TEB InitialTeb)
|
||||||
|
{
|
||||||
|
UNIMPLEMENTED;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @unimplemented
|
||||||
|
*/
|
||||||
|
PVOID
|
||||||
|
NTAPI
|
||||||
|
RtlpGetExceptionAddress(VOID)
|
||||||
|
{
|
||||||
|
UNIMPLEMENTED;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @unimplemented
|
||||||
|
*/
|
||||||
|
BOOLEAN
|
||||||
|
NTAPI
|
||||||
|
RtlDispatchException(IN PEXCEPTION_RECORD ExceptionRecord,
|
||||||
|
IN PCONTEXT Context)
|
||||||
|
{
|
||||||
|
UNIMPLEMENTED;
|
||||||
|
return FALSE;
|
||||||
|
}
|
684
reactos/lib/rtl/amd64/unwind.c
Normal file
684
reactos/lib/rtl/amd64/unwind.c
Normal file
|
@ -0,0 +1,684 @@
|
||||||
|
/*
|
||||||
|
* 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 */
|
||||||
|
EndAddress = FunctionEntry->EndAddress + ImageBase;
|
||||||
|
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 & 0x7) + 8;
|
||||||
|
PopReg(&LocalContext, Reg);
|
||||||
|
InstrPtr += 2;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check for retn / retf */
|
||||||
|
if ( (Instr & 0xf7) == 0xc3 )
|
||||||
|
{
|
||||||
|
/* We are finished */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Opcode not allowed for Epilog */
|
||||||
|
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 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 left 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;
|
||||||
|
INT i;
|
||||||
|
PRUNTIME_FUNCTION FunctionEntry;
|
||||||
|
|
||||||
|
DPRINT("Enter RtlWalkFrameChain\n");
|
||||||
|
|
||||||
|
/* 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 < 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Save this frame and continue with new Rip */
|
||||||
|
ControlPc = Context.Rip;
|
||||||
|
Callers[i] = (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);
|
||||||
|
|
||||||
|
if (CallersAddress)
|
||||||
|
{
|
||||||
|
*CallersAddress = (Number >= 3) ? Callers[2] : NULL;
|
||||||
|
}
|
||||||
|
if (CallersCaller)
|
||||||
|
{
|
||||||
|
*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);
|
||||||
|
}
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
|
|
||||||
/* FUNCTIONS ***************************************************************/
|
/* FUNCTIONS ***************************************************************/
|
||||||
|
|
||||||
#if !defined(_M_IX86)
|
#if !defined(_M_IX86) && !defined(_M_AMD64)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* @implemented
|
* @implemented
|
||||||
|
@ -63,6 +63,10 @@ RtlRaiseException(IN PEXCEPTION_RECORD ExceptionRecord)
|
||||||
RtlRaiseStatus(Status);
|
RtlRaiseStatus(Status);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(_M_IX86)
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
#pragma warning(push)
|
#pragma warning(push)
|
||||||
#pragma warning(disable:4717) // RtlRaiseStatus is recursive by design
|
#pragma warning(disable:4717) // RtlRaiseStatus is recursive by design
|
||||||
|
|
|
@ -35,6 +35,17 @@
|
||||||
<file>mem.c</file>
|
<file>mem.c</file>
|
||||||
<file>memgen.c</file>
|
<file>memgen.c</file>
|
||||||
</if>
|
</if>
|
||||||
|
<if property="ARCH" value="amd64">
|
||||||
|
<directory name="amd64">
|
||||||
|
<file>debug_asm.S</file>
|
||||||
|
<file>except_asm.S</file>
|
||||||
|
<file>slist.S</file>
|
||||||
|
<file>unwind.c</file>
|
||||||
|
<file>stubs.c</file>
|
||||||
|
</directory>
|
||||||
|
<file>mem.c</file>
|
||||||
|
<file>memgen.c</file>
|
||||||
|
</if>
|
||||||
<directory name="austin">
|
<directory name="austin">
|
||||||
<file>avl.c</file>
|
<file>avl.c</file>
|
||||||
<file>tree.c</file>
|
<file>tree.c</file>
|
||||||
|
|
|
@ -32,10 +32,12 @@ extern VOID FASTCALL CHECK_PAGED_CODE_RTL(char *file, int line);
|
||||||
#define ROUND_UP(n, align) \
|
#define ROUND_UP(n, align) \
|
||||||
ROUND_DOWN(((ULONG)n) + (align) - 1, (align))
|
ROUND_DOWN(((ULONG)n) + (align) - 1, (align))
|
||||||
|
|
||||||
|
#define RVA(m, b) ((PVOID)((ULONG_PTR)(b) + (ULONG_PTR)(m)))
|
||||||
|
|
||||||
VOID
|
VOID
|
||||||
NTAPI
|
NTAPI
|
||||||
RtlpGetStackLimits(PULONG_PTR StackBase,
|
RtlpGetStackLimits(PULONG_PTR LowLimit,
|
||||||
PULONG_PTR StackLimit);
|
PULONG_PTR HighLimit);
|
||||||
|
|
||||||
PEXCEPTION_REGISTRATION_RECORD
|
PEXCEPTION_REGISTRATION_RECORD
|
||||||
NTAPI
|
NTAPI
|
||||||
|
|
|
@ -20,7 +20,10 @@ NTAPI
|
||||||
RtlInitializeSListHead(IN PSLIST_HEADER ListHead)
|
RtlInitializeSListHead(IN PSLIST_HEADER ListHead)
|
||||||
{
|
{
|
||||||
#ifdef _WIN64
|
#ifdef _WIN64
|
||||||
UNIMPLEMENTED;
|
ListHead->Alignment = 0;
|
||||||
|
ListHead->Region = 0;
|
||||||
|
ListHead->Header8.Init = 1;
|
||||||
|
// ListHead->Header8.HeaderType = 1; // FIXME: depending on cmpxchg16b support?
|
||||||
#else
|
#else
|
||||||
ListHead->Alignment = 0;
|
ListHead->Alignment = 0;
|
||||||
#endif
|
#endif
|
||||||
|
@ -31,8 +34,25 @@ NTAPI
|
||||||
RtlFirstEntrySList(IN const SLIST_HEADER *ListHead)
|
RtlFirstEntrySList(IN const SLIST_HEADER *ListHead)
|
||||||
{
|
{
|
||||||
#ifdef _WIN64
|
#ifdef _WIN64
|
||||||
UNIMPLEMENTED;
|
if (ListHead->Header8.HeaderType)
|
||||||
return NULL;
|
{
|
||||||
|
return (PVOID)(ListHead->Region & ~0xF);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
union {
|
||||||
|
PVOID P;
|
||||||
|
struct {
|
||||||
|
ULONG64 Reserved:4;
|
||||||
|
ULONG64 NextEntry:39;
|
||||||
|
ULONG64 Reserved2:21;
|
||||||
|
} Bits;
|
||||||
|
} Pointer;
|
||||||
|
|
||||||
|
Pointer.P = (PVOID)ListHead;
|
||||||
|
Pointer.Bits.NextEntry = ListHead->Header8.NextEntry;
|
||||||
|
return Pointer.P;
|
||||||
|
}
|
||||||
#else
|
#else
|
||||||
return ListHead->Next.Next;
|
return ListHead->Next.Next;
|
||||||
#endif
|
#endif
|
||||||
|
@ -43,8 +63,8 @@ NTAPI
|
||||||
RtlQueryDepthSList(IN PSLIST_HEADER ListHead)
|
RtlQueryDepthSList(IN PSLIST_HEADER ListHead)
|
||||||
{
|
{
|
||||||
#ifdef _WIN64
|
#ifdef _WIN64
|
||||||
UNIMPLEMENTED;
|
return ListHead->Header8.HeaderType ?
|
||||||
return 0;
|
ListHead->Header16.Sequence : ListHead->Header8.Sequence;
|
||||||
#else
|
#else
|
||||||
return ListHead->Depth;
|
return ListHead->Depth;
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -27,40 +27,33 @@
|
||||||
#define SPECIAL 32 /* 0x */
|
#define SPECIAL 32 /* 0x */
|
||||||
#define LARGE 64 /* use 'ABCDEF' instead of 'abcdef' */
|
#define LARGE 64 /* use 'ABCDEF' instead of 'abcdef' */
|
||||||
#define REMOVEHEX 256 /* use 256 as remve 0x frim BASE 16 */
|
#define REMOVEHEX 256 /* use 256 as remve 0x frim BASE 16 */
|
||||||
typedef struct {
|
typedef union {
|
||||||
unsigned int mantissal:32;
|
struct {
|
||||||
unsigned int mantissah:20;
|
unsigned int mantissal:32;
|
||||||
unsigned int exponent:11;
|
unsigned int mantissah:20;
|
||||||
unsigned int sign:1;
|
unsigned int exponent:11;
|
||||||
|
unsigned int sign:1;
|
||||||
|
};
|
||||||
|
long long AsLongLong;
|
||||||
} double_t;
|
} double_t;
|
||||||
|
|
||||||
|
/* We depend on this being true */
|
||||||
|
C_ASSERT(sizeof(double_t) == sizeof(double));
|
||||||
|
|
||||||
static
|
static
|
||||||
__inline
|
__inline
|
||||||
int
|
int
|
||||||
_isinf(double __x)
|
_isinf(double_t x)
|
||||||
{
|
{
|
||||||
union
|
return ( x.exponent == 0x7ff && ( x.mantissah == 0 && x.mantissal == 0 ));
|
||||||
{
|
|
||||||
double* __x;
|
|
||||||
double_t* x;
|
|
||||||
} x;
|
|
||||||
|
|
||||||
x.__x = &__x;
|
|
||||||
return ( x.x->exponent == 0x7ff && ( x.x->mantissah == 0 && x.x->mantissal == 0 ));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
__inline
|
__inline
|
||||||
int
|
int
|
||||||
_isnan(double __x)
|
_isnan(double_t x)
|
||||||
{
|
{
|
||||||
union
|
return ( x.exponent == 0x7ff && ( x.mantissah != 0 || x.mantissal != 0 ));
|
||||||
{
|
|
||||||
double* __x;
|
|
||||||
double_t* x;
|
|
||||||
} x;
|
|
||||||
x.__x = &__x;
|
|
||||||
return ( x.x->exponent == 0x7ff && ( x.x->mantissah != 0 || x.x->mantissal != 0 ));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -180,14 +173,13 @@ number(char * buf, char * end, long long num, int base, int size, int precision,
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *
|
static char *
|
||||||
numberf(char * buf, char * end, double num, int base, int size, int precision, int type)
|
numberf(char * buf, char * end, double_t num, int base, int size, int precision, int type)
|
||||||
{
|
{
|
||||||
char c,sign,tmp[66];
|
char c,sign,tmp[66];
|
||||||
const char *digits;
|
const char *digits;
|
||||||
const char *small_digits = "0123456789abcdefghijklmnopqrstuvwxyz";
|
const char *small_digits = "0123456789abcdefghijklmnopqrstuvwxyz";
|
||||||
const char *large_digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
const char *large_digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||||
int i;
|
int i;
|
||||||
long long x;
|
|
||||||
|
|
||||||
/* FIXME
|
/* FIXME
|
||||||
the float version of number is direcly copy of number
|
the float version of number is direcly copy of number
|
||||||
|
@ -201,9 +193,9 @@ numberf(char * buf, char * end, double num, int base, int size, int precision, i
|
||||||
c = (type & ZEROPAD) ? '0' : ' ';
|
c = (type & ZEROPAD) ? '0' : ' ';
|
||||||
sign = 0;
|
sign = 0;
|
||||||
if (type & SIGN) {
|
if (type & SIGN) {
|
||||||
if (num < 0) {
|
if (num.sign) {
|
||||||
sign = '-';
|
sign = '-';
|
||||||
num = -num;
|
num.sign = 0;
|
||||||
size--;
|
size--;
|
||||||
} else if (type & PLUS) {
|
} else if (type & PLUS) {
|
||||||
sign = '+';
|
sign = '+';
|
||||||
|
@ -220,15 +212,11 @@ numberf(char * buf, char * end, double num, int base, int size, int precision, i
|
||||||
size--;
|
size--;
|
||||||
}
|
}
|
||||||
i = 0;
|
i = 0;
|
||||||
if (num == 0)
|
if (num.AsLongLong == 0)
|
||||||
tmp[i++] = '0';
|
tmp[i++] = '0';
|
||||||
else while (num != 0)
|
else while (num.AsLongLong != 0)
|
||||||
{
|
{
|
||||||
x = num;
|
tmp[i++] = digits[do_div(&num.AsLongLong,base)];
|
||||||
tmp[i++] = digits[do_div(&x,base)];
|
|
||||||
#ifndef _M_ARM // Missing __floatdidf in CeGCC 0.55 -- GCC 4.4
|
|
||||||
num=x;
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
if (i > precision)
|
if (i > precision)
|
||||||
precision = i;
|
precision = i;
|
||||||
|
@ -389,7 +377,7 @@ int __cdecl _vsnprintf(char *buf, size_t cnt, const char *fmt, va_list args)
|
||||||
{
|
{
|
||||||
int len;
|
int len;
|
||||||
unsigned long long num;
|
unsigned long long num;
|
||||||
double _double;
|
double_t _double;
|
||||||
|
|
||||||
int base;
|
int base;
|
||||||
char *str, *end;
|
char *str, *end;
|
||||||
|
@ -600,7 +588,7 @@ int __cdecl _vsnprintf(char *buf, size_t cnt, const char *fmt, va_list args)
|
||||||
case 'f':
|
case 'f':
|
||||||
case 'g':
|
case 'g':
|
||||||
case 'G':
|
case 'G':
|
||||||
_double = (double)va_arg(args, double);
|
_double = va_arg(args, double_t);
|
||||||
if ( _isnan(_double) ) {
|
if ( _isnan(_double) ) {
|
||||||
s = "Nan";
|
s = "Nan";
|
||||||
len = 3;
|
len = 3;
|
||||||
|
@ -631,7 +619,7 @@ int __cdecl _vsnprintf(char *buf, size_t cnt, const char *fmt, va_list args)
|
||||||
} else {
|
} else {
|
||||||
if ( precision == -1 )
|
if ( precision == -1 )
|
||||||
precision = 6;
|
precision = 6;
|
||||||
str = numberf(str, end, (int)_double, base, field_width, precision, flags);
|
str = numberf(str, end, _double, base, field_width, precision, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
|
|
|
@ -27,40 +27,33 @@
|
||||||
#define SPECIAL 32 /* 0x */
|
#define SPECIAL 32 /* 0x */
|
||||||
#define LARGE 64 /* use 'ABCDEF' instead of 'abcdef' */
|
#define LARGE 64 /* use 'ABCDEF' instead of 'abcdef' */
|
||||||
#define REMOVEHEX 256 /* use 256 as remve 0x frim BASE 16 */
|
#define REMOVEHEX 256 /* use 256 as remve 0x frim BASE 16 */
|
||||||
typedef struct {
|
typedef union {
|
||||||
unsigned int mantissal:32;
|
struct {
|
||||||
unsigned int mantissah:20;
|
unsigned int mantissal:32;
|
||||||
unsigned int exponent:11;
|
unsigned int mantissah:20;
|
||||||
unsigned int sign:1;
|
unsigned int exponent:11;
|
||||||
|
unsigned int sign:1;
|
||||||
|
};
|
||||||
|
long long AsLongLong;
|
||||||
} double_t;
|
} double_t;
|
||||||
|
|
||||||
|
/* We depend on this being true */
|
||||||
|
C_ASSERT(sizeof(double_t) == sizeof(double));
|
||||||
|
|
||||||
static
|
static
|
||||||
__inline
|
__inline
|
||||||
int
|
int
|
||||||
_isinf(double __x)
|
_isinf(double_t x)
|
||||||
{
|
{
|
||||||
union
|
return ( x.exponent == 0x7ff && ( x.mantissah == 0 && x.mantissal == 0 ));
|
||||||
{
|
|
||||||
double* __x;
|
|
||||||
double_t* x;
|
|
||||||
} x;
|
|
||||||
|
|
||||||
x.__x = &__x;
|
|
||||||
return ( x.x->exponent == 0x7ff && ( x.x->mantissah == 0 && x.x->mantissal == 0 ));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
__inline
|
__inline
|
||||||
int
|
int
|
||||||
_isnan(double __x)
|
_isnan(double_t x)
|
||||||
{
|
{
|
||||||
union
|
return ( x.exponent == 0x7ff && ( x.mantissah != 0 || x.mantissal != 0 ));
|
||||||
{
|
|
||||||
double* __x;
|
|
||||||
double_t* x;
|
|
||||||
} x;
|
|
||||||
x.__x = &__x;
|
|
||||||
return ( x.x->exponent == 0x7ff && ( x.x->mantissah != 0 || x.x->mantissal != 0 ));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -179,14 +172,13 @@ number(wchar_t * buf, wchar_t * end, long long num, int base, int size, int prec
|
||||||
}
|
}
|
||||||
|
|
||||||
static wchar_t *
|
static wchar_t *
|
||||||
numberf(wchar_t * buf, wchar_t * end, double num, int base, int size, int precision, int type)
|
numberf(wchar_t * buf, wchar_t * end, double_t num, int base, int size, int precision, int type)
|
||||||
{
|
{
|
||||||
wchar_t c, sign, tmp[66];
|
wchar_t c, sign, tmp[66];
|
||||||
const wchar_t *digits;
|
const wchar_t *digits;
|
||||||
const wchar_t *small_digits = L"0123456789abcdefghijklmnopqrstuvwxyz";
|
const wchar_t *small_digits = L"0123456789abcdefghijklmnopqrstuvwxyz";
|
||||||
const wchar_t *large_digits = L"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
const wchar_t *large_digits = L"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||||
int i;
|
int i;
|
||||||
long long x;
|
|
||||||
|
|
||||||
/* FIXME
|
/* FIXME
|
||||||
the float version of number is direcly copy of number
|
the float version of number is direcly copy of number
|
||||||
|
@ -201,9 +193,9 @@ numberf(wchar_t * buf, wchar_t * end, double num, int base, int size, int precis
|
||||||
c = (type & ZEROPAD) ? L'0' : L' ';
|
c = (type & ZEROPAD) ? L'0' : L' ';
|
||||||
sign = 0;
|
sign = 0;
|
||||||
if (type & SIGN) {
|
if (type & SIGN) {
|
||||||
if (num < 0) {
|
if (num.sign) {
|
||||||
sign = L'-';
|
sign = L'-';
|
||||||
num = -num;
|
num.sign = 0;
|
||||||
size--;
|
size--;
|
||||||
} else if (type & PLUS) {
|
} else if (type & PLUS) {
|
||||||
sign = L'+';
|
sign = L'+';
|
||||||
|
@ -220,15 +212,11 @@ numberf(wchar_t * buf, wchar_t * end, double num, int base, int size, int precis
|
||||||
size--;
|
size--;
|
||||||
}
|
}
|
||||||
i = 0;
|
i = 0;
|
||||||
if (num == 0)
|
if (num.AsLongLong == 0)
|
||||||
tmp[i++] = L'0';
|
tmp[i++] = L'0';
|
||||||
else while (num != 0)
|
else while (num.AsLongLong != 0)
|
||||||
{
|
{
|
||||||
x = num;
|
tmp[i++] = digits[do_div(&num.AsLongLong,base)];
|
||||||
tmp[i++] = digits[do_div(&x,base)];
|
|
||||||
#ifndef _M_ARM // Missing __floatdidf in CeGCC 0.55 -- GCC 4.4
|
|
||||||
num = x;
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
if (i > precision)
|
if (i > precision)
|
||||||
precision = i;
|
precision = i;
|
||||||
|
@ -394,7 +382,7 @@ int __cdecl _vsnwprintf(wchar_t *buf, size_t cnt, const wchar_t *fmt, va_list ar
|
||||||
const char *s;
|
const char *s;
|
||||||
const wchar_t *sw;
|
const wchar_t *sw;
|
||||||
const wchar_t *ss;
|
const wchar_t *ss;
|
||||||
double _double;
|
double_t _double;
|
||||||
|
|
||||||
int flags; /* flags to number() */
|
int flags; /* flags to number() */
|
||||||
|
|
||||||
|
@ -597,7 +585,7 @@ int __cdecl _vsnwprintf(wchar_t *buf, size_t cnt, const wchar_t *fmt, va_list ar
|
||||||
case 'f':
|
case 'f':
|
||||||
case 'g':
|
case 'g':
|
||||||
case 'G':
|
case 'G':
|
||||||
_double = (double)va_arg(args, double);
|
_double = va_arg(args, double_t);
|
||||||
|
|
||||||
if ( _isnan(_double) ) {
|
if ( _isnan(_double) ) {
|
||||||
ss = L"Nan";
|
ss = L"Nan";
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue