ntdll: Fix handling of floating point arguments in relay debugging on ARM.

Signed-off-by: Alexandre Julliard <julliard@winehq.org>
oldstable
Alexandre Julliard 2017-12-14 11:44:57 +01:00
parent 7e9f1878db
commit 5e3534ee41
2 changed files with 92 additions and 38 deletions

View File

@ -468,6 +468,10 @@ DECLSPEC_HIDDEN void * WINAPI relay_trace_entry( struct relay_descr *descr, unsi
struct relay_private_data *data = descr->private;
struct relay_entry_point *entry_point = data->entry_points + ordinal;
unsigned int i, pos;
#ifndef __SOFTFP__
unsigned int float_pos = 0, double_pos = 0;
const union fpregs { float s[16]; double d[8]; } *fpstack = (const union fpregs *)stack - 1;
#endif
TRACE( "\1Call %s(", func_name( data, ordinal ));
@ -476,6 +480,7 @@ DECLSPEC_HIDDEN void * WINAPI relay_trace_entry( struct relay_descr *descr, unsi
switch (arg_types[i])
{
case 'j': /* int64 */
pos = (pos + 1) & ~1;
TRACE( "%x%08x", stack[pos+1], stack[pos] );
pos += 2;
break;
@ -489,6 +494,30 @@ DECLSPEC_HIDDEN void * WINAPI relay_trace_entry( struct relay_descr *descr, unsi
case 'w': /* wstr */
trace_string_w( stack[pos++] );
break;
case 'f': /* float */
#ifndef __SOFTFP__
if (!(float_pos % 2)) float_pos = max( float_pos, double_pos * 2 );
if (float_pos < 16)
{
TRACE( "%g", fpstack->s[float_pos++] );
break;
}
#endif
TRACE( "%g", *(const float *)&stack[pos++] );
break;
case 'd': /* double */
#ifndef __SOFTFP__
double_pos = max( (float_pos + 1) / 2, double_pos );
if (double_pos < 8)
{
TRACE( "%g", fpstack->d[double_pos++] );
break;
}
#endif
pos = (pos + 1) & ~1;
TRACE( "%g", *(const double *)&stack[pos] );
pos += 2;
break;
case 'i': /* long */
default:
TRACE( "%08x", stack[pos++] );
@ -496,6 +525,14 @@ DECLSPEC_HIDDEN void * WINAPI relay_trace_entry( struct relay_descr *descr, unsi
}
if (!is_ret_val( arg_types[i+1] )) TRACE( "," );
}
#ifndef __SOFTFP__
if (float_pos || double_pos)
{
pos |= 0x80000000;
stack = (const DWORD *)fpstack; /* retaddr is below the fp regs */
}
#endif
*nb_args = pos;
TRACE( ") ret=%08x\n", stack[-1] );
return entry_point->orig_func;
@ -519,39 +556,56 @@ DECLSPEC_HIDDEN void WINAPI relay_trace_exit( struct relay_descr *descr, unsigne
TRACE( " retval=%08x ret=%08x\n", (UINT)retval, retaddr );
}
extern LONGLONG CDECL call_entry_point( void *func, int nb_args, const DWORD *args );
__ASM_GLOBAL_FUNC( call_entry_point,
extern LONGLONG WINAPI relay_call( struct relay_descr *descr, unsigned int idx, const DWORD *stack );
__ASM_GLOBAL_FUNC( relay_call,
".arm\n\t"
"push {r4, r5, LR}\n\t"
"mov r4, r0\n\t"
"mov r5, SP\n\t"
"push {r4-r8,lr}\n\t"
"sub sp, #16\n\t"
"mov r6, r2\n\t"
"add r3, sp, #12\n\t"
"mov r7, r0\n\t"
"mov r8, r1\n\t"
"bl " __ASM_NAME("relay_trace_entry") "\n\t"
"mov ip, r0\n\t" /* entry point */
"mov r5, sp\n\t"
"ldr r1, [sp, #12]\n\t" /* number of args */
"lsl r3, r1, #2\n\t"
"sub SP, SP, r3\n\t"
"and SP, SP, #~7\n"
"1:\tsub r3, r3, #4\n\t"
"subs r3, #16\n\t" /* first 4 args are in registers */
"ble 2f\n\t"
"sub sp, r3\n\t"
"and sp, #~7\n"
"add r2, r6, #16\n\t" /* skip r0-r3 */
"1:\tsubs r3, r3, #4\n\t"
"ldr r0, [r2, r3]\n\t"
"str r0, [SP, r3]\n\t"
"cmp r3, #0\n\t"
"bgt 1b\n\t"
"cmp r1, #0\n\t"
"beq 3f\n\t"
"cmp r1, #2\n\t"
"bgt 2f\n\t"
"pop {r0-r1}\n\t"
"b 3f\n"
"2:\tpop {r0-r3}\n"
"3:\tblx r4\n\t"
"mov SP, r5\n\t"
"pop {r4, r5, PC}" )
static LONGLONG WINAPI relay_call( struct relay_descr *descr, unsigned int idx, const DWORD *stack )
{
unsigned int nb_args;
void *func = relay_trace_entry( descr, idx, stack, &nb_args );
LONGLONG ret = call_entry_point( func, nb_args, stack );
relay_trace_exit( descr, idx, stack[-1], ret );
return ret;
}
"str r0, [sp, r3]\n\t"
"bgt 1b\n"
"2:\t"
#ifndef __SOFTFP__
"tst r1, #0x80000000\n\t"
"ldm r6, {r0-r3}\n\t"
"vldmdbne r6!, {s0-s15}\n\t"
#else
"ldm r6, {r0-r3}\n\t"
#endif
"blx ip\n\t"
"mov sp, r5\n\t"
"ldr r2, [r6, #-4]\n\t" /* retaddr */
"mov r4, r0\n\t"
"mov r5, r1\n\t"
"mov r0, r7\n\t"
"mov r1, r8\n\t"
"strd r4, [sp]\n\t"
#ifndef __SOFTFP__
"vstr d0, [sp, #8]\n\t" /* preserve floating point retval */
"bl " __ASM_NAME("relay_trace_exit") "\n\t"
"vldr d0, [sp, #8]\n\t"
#else
"bl " __ASM_NAME("relay_trace_exit") "\n\t"
#endif
"mov r0, r4\n\t"
"mov r1, r5\n\t"
"add sp, #16\n\t"
"pop {r4-r8,pc}" )
#elif defined(__aarch64__)

View File

@ -255,16 +255,16 @@ static void output_relay_debug( DLLSPEC *spec )
case CPU_ARM:
{
unsigned int mask, val, count = 0;
unsigned int stack_size = min( 16, (get_args_size( odp ) + 7) & ~7 );
int j, has_float = 0;
if (strcmp( float_abi_option, "soft" ))
for (j = 0; j < odp->u.func.nb_args && !has_float; j++)
has_float = is_float_arg( odp, j );
val = (odp->u.func.args_str_offset << 16) | (i - spec->base);
switch (stack_size)
{
case 16: output( "\tpush {r0-r3}\n" ); break;
case 8: output( "\tpush {r0-r1}\n" ); break;
case 0: break;
}
output( "\tpush {r0-r3}\n" );
output( "\tmov r2, SP\n");
if (has_float) output( "\tvpush {s0-s15}\n" );
output( "\tpush {LR}\n" );
output( "\tsub SP, #4\n");
for (mask = 0xff; mask; mask <<= 8)
@ -275,7 +275,7 @@ static void output_relay_debug( DLLSPEC *spec )
output( "\tldr IP, [r0, #4]\n");
output( "1:\tblx IP\n");
output( "\tldr IP, [SP, #4]\n" );
output( "\tadd SP, #%u\n", stack_size + 8 );
output( "\tadd SP, #%u\n", 24 + (has_float ? 64 : 0) );
output( "\tbx IP\n");
output( "2:\t.long .L__wine_spec_relay_descr-1b\n" );
break;