Compare commits

...

8 Commits

Author SHA1 Message Date
Timo Kreuzer
08161566d1 [RTL/x64] Handle STATUS_UNWIND_CONSOLIDATE in RtlRestoreContext
It's not entirely correct yet and will probably fail on recursive c++ exceptions, but it fixes basic c++ exception handling.
2024-02-19 16:55:31 +02:00
Timo Kreuzer
426e402c54 [CRT] Rewrite floating point handling for streamout
Fixes some crashes and tests.
2024-02-19 16:55:30 +02:00
Timo Kreuzer
2436f57fd5 hack comdlg32/filedlg.c 2024-02-19 16:55:30 +02:00
Timo Kreuzer
68ab372241 [WS2_32_WINETEST] Prevent test from hanging on reactos 2024-02-19 16:55:29 +02:00
Timo Kreuzer
29b42d0d1f EXP [NTOS] Fix flags stuff in ObpCreateUnnamedHandle 2024-02-19 16:55:29 +02:00
Timo Kreuzer
d1517f9df3 EXP [NTOS] Try to improve the situation about KiServiceExit things
Do not convert back from CONTEXT after DbgkForwardException, because that resets the breakpoint address in the trap frame to AT the int 3, which will cause an infinite loop of break points to happen (e.g. in ntdll_winetest info)
2024-02-19 16:55:29 +02:00
Timo Kreuzer
048db88043 WIP [NTOS] Fix handling of non-volatiles in trap vs exception frame 2024-02-19 16:55:28 +02:00
Timo Kreuzer
7f2ed4d02f [NTOS] Fix x64 definition of MMPFN
Adjust the definition of COLORED_LIST_HEAD to always match the new MI_PFN_BITS define.
2024-02-19 16:55:28 +02:00
12 changed files with 601 additions and 219 deletions

View File

@@ -1335,7 +1335,9 @@ START_TEST(filedlg)
test_DialogCancel();
test_create_view_window2();
test_create_view_template();
#ifndef _M_AMD64 // FIXME: rsrc section is RO in MSVC builds, it somehow works on 2k3 x64
test_arrange();
#endif
test_resize();
test_ok();
test_getfolderpath();

View File

@@ -8431,7 +8431,11 @@ todo_wine
iret = connect(connector, (struct sockaddr*)&bindAddress, sizeof(bindAddress));
ok(iret == 0, "connecting to accepting socket failed, error %d\n", WSAGetLastError());
#ifdef __REACTOS__
dwret = WaitForSingleObject(overlapped.hEvent, 3000);
#else
dwret = WaitForSingleObject(overlapped.hEvent, INFINITE);
#endif
ok(dwret == WAIT_OBJECT_0, "Waiting for accept event failed with %d + errno %d\n", dwret, GetLastError());
bret = GetOverlappedResult((HANDLE)listener, &overlapped, &bytesReturned, FALSE);

View File

@@ -369,6 +369,12 @@ typedef struct _MMPFNENTRY
USHORT ParityError:1;
} MMPFNENTRY;
#ifdef _WIN64
#define MI_PFN_BITS 57
#else
#define MI_PFN_BITS 25
#endif
// Mm internal
typedef struct _MMPFN
{
@@ -402,6 +408,9 @@ typedef struct _MMPFN
USHORT ShortFlags;
} e2;
} u3;
#ifdef _WIN64
ULONG UsedPageTableEntries;
#endif
union
{
MMPTE OriginalPte;
@@ -415,7 +424,7 @@ typedef struct _MMPFN
ULONG_PTR EntireFrame;
struct
{
ULONG_PTR PteFrame:25;
ULONG_PTR PteFrame : MI_PFN_BITS;
ULONG_PTR InPageError:1;
ULONG_PTR VerifierAllocation:1;
ULONG_PTR AweAllocation:1;

View File

@@ -36,11 +36,11 @@ KeContextToTrapFrame(IN PCONTEXT Context,
if (ContextFlags & CONTEXT_INTEGER)
{
TrapFrame->Rax = Context->Rax;
TrapFrame->Rbx = Context->Rbx;
//TrapFrame->Rbx = Context->Rbx;
TrapFrame->Rcx = Context->Rcx;
TrapFrame->Rdx = Context->Rdx;
TrapFrame->Rsi = Context->Rsi;
TrapFrame->Rdi = Context->Rdi;
//TrapFrame->Rsi = Context->Rsi;
//TrapFrame->Rdi = Context->Rdi;
TrapFrame->Rbp = Context->Rbp;
TrapFrame->R8 = Context->R8;
TrapFrame->R9 = Context->R9;
@@ -48,6 +48,9 @@ KeContextToTrapFrame(IN PCONTEXT Context,
TrapFrame->R11 = Context->R11;
if (ExceptionFrame)
{
ExceptionFrame->Rbx = Context->Rbx;
ExceptionFrame->Rsi = Context->Rsi;
ExceptionFrame->Rdi = Context->Rdi;
ExceptionFrame->R12 = Context->R12;
ExceptionFrame->R13 = Context->R13;
ExceptionFrame->R14 = Context->R14;

View File

@@ -93,7 +93,7 @@ KeInitExceptions(VOID)
}
static
VOID
BOOLEAN
KiDispatchExceptionToUser(
IN PKTRAP_FRAME TrapFrame,
IN PCONTEXT Context,
@@ -144,35 +144,35 @@ KiDispatchExceptionToUser(
EXCEPTION_EXECUTE_HANDLER)
{
// FIXME: handle stack overflow
//__debugbreak();
/* Nothing we can do here */
_disable();
_SEH2_YIELD(return);
_SEH2_YIELD(return FALSE);
}
_SEH2_END;
/* Now set the two params for the user-mode dispatcher */
TrapFrame->Rcx = (ULONG64)&UserStack->ExceptionRecord;
TrapFrame->Rdx = (ULONG64)&UserStack->Context;
Context->Rcx = (ULONG64)&UserStack->ExceptionRecord;
Context->Rdx = (ULONG64)&UserStack->Context;
/* Set new Stack Pointer */
TrapFrame->Rsp = UserRsp;
Context->Rsp = UserRsp;
/* Force correct segments */
TrapFrame->SegCs = KGDT64_R3_CODE | RPL_MASK;
TrapFrame->SegDs = KGDT64_R3_DATA | RPL_MASK;
TrapFrame->SegEs = KGDT64_R3_DATA | RPL_MASK;
TrapFrame->SegFs = KGDT64_R3_CMTEB | RPL_MASK;
TrapFrame->SegGs = KGDT64_R3_DATA | RPL_MASK;
TrapFrame->SegSs = KGDT64_R3_DATA | RPL_MASK;
Context->SegCs = KGDT64_R3_CODE | RPL_MASK;
Context->SegDs = KGDT64_R3_DATA | RPL_MASK;
Context->SegEs = KGDT64_R3_DATA | RPL_MASK;
Context->SegFs = KGDT64_R3_CMTEB | RPL_MASK;
Context->SegGs = KGDT64_R3_DATA | RPL_MASK;
Context->SegSs = KGDT64_R3_DATA | RPL_MASK;
/* Set RIP to the User-mode Dispatcher */
TrapFrame->Rip = (ULONG64)KeUserExceptionDispatcher;
Context->Rip = (ULONG64)KeUserExceptionDispatcher;
_disable();
/* Exit to usermode */
KiServiceExit2(TrapFrame);
return TRUE;
}
static
@@ -361,10 +361,14 @@ KiDispatchException(IN PEXCEPTION_RECORD ExceptionRecord,
/* Forward exception to user mode debugger */
if (DbgkForwardException(ExceptionRecord, TRUE, FALSE)) return;
/* Forward exception to user mode (does not return, if successful) */
KiDispatchExceptionToUser(TrapFrame, &Context, ExceptionRecord);
/* Forward exception to user mode */
if (KiDispatchExceptionToUser(TrapFrame, &Context, ExceptionRecord))
{
goto Handled;
}
/* Failed to dispatch, fall through for second chance handling */
//__debugbreak();
}
/* Try second chance */
@@ -409,6 +413,7 @@ NTAPI
KeRaiseUserException(IN NTSTATUS ExceptionCode)
{
UNIMPLEMENTED;
//__debugbreak();
return STATUS_UNSUCCESSFUL;
}

View File

@@ -900,13 +900,20 @@ no_user_apc_pending:
/*!
* VOID
* DECLSPEC_NORETURN
* KiServiceExit(IN PKTRAP_FRAME TrapFrame, IN NTSTATUS Status));
* KiServiceExit(
* _In_ PKTRAP_FRAME TrapFrame@<rcx>,
* _In_ NTSTATUS Status@<edx>);
*
* Returns from a systemcall to user mode.
* Non-volatile registers will not be set.
* USed by KiUserModeCallout (x64), NtRaiseException, NtContinue
*/
PUBLIC KiServiceExit
.PROC KiServiceExit
.endprolog
lea rsp, [rcx - MAX_SYSCALL_PARAM_SIZE]
mov rax, rdx
jmp KiSystemServiceExit
.ENDP
@@ -915,7 +922,10 @@ PUBLIC KiServiceExit
/*!
* VOID
* DECLSPEC_NORETURN
* KiServiceExit2(IN PKTRAP_FRAME TrapFrame);
* KiServiceExit2(
* _In_ PKTRAP_FRAME TrapFrame@<rcx>);
*
* Returns from
*/
PUBLIC KiServiceExit2
.PROC KiServiceExit2
@@ -926,6 +936,11 @@ PUBLIC KiServiceExit2
mov rsp, rcx
.ENDP
/*
* Internal function. Exits to user-mode with rsp pointing to the trap frame.
* All non-volatile register context must be set up already.
* Used by KiInitializeContextThread to set up the init path for a new thread.
*/
PUBLIC KiServiceExit3
.PROC KiServiceExit3
.PUSHFRAME

View File

@@ -206,24 +206,18 @@ extern const ULONG MmProtectToValue[32];
//
#define MI_INITIAL_SESSION_IDS 64
#if defined(_M_IX86) || defined(_M_ARM)
//
// PFN List Sentinel
//
#ifdef _WIN64
#define LIST_HEAD 0xFFFFFFFFFFFFFFFFLL
#else
#define LIST_HEAD 0xFFFFFFFF
#endif
//
// Because GCC cannot automatically downcast 0xFFFFFFFF to lesser-width bits,
// we need a manual definition suited to the number of bits in the PteFrame.
// This is used as a LIST_HEAD for the colored list
//
#define COLORED_LIST_HEAD ((1 << 25) - 1) // 0x1FFFFFF
#elif defined(_M_AMD64)
#define LIST_HEAD 0xFFFFFFFFFFFFFFFFLL
#define COLORED_LIST_HEAD ((1ULL << 57) - 1) // 0x1FFFFFFFFFFFFFFLL
#else
#error Define these please!
#endif
#define COLORED_LIST_HEAD (((ULONG_PTR)1 << MI_PFN_BITS) - 1)
//
// Returns the color of a page

View File

@@ -1395,6 +1395,11 @@ ObpCreateUnnamedHandle(IN PVOID Object,
/* Save the access mask */
NewEntry.GrantedAccess = GrantedAccess;
if (NewEntry.ObAttributes & OBJ_PROTECT_CLOSE)
{
NewEntry.GrantedAccess |= ObpAccessProtectCloseBit;
NewEntry.ObAttributes &= ~OBJ_PROTECT_CLOSE;
}
/*
* Create the actual handle. We'll need to do this *after* calling

View File

@@ -57,7 +57,7 @@ MACRO(EnterTrap, Flags)
lea rbp, [rsp]
.setframe rbp, 0
if (Flags AND TF_NONVOLATILES)
if (Flags AND TF_NONVOLATILES) // ???
/* Save non-volatile registers */
mov [rbp + KTRAP_FRAME_Rbx], rbx
.savereg rbx, KTRAP_FRAME_Rbx
@@ -228,9 +228,9 @@ kernel_mode_return:
if (Flags AND TF_NONVOLATILES)
/* Restore non-volatile registers */
mov rbx, [rbp + KTRAP_FRAME_Rbx]
mov rdi, [rbp + KTRAP_FRAME_Rdi]
mov rsi, [rbp + KTRAP_FRAME_Rsi]
//mov rbx, [rbp + KTRAP_FRAME_Rbx]
//mov rdi, [rbp + KTRAP_FRAME_Rdi]
//mov rsi, [rbp + KTRAP_FRAME_Rsi]
endif
if (Flags AND TF_VOLATILES)

View File

@@ -13,6 +13,14 @@
#include <strings.h>
#include <math.h>
#include <float.h>
#include <limits.h>
#include <minmax.h>
#if DBG && defined(_MSC_VER)
#define assert(x) if (!(x)) __int2c()
#else
#define assert(x)
#endif
#ifdef _UNICODE
# define streamout wstreamout
@@ -64,172 +72,14 @@ enum
(flags & FLAG_SHORT) ? (unsigned short)va_arg(argptr, int) : \
va_arg(argptr, unsigned int)
#define va_arg_ffp(argptr, flags) \
(flags & FLAG_LONGDOUBLE) ? va_arg(argptr, long double) : \
va_arg(argptr, double)
#define get_exp(f) (int)floor(f == 0 ? 0 : (f >= 0 ? log10(f) : log10(-f)))
#define round(x) floor((x) + 0.5)
#ifndef _USER32_WSPRINTF
void
#ifdef _LIBCNT_
/* Due to restrictions in kernel mode regarding the use of floating point,
we prevent it from being inlined */
__declspec(noinline)
#endif
format_float(
TCHAR chr,
unsigned int flags,
int precision,
TCHAR **string,
const TCHAR **prefix,
va_list *argptr)
{
static const TCHAR digits_l[] = _T("0123456789abcdef0x");
static const TCHAR digits_u[] = _T("0123456789ABCDEF0X");
static const TCHAR _nan[] = _T("#QNAN");
static const TCHAR _infinity[] = _T("#INF");
const TCHAR *digits = digits_l;
int exponent = 0, sign;
long double fpval, fpval2;
int padding = 0, num_digits, val32, base = 10;
/* Normalize the precision */
if (precision < 0) precision = 6;
else if (precision > 17)
{
padding = precision - 17;
precision = 17;
}
/* Get the float value and calculate the exponent */
fpval = va_arg_ffp(*argptr, flags);
exponent = get_exp(fpval);
sign = fpval < 0 ? -1 : 1;
switch (chr)
{
case _T('G'):
digits = digits_u;
case _T('g'):
if (precision > 0) precision--;
if (exponent < -4 || exponent >= precision) goto case_e;
/* Shift the decimal point and round */
fpval2 = round(sign * fpval * pow(10., precision));
/* Skip trailing zeroes */
while (precision && (unsigned __int64)fpval2 % 10 == 0)
{
precision--;
fpval2 /= 10;
}
break;
case _T('E'):
digits = digits_u;
case _T('e'):
case_e:
/* Shift the decimal point and round */
fpval2 = round(sign * fpval * pow(10., precision - exponent));
/* Compensate for changed exponent through rounding */
if (fpval2 >= (unsigned __int64)pow(10., precision + 1))
{
exponent++;
fpval2 = round(sign * fpval * pow(10., precision - exponent));
}
val32 = exponent >= 0 ? exponent : -exponent;
// FIXME: handle length of exponent field:
// http://msdn.microsoft.com/de-de/library/0fatw238%28VS.80%29.aspx
num_digits = 3;
while (num_digits--)
{
*--(*string) = digits[val32 % 10];
val32 /= 10;
}
/* Sign for the exponent */
*--(*string) = exponent >= 0 ? _T('+') : _T('-');
/* Add 'e' or 'E' separator */
*--(*string) = digits[0xe];
break;
case _T('A'):
digits = digits_u;
case _T('a'):
// base = 16;
// FIXME: TODO
case _T('f'):
default:
/* Shift the decimal point and round */
fpval2 = round(sign * fpval * pow(10., precision));
break;
}
/* Handle sign */
if (fpval < 0)
{
*prefix = _T("-");
}
else if (flags & FLAG_FORCE_SIGN)
*prefix = _T("+");
else if (flags & FLAG_FORCE_SIGNSP)
*prefix = _T(" ");
/* Handle special cases first */
if (_isnan(fpval))
{
(*string) -= sizeof(_nan) / sizeof(TCHAR) - 1;
_tcscpy((*string), _nan);
fpval2 = 1;
}
else if (!_finite(fpval))
{
(*string) -= sizeof(_infinity) / sizeof(TCHAR) - 1;
_tcscpy((*string), _infinity);
fpval2 = 1;
}
else
{
/* Zero padding */
while (padding-- > 0) *--(*string) = _T('0');
/* Digits after the decimal point */
num_digits = precision;
while (num_digits-- > 0)
{
*--(*string) = digits[(unsigned __int64)fpval2 % 10];
fpval2 /= base;
}
}
if (precision > 0 || flags & FLAG_SPECIAL)
*--(*string) = _T('.');
/* Digits before the decimal point */
do
{
*--(*string) = digits[(unsigned __int64)fpval2 % base];
fpval2 /= base;
}
while ((unsigned __int64)fpval2);
}
#endif
static
int
streamout_char(FILE *stream, int chr)
{
#if !defined(_USER32_WSPRINTF)
if ((stream->_flag & _IOSTRG) && (stream->_base == NULL))
if ((stream->_flag & _IOSTRG) && (stream->_base == NULL))
return 1;
#endif
#if defined(_USER32_WSPRINTF) || defined(_LIBCNT_)
@@ -255,8 +105,8 @@ streamout_astring(FILE *stream, const char *string, size_t count)
int written = 0;
#if !defined(_USER32_WSPRINTF)
if ((stream->_flag & _IOSTRG) && (stream->_base == NULL))
return count;
if ((stream->_flag & _IOSTRG) && (stream->_base == NULL))
return (int)count;
#endif
while (count--)
@@ -283,8 +133,8 @@ streamout_wstring(FILE *stream, const wchar_t *string, size_t count)
int written = 0;
#if defined(_UNICODE) && !defined(_USER32_WSPRINTF)
if ((stream->_flag & _IOSTRG) && (stream->_base == NULL))
return count;
if ((stream->_flag & _IOSTRG) && (stream->_base == NULL))
return (int)count;
#endif
while (count--)
@@ -315,6 +165,484 @@ streamout_wstring(FILE *stream, const wchar_t *string, size_t count)
#define streamout_string streamout_astring
#endif
#ifndef _USER32_WSPRINTF
// Base 2 exponent divided by 8 is base 16 exponent
#define DBL_MAX_16_EXP (DBL_MAX_EXP / 8)
// A double has 52 fraction bits, which is 14 hex digits
#define DBL_DIG_HEX 14
#define DBL_MAX_DIGITS_10 17
#define DBL_MAX_DIGITS_16 14
static
int
get_exponent(double fpval, int base)
{
int exponent;
if (fpval == 0.)
{
exponent = 0;
}
else if (base == 10)
{
exponent = (int)floor(log10(fpval));
assert(exponent <= DBL_MAX_10_EXP);
}
else
{
unsigned __int64 fp_bits = *(unsigned __int64*)&fpval;
int exponent2 = (int)((fp_bits >> 52) & 0x7ff);
exponent2 -= 1023;
exponent = (int)(exponent2 / 8);
assert(exponent <= DBL_MAX_16_EXP);
}
return exponent;
}
static
int
get_dbl_digits(
unsigned char digit_buffer[DBL_MAX_DIGITS_10],
double fpval,
int base,
int exponent,
int *pnum_digits)
{
int num_digits = *pnum_digits;
/* Only base 10 (dec) and 16 (hex) are valid */
assert((base == 10) || (base == 16));
/* fpval must be positive! */
assert(fpval >= 0.);
/* Must fit into the buffer */
assert(num_digits <= DBL_MAX_DIGITS_10);
/* Calculate the maximum divisor */
double divisor = pow(10.0, exponent);
/* Calculate the digits */
double remainder = fpval;
for (int i = 0; i < num_digits; i++)
{
int digit = (int)(remainder / divisor);
digit_buffer[i] = digit;
remainder -= digit * divisor;
divisor /= 10.0;
}
/* Round up */
int trailing_digit = (int)(remainder / divisor);
if (trailing_digit >= 5)
{
int carry = 1;
for (int i = num_digits - 1; i >= 0; i--)
{
digit_buffer[i] += carry;
if (digit_buffer[i] == 10)
{
digit_buffer[i] = 0;
carry = 1;
}
else
{
carry = 0;
}
}
/* If we carried over the first digit, we need to shift the digits */
if (carry)
{
assert(num_digits < DBL_MAX_DIGITS_10);
for (int i = num_digits; i > 0; i--)
{
digit_buffer[i] = digit_buffer[i - 1];
}
digit_buffer[0] = 1;
exponent++;
num_digits++;
}
}
/* Strip trailing zeroes */
while ((num_digits > 0) && (digit_buffer[num_digits - 1] == 0))
{
num_digits--;
}
*pnum_digits = num_digits;
return exponent;
}
static
int
stramout_dbl_digits(
FILE* stream,
const TCHAR* dig_chars,
const char * inv_str,
unsigned int flags,
const unsigned char dig_buffer[DBL_MAX_DIGITS_10],
int num_real_digits,
int num_int_digits,
int num_frac_digits,
int first_real_digit,
char use_frac_padding)
{
int current_digit = 0;
/* Check if we need to insert a virtual 0 */
if (first_real_digit > 0)
{
/* This can only happen when exponent < 0 */
assert(num_int_digits == 1);
/* Output virtual 0 integer digit */
streamout_char(stream, dig_chars[0]);
current_digit++;
}
else
{
const int num_real_int_digits = min(num_int_digits, num_real_digits);
current_digit += num_real_int_digits;
for (int i = 0; i < num_real_int_digits; i++)
{
streamout_char(stream, dig_chars[dig_buffer[i]]);
}
/* Output optional right 0 padding */
const int right_padding = num_int_digits - num_real_int_digits;
current_digit += max(right_padding, 0);
for (int i = 0; i < right_padding; i++)
{
streamout_char(stream, '0');
}
}
/* We print the dot when there are fraction digits or the # flag was used */
if ((num_frac_digits > 0) || ((flags & FLAG_SPECIAL) != 0))
{
streamout_char(stream, '.');
}
/* Only output fraction digits, if precision is > 0 */
if (num_frac_digits > 0)
{
int num_real_frac_digits = num_real_digits - num_int_digits;
/* Check for invalid numbers */
if (inv_str != 0)
{
const int inv_str_len = (int)strlen(inv_str);
num_real_frac_digits = min(inv_str_len, num_frac_digits);
for (int i = 0; i < num_real_frac_digits; i++)
{
streamout_char(stream, inv_str[i]);
current_digit++;
}
}
else
{
/* Output optional 0 chars before real digits begin */
const int left_padding = first_real_digit - current_digit;
current_digit += max(left_padding, 0);
for (int i = 0; i < left_padding; i++)
{
streamout_char(stream, '0');
}
/* Output remaining real digits */
const int start_digit = current_digit - first_real_digit;
for (int i = start_digit; i < num_real_digits; i++)
{
streamout_char(stream, dig_chars[dig_buffer[i]]);
current_digit++;
}
}
/* Pad right with '0' for additional precision */
if (use_frac_padding)
{
const int right_padding = num_frac_digits + num_int_digits - current_digit;
for (int i = 0; i < right_padding; i++)
{
streamout_char(stream, '0');
current_digit++;
}
}
}
/* Return the number of written characters */
return current_digit + (num_frac_digits > 0);
}
static
int
#ifdef _LIBCNT_
/* Due to restrictions in kernel mode regarding the use of floating point,
we prevent it from being inlined */
__declspec(noinline)
#endif
streamout_double(
FILE* stream,
char format,
unsigned __int64 fp_bits,
unsigned int flags,
int width,
int precision)
{
const char use_frac_padding = (format != 'g');// || use_exp;
static const char _qnan[] = "#QNAN";
static const char _snan[] = "#SNAN";
static const char _ind[] = "#IND";
static const char _infinity[] = "#INF";
const char* inv_str = 0;
static const TCHAR dig_chars_l[] = _T("0123456789abcdefp0x");
static const TCHAR dig_chars_u[] = _T("0123456789ABCDEFP0X");
const TCHAR* dig_chars = dig_chars_l;
unsigned char dig_buffer[DBL_MAX_DIGITS_10];
int base = 10;
int use_exp_format = 0;
char sign_char = 0;
int exponent;
int rounded_exponent;
int width_exp;
int num_int_digits;
int num_frac_digits;
int first_real_digit;
int num_digits;
/* Convert to an actual double */
double fpval = *(double*)&fp_bits;
/* Check for upper case digits to use */
if ((format == 'E') || (format == 'F') || (format == 'G') || (format == 'A'))
{
dig_chars = dig_chars_u;
format = format - 'A' + 'a';
}
/* Check for base 16 (hex) */
if (format == 'a')
{
base = 16;
}
/* Check for default precision */
if (precision < 0) precision = 6;
/* Get sign and normalize fpval to absolute */
if (fp_bits & 0x8000000000000000ULL)
{
sign_char = '-';
fpval = -fpval;
}
else if (flags & FLAG_FORCE_SIGN)
{
sign_char = '+';
}
else if (flags & FLAG_FORCE_SIGNSP)
{
sign_char = ' ';
}
const int width_sign = (sign_char != 0) ? 1 : 0;
/* Handle NAN / INF */
if (_isnan(fpval))
{
if (fp_bits == 0xFFF8000000000000ULL)
{
inv_str = _ind;
}
else if (fp_bits & 0x0008000000000000ULL)
{
inv_str = _qnan;
}
else
{
inv_str = _snan;
}
fpval = 1.;
}
else if (!_finite(fpval))
{
inv_str = _infinity;
fpval = 1.;
}
/* Calculate the exponent (i.e. digits before decimal point) */
exponent = get_exponent(fpval, base);
retry:
/* Check whether to ise the exponent format */
if (format == 'g')
{
use_exp_format = ((exponent < -4) || (exponent >= precision));
}
else if (format == 'f')
{
use_exp_format = 0;
}
else
{
use_exp_format = 1;
}
/* Check for explicit exponent format */
if (use_exp_format)
{
width_exp = 5;
/* One digit before the decimal point */
num_int_digits = 1;
/* Precision includes the integer digit */
first_real_digit = 0;
}
else
{
width_exp = 0;
/* Integer digits based on exponent, at least 1 */
num_int_digits = max(exponent + 1, 1);
/* First real digit based on exponent */
first_real_digit = max(-exponent, 0);
}
if (format == 'g')
{
num_frac_digits = max(precision - num_int_digits, 0);
}
else
{
/* Precision is the number of fractional digits */
num_frac_digits = precision;
}
num_digits = num_int_digits + num_frac_digits;
/* Get max number of actual digits */
const int max_real_digits = (base == 16) ? DBL_MAX_DIGITS_16 : DBL_MAX_DIGITS_10;
/* Calculate the number of real digits to return */
int num_real_digits = min(num_digits - first_real_digit, max_real_digits);
/* Get the digits (0 based) */
rounded_exponent = get_dbl_digits(dig_buffer, fpval, base, exponent, &num_real_digits);
/* If the expoent changed due to rounding, we need to try again */
if (rounded_exponent != exponent)
{
assert(rounded_exponent > exponent);
exponent = rounded_exponent;
goto retry;
}
/* Special handling for special numbers */
if (inv_str != NULL)
{
num_real_digits = (int)strlen(inv_str) + 1;
}
/* In the g format we need to handle stripped trailing zeroes */
if ((format == 'g'))
{
int max_digits = first_real_digit + num_real_digits;
num_frac_digits = max(max_digits - num_int_digits, 0);
num_digits = num_int_digits + num_frac_digits;
}
/* Calculate widths */
int width_dot = ((num_frac_digits > 0) || (flags & FLAG_SPECIAL)) ? 1 : 0;
int width_of_number = width_sign + num_digits + width_dot + width_exp;
/* Output left space padding */
if (((flags & FLAG_ALIGN_LEFT) == 0) &&
((flags & FLAG_PAD_ZERO) == 0) &&
(width > width_of_number))
{
const int padding = width - width_of_number;
for (int i = 0; i < padding; i++)
{
streamout_char(stream, ' ');
}
}
/* Output sign */
if (sign_char != 0)
{
streamout_char(stream, sign_char);
}
/* Output hex prefix */
if (format == 'a')
{
streamout_string(stream, &dig_chars[0x11], 2);
}
/* Output left 0 padding */
if (((flags & FLAG_ALIGN_LEFT) == 0) &&
((flags & FLAG_PAD_ZERO) != 0) &&
(width > width_of_number))
{
const int padding = width - width_of_number;
for (int i = 0; i < padding; i++)
{
streamout_char(stream, '0');
}
}
/* Output the digits */
stramout_dbl_digits(
stream,
dig_chars,
inv_str,
flags,
dig_buffer,
num_real_digits,
num_int_digits,
num_frac_digits,
first_real_digit,
use_frac_padding);
/* Output the exponent */
if (use_exp_format)
{
streamout_char(stream, format == 'a' ? dig_chars[0x10] : dig_chars[0xe]);
streamout_char(stream, (exponent >= 0) ? '+' : '-');
exponent = (exponent < 0) ? -exponent : exponent;
assert(exponent < 1000);
streamout_char(stream, dig_chars[exponent / 100]);
exponent %= 100;
streamout_char(stream, dig_chars[exponent / 10]);
exponent %= 10;
streamout_char(stream, dig_chars[exponent]);
}
/* Output right padding */
if (((flags & FLAG_ALIGN_LEFT) != 0) &&
(width > width_of_number))
{
const int padding = width - width_of_number;
for (int i = 0; i < padding; i++)
{
streamout_char(stream, ' ');
}
}
return max(width, width_of_number);
}
#endif // _USER32_WSPRINTF
#ifdef _USER32_WSPRINTF
# define USE_MULTISIZE 0
#else
@@ -332,7 +660,7 @@ streamout(FILE *stream, const TCHAR *format, va_list argptr)
TCHAR chr, *string;
STRING *nt_string;
const TCHAR *digits, *prefix;
int base, fieldwidth, precision, padding;
int base, fieldwidth, precision, padding, rpadding = 0;
size_t prefixlen, len;
int written = 1, written_all = 0;
unsigned int flags;
@@ -558,11 +886,11 @@ streamout(FILE *stream, const TCHAR *format, va_list argptr)
#else
flags &= ~FLAG_WIDECHAR;
#endif
/* Use external function, one for kernel one for user mode */
format_float(chr, flags, precision, &string, &prefix, &argptr);
len = _tcslen(string);
precision = 0;
break;
/* Capture the double as 64bit int to avoid changing it with the FPU */
unsigned __int64 fpval = va_arg(argptr, unsigned __int64);
written = streamout_double(stream, chr, fpval, flags, fieldwidth, precision);
written_all += written;
continue;
#endif
case _T('d'):
@@ -679,15 +1007,13 @@ streamout(FILE *stream, const TCHAR *format, va_list argptr)
if (written == -1) return -1;
written_all += written;
#if 0 && SUPPORT_FLOAT
/* Optional right '0' padding */
while (precision-- > 0)
while (rpadding-- > 0)
{
if ((written = streamout_char(stream, _T('0'))) == 0) return -1;
written_all += written;
len++;
}
#endif
/* Optional right padding */
if (flags & FLAG_ALIGN_LEFT)
@@ -698,7 +1024,6 @@ streamout(FILE *stream, const TCHAR *format, va_list argptr)
written_all += written;
}
}
}
if (written == -1) return -1;

View File

@@ -107,22 +107,19 @@ PUBLIC RtlCaptureContext
.ENDP
/*
* VOID NTAPI
* RtlRestoreContext(
* _In_ PCONTEXT ContextRecord@<rcx>,
* PEXCEPTION_RECORD *ExceptionRecord@<rdx>);
* VOID
* RtlpRestoreContextInternal(
* _In_ PCONTEXT ContextRecord@<rcx>);
*/
PUBLIC RtlRestoreContext
.PROC RtlRestoreContext
PUBLIC RtlpRestoreContextInternal
.PROC RtlpRestoreContextInternal
/* Allocate space */
sub rsp, HEX(8)
.ALLOCSTACK 8
.ENDPROLOG
// TODO: Handle ExceptionRecord
/* Restore legacy floating point registers (It's slow, so do it first) */
/* Restore legacy floating point registers (It is slow, so do it first) */
ldmxcsr [rcx + CxMxCsr]
fxrstor [rcx + CxFltSave]

View File

@@ -1132,3 +1132,26 @@ RtlSetUnwindContext(
*ContextPointers.Xmm14 = Context->Xmm14;
*ContextPointers.Xmm15 = Context->Xmm15;
}
VOID
RtlpRestoreContextInternal(
_In_ PCONTEXT ContextRecord);
VOID
RtlRestoreContext(
_In_ PCONTEXT ContextRecord,
_In_ PEXCEPTION_RECORD ExceptionRecord)
{
if (ExceptionRecord != NULL)
{
if ((ExceptionRecord->ExceptionCode == STATUS_UNWIND_CONSOLIDATE) &&
(ExceptionRecord->NumberParameters >= 1))
{
PVOID (*Consolidate)(EXCEPTION_RECORD*) = (PVOID)ExceptionRecord->ExceptionInformation[0];
// FIXME: This should be called through an asm wrapper to allow handling recursive unwinding
ContextRecord->Rip = (ULONG64)Consolidate(ExceptionRecord);
}
}
RtlpRestoreContextInternal(ContextRecord);
}