ntdll: Display floating point arguments in relay debugging on i386 and x86-64.

Signed-off-by: Alexandre Julliard <julliard@winehq.org>
oldstable
Alexandre Julliard 2017-12-07 11:14:02 +01:00
parent 83bbeab9b2
commit 8c1bb2aa61
3 changed files with 383 additions and 184 deletions

View File

@ -44,14 +44,13 @@ struct relay_descr /* descriptor for a module */
{
void *magic; /* signature */
void *relay_call; /* functions to call from relay thunks */
void *relay_call_regs; /* no longer used */
void *private; /* reserved for the relay code private data */
const char *entry_point_base; /* base address of entry point thunks */
const unsigned int *entry_point_offsets; /* offsets of entry points thunks */
const unsigned int *arg_types; /* table of argument types for all entry points */
const char *args_string; /* string describing the arguments */
};
#define RELAY_DESCR_MAGIC ((void *)0xdeb90001)
#define RELAY_DESCR_MAGIC ((void *)0xdeb90002)
#define IS_INTARG(x) (((ULONG_PTR)(x) >> 16) == 0)
/* private data built at dll load time */
@ -295,49 +294,85 @@ static BOOL check_from_module( const WCHAR **includelist, const WCHAR **excludel
return show;
}
/***********************************************************************
* RELAY_PrintArgs
*/
static inline void RELAY_PrintArgs( const INT_PTR *args, int nb_args, unsigned int typemask )
static BOOL is_ret_val( char type )
{
while (nb_args--)
{
if ((typemask & 3) && !IS_INTARG(*args))
{
if (typemask & 2)
TRACE( "%08lx %s", *args, debugstr_w((LPCWSTR)*args) );
else
TRACE( "%08lx %s", *args, debugstr_a((LPCSTR)*args) );
}
else TRACE( "%08lx", *args );
if (nb_args) TRACE( "," );
args++;
typemask >>= 2;
}
return type >= 'A' && type <= 'Z';
}
static const char *func_name( struct relay_private_data *data, unsigned int ordinal )
{
struct relay_entry_point *entry_point = data->entry_points + ordinal;
if (entry_point->name)
return wine_dbg_sprintf( "%s.%s", data->dllname, entry_point->name );
else
return wine_dbg_sprintf( "%s.%u", data->dllname, data->base + ordinal );
}
static void trace_string_a( INT_PTR ptr )
{
if (!IS_INTARG( ptr )) TRACE( "%08lx %s", ptr, debugstr_a( (char *)ptr ));
else TRACE( "%08lx", ptr );
}
static void trace_string_w( INT_PTR ptr )
{
if (!IS_INTARG( ptr )) TRACE( "%08lx %s", ptr, debugstr_w( (WCHAR *)ptr ));
else TRACE( "%08lx", ptr );
}
#ifdef __i386__
/***********************************************************************
* relay_trace_entry
*
* stack points to the return address, i.e. the first argument is stack[1].
*/
DECLSPEC_HIDDEN void * WINAPI relay_trace_entry( struct relay_descr *descr,
unsigned int idx, const INT_PTR *stack )
DECLSPEC_HIDDEN void * WINAPI relay_trace_entry( struct relay_descr *descr, unsigned int idx,
const DWORD *stack, unsigned int *nb_args )
{
WORD ordinal = LOWORD(idx);
BYTE nb_args = LOBYTE(HIWORD(idx));
const char *arg_types = descr->args_string + HIWORD(idx);
struct relay_private_data *data = descr->private;
struct relay_entry_point *entry_point = data->entry_points + ordinal;
unsigned int i, pos;
if (TRACE_ON(relay))
TRACE( "\1Call %s(", func_name( data, ordinal ));
for (i = pos = 0; !is_ret_val( arg_types[i] ); i++)
{
if (entry_point->name)
TRACE( "\1Call %s.%s(", data->dllname, entry_point->name );
else
TRACE( "\1Call %s.%u(", data->dllname, data->base + ordinal );
RELAY_PrintArgs( stack + 1, nb_args, descr->arg_types[ordinal] );
TRACE( ") ret=%08lx\n", stack[0] );
switch (arg_types[i])
{
case 'j': /* int64 */
TRACE( "%x%08x", stack[pos+1], stack[pos] );
pos += 2;
break;
case 'k': /* int128 */
TRACE( "{%08x,%08x,%08x,%08x}", stack[pos], stack[pos+1], stack[pos+2], stack[pos+3] );
pos += 4;
break;
case 's': /* str */
trace_string_a( stack[pos++] );
break;
case 'w': /* wstr */
trace_string_w( stack[pos++] );
break;
case 'f': /* float */
TRACE( "%g", *(const float *)&stack[pos++] );
break;
case 'd': /* double */
TRACE( "%g", *(const double *)&stack[pos] );
pos += 2;
break;
case 'i': /* long */
default:
TRACE( "%08x", stack[pos++] );
break;
}
if (!is_ret_val( arg_types[i+1] )) TRACE( "," );
}
*nb_args = pos;
if (arg_types[0] == 't') *nb_args |= 0x80000000; /* thiscall */
TRACE( ") ret=%08x\n", stack[-1] );
return entry_point->orig_func;
}
@ -345,63 +380,21 @@ DECLSPEC_HIDDEN void * WINAPI relay_trace_entry( struct relay_descr *descr,
* relay_trace_exit
*/
DECLSPEC_HIDDEN void WINAPI relay_trace_exit( struct relay_descr *descr, unsigned int idx,
const INT_PTR *stack, LONGLONG retval )
void *retaddr, LONGLONG retval )
{
WORD ordinal = LOWORD(idx);
BYTE flags = HIBYTE(HIWORD(idx));
struct relay_private_data *data = descr->private;
struct relay_entry_point *entry_point = data->entry_points + ordinal;
const char *arg_types = descr->args_string + HIWORD(idx);
if (entry_point->name)
TRACE( "\1Ret %s.%s()", data->dllname, entry_point->name );
else
TRACE( "\1Ret %s.%u()", data->dllname, data->base + ordinal );
TRACE( "\1Ret %s()", func_name( descr->private, LOWORD(idx) ));
if (flags & 1) /* 64-bit return value */
TRACE( " retval=%08x%08x ret=%08lx\n",
(UINT)(retval >> 32), (UINT)retval, stack[0] );
while (!is_ret_val( *arg_types )) arg_types++;
if (*arg_types == 'J') /* int64 return value */
TRACE( " retval=%08x%08x ret=%08x\n",
(UINT)(retval >> 32), (UINT)retval, (UINT)retaddr );
else
TRACE( " retval=%08lx ret=%08lx\n", (UINT_PTR)retval, stack[0] );
TRACE( " retval=%08x ret=%08x\n", (UINT)retval, (UINT)retaddr );
}
#ifdef __i386__
extern LONGLONG CDECL call_entry_point( void *func, int nb_args, const INT_PTR *args, int flags );
__ASM_GLOBAL_FUNC( call_entry_point,
"pushl %ebp\n\t"
__ASM_CFI(".cfi_adjust_cfa_offset 4\n\t")
__ASM_CFI(".cfi_rel_offset %ebp,0\n\t")
"movl %esp,%ebp\n\t"
__ASM_CFI(".cfi_def_cfa_register %ebp\n\t")
"pushl %esi\n\t"
__ASM_CFI(".cfi_rel_offset %esi,-4\n\t")
"pushl %edi\n\t"
__ASM_CFI(".cfi_rel_offset %edi,-8\n\t")
"movl 12(%ebp),%edx\n\t"
"shll $2,%edx\n\t"
"jz 1f\n\t"
"subl %edx,%esp\n\t"
"andl $~15,%esp\n\t"
"movl 12(%ebp),%ecx\n\t"
"movl 16(%ebp),%esi\n\t"
"movl %esp,%edi\n\t"
"cld\n\t"
"rep; movsl\n"
"testl $2,20(%ebp)\n\t" /* (flags & 2) -> thiscall */
"jz 1f\n\t"
"popl %ecx\n\t"
"1:\tcall *8(%ebp)\n\t"
"leal -8(%ebp),%esp\n\t"
"popl %edi\n\t"
__ASM_CFI(".cfi_same_value %edi\n\t")
"popl %esi\n\t"
__ASM_CFI(".cfi_same_value %esi\n\t")
"popl %ebp\n\t"
__ASM_CFI(".cfi_def_cfa %esp,4\n\t")
__ASM_CFI(".cfi_same_value %ebp\n\t")
"ret" )
extern LONGLONG WINAPI relay_call( struct relay_descr *descr, unsigned int idx, const INT_PTR *stack );
extern LONGLONG WINAPI relay_call( struct relay_descr *descr, unsigned int idx );
__ASM_GLOBAL_FUNC( relay_call,
"pushl %ebp\n\t"
__ASM_CFI(".cfi_adjust_cfa_offset 4\n\t")
@ -415,22 +408,24 @@ __ASM_GLOBAL_FUNC( relay_call,
"pushl %ecx\n\t"
__ASM_CFI(".cfi_rel_offset %ecx,-12\n\t")
/* trace the parameters */
"pushl 16(%ebp)\n\t"
"pushl %eax\n\t"
"pushl %esp\n\t" /* number of args return ptr */
"leal 20(%ebp),%esi\n\t" /* stack */
"pushl %esi\n\t"
"pushl 12(%ebp)\n\t"
"pushl 8(%ebp)\n\t"
"call " __ASM_NAME("relay_trace_entry") "\n\t"
/* copy the arguments*/
"movzbl 14(%ebp),%ecx\n\t" /* number of args */
"movl -16(%ebp),%ecx\n\t" /* number of args */
"jecxz 1f\n\t"
"andl $0x7fffffff,%ecx\n\t"
"leal 0(,%ecx,4),%edx\n\t"
"subl %edx,%esp\n\t"
"andl $~15,%esp\n\t"
"movl 16(%ebp),%esi\n\t"
"addl $4,%esi\n\t"
"movl %esp,%edi\n\t"
"cld\n\t"
"rep; movsl\n\t"
"testb $2,15(%ebp)\n\t" /* (flags & 2) -> thiscall */
"testl $0x80000000,-16(%ebp)\n\t" /* thiscall */
"jz 1f\n\t"
"popl %ecx\n"
/* call the entry point */
@ -458,11 +453,73 @@ __ASM_GLOBAL_FUNC( relay_call,
"popl %ebp\n\t"
__ASM_CFI(".cfi_def_cfa %esp,4\n\t")
__ASM_CFI(".cfi_same_value %ebp\n\t")
"ret $12" )
"ret $8" )
#elif defined(__arm__)
extern LONGLONG CDECL call_entry_point( void *func, int nb_args, const INT_PTR *args, int flags );
/***********************************************************************
* relay_trace_entry
*/
DECLSPEC_HIDDEN void * WINAPI relay_trace_entry( struct relay_descr *descr, unsigned int idx,
const DWORD *stack, unsigned int *nb_args )
{
WORD ordinal = LOWORD(idx);
const char *arg_types = descr->args_string + HIWORD(idx);
struct relay_private_data *data = descr->private;
struct relay_entry_point *entry_point = data->entry_points + ordinal;
unsigned int i, pos;
TRACE( "\1Call %s(", func_name( data, ordinal ));
for (i = pos = 0; !is_ret_val( arg_types[i] ); i++)
{
switch (arg_types[i])
{
case 'j': /* int64 */
TRACE( "%x%08x", stack[pos+1], stack[pos] );
pos += 2;
break;
case 'k': /* int128 */
TRACE( "{%08x,%08x,%08x,%08x}", stack[pos], stack[pos+1], stack[pos+2], stack[pos+3] );
pos += 4;
break;
case 's': /* str */
trace_string_a( stack[pos++] );
break;
case 'w': /* wstr */
trace_string_w( stack[pos++] );
break;
case 'i': /* long */
default:
TRACE( "%08x", stack[pos++] );
break;
}
if (!is_ret_val( arg_types[i+1] )) TRACE( "," );
}
*nb_args = pos;
TRACE( ") ret=%08x\n", stack[-1] );
return entry_point->orig_func;
}
/***********************************************************************
* relay_trace_exit
*/
DECLSPEC_HIDDEN void WINAPI relay_trace_exit( struct relay_descr *descr, unsigned int idx,
DWORD retaddr, LONGLONG retval )
{
const char *arg_types = descr->args_string + HIWORD(idx);
TRACE( "\1Ret %s()", func_name( descr->private, LOWORD(idx) ));
while (!is_ret_val( *arg_types )) arg_types++;
if (*arg_types == 'J') /* int64 return value */
TRACE( " retval=%08x%08x ret=%08x\n",
(UINT)(retval >> 32), (UINT)retval, retaddr );
else
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,
".arm\n\t"
"push {r4, r5, LR}\n\t"
@ -487,19 +544,64 @@ __ASM_GLOBAL_FUNC( call_entry_point,
"mov SP, r5\n\t"
"pop {r4, r5, PC}" )
static LONGLONG WINAPI relay_call( struct relay_descr *descr, unsigned int idx, const INT_PTR *stack )
static LONGLONG WINAPI relay_call( struct relay_descr *descr, unsigned int idx, const DWORD *stack )
{
BYTE nb_args = LOBYTE(HIWORD(idx));
BYTE flags = HIBYTE(HIWORD(idx));
void *func = relay_trace_entry( descr, idx, stack );
LONGLONG ret = call_entry_point( func, nb_args, stack + 1, flags );
relay_trace_exit( descr, idx, stack, ret );
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;
}
#elif defined(__aarch64__)
extern LONGLONG CDECL call_entry_point( void *func, int nb_args, const INT_PTR *args, int flags );
/***********************************************************************
* relay_trace_entry
*/
DECLSPEC_HIDDEN void * WINAPI relay_trace_entry( struct relay_descr *descr, unsigned int idx,
const INT_PTR *stack, unsigned int *nb_args )
{
WORD ordinal = LOWORD(idx);
const char *arg_types = descr->args_string + HIWORD(idx);
struct relay_private_data *data = descr->private;
struct relay_entry_point *entry_point = data->entry_points + ordinal;
unsigned int i;
TRACE( "\1Call %s(", func_name( data, ordinal ));
for (i = 0; !is_ret_val( arg_types[i] ); i++)
{
switch (arg_types[i])
{
case 's': /* str */
trace_string_a( stack[i] );
break;
case 'w': /* wstr */
trace_string_w( stack[i] );
break;
case 'i': /* long */
default:
TRACE( "%08lx", stack[i] );
break;
}
if (!is_ret_val( arg_types[i + 1] )) TRACE( "," );
}
*nb_args = i;
TRACE( ") ret=%08lx\n", stack[-1] );
return entry_point->orig_func;
}
/***********************************************************************
* relay_trace_exit
*/
DECLSPEC_HIDDEN void WINAPI relay_trace_exit( struct relay_descr *descr, unsigned int idx,
INT_PTR retaddr, INT_PTR retval )
{
TRACE( "\1Ret %s() retval=%08lx ret=%08lx\n",
func_name( descr->private, LOWORD(idx) ), retval, retaddr );
}
extern LONGLONG CDECL call_entry_point( void *func, int nb_args, const INT_PTR *args );
__ASM_GLOBAL_FUNC( call_entry_point,
"stp x29, x30, [SP,#-16]!\n\t"
"stp x19, x20, [SP,#-16]!\n\t"
@ -544,43 +646,97 @@ __ASM_GLOBAL_FUNC( call_entry_point,
static LONGLONG WINAPI relay_call( struct relay_descr *descr, unsigned int idx, const INT_PTR *stack )
{
BYTE nb_args = LOBYTE(HIWORD(idx));
BYTE flags = HIBYTE(HIWORD(idx));
void *func = relay_trace_entry( descr, idx, stack + 3 );
LONGLONG ret = call_entry_point( func, nb_args, stack + 4, flags );
relay_trace_exit( descr, idx, stack + 3, ret );
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;
}
#elif defined(__x86_64__)
extern void * WINAPI relay_call( struct relay_descr *descr, unsigned int idx, const INT_PTR *stack );
/***********************************************************************
* relay_trace_entry
*/
DECLSPEC_HIDDEN void * WINAPI relay_trace_entry( struct relay_descr *descr, unsigned int idx,
const INT_PTR *stack, unsigned int *nb_args )
{
WORD ordinal = LOWORD(idx);
const char *arg_types = descr->args_string + HIWORD(idx);
struct relay_private_data *data = descr->private;
struct relay_entry_point *entry_point = data->entry_points + ordinal;
unsigned int i;
TRACE( "\1Call %s(", func_name( data, ordinal ));
for (i = 0; !is_ret_val( arg_types[i] ); i++)
{
switch (arg_types[i])
{
case 's': /* str */
trace_string_a( stack[i] );
break;
case 'w': /* wstr */
trace_string_w( stack[i] );
break;
case 'f': /* float */
TRACE( "%g", *(const float *)&stack[i] );
break;
case 'd': /* double */
TRACE( "%g", *(const double *)&stack[i] );
break;
case 'i': /* long */
default:
TRACE( "%08lx", stack[i] );
break;
}
if (!is_ret_val( arg_types[i] )) TRACE( "," );
}
*nb_args = i;
TRACE( ") ret=%08lx\n", stack[-1] );
return entry_point->orig_func;
}
/***********************************************************************
* relay_trace_exit
*/
DECLSPEC_HIDDEN void WINAPI relay_trace_exit( struct relay_descr *descr, unsigned int idx,
INT_PTR retaddr, INT_PTR retval )
{
TRACE( "\1Ret %s() retval=%08lx ret=%08lx\n",
func_name( descr->private, LOWORD(idx) ), retval, retaddr );
}
extern INT_PTR WINAPI relay_call( struct relay_descr *descr, unsigned int idx, const INT_PTR *stack );
__ASM_GLOBAL_FUNC( relay_call,
"pushq %rbp\n\t"
__ASM_CFI(".cfi_adjust_cfa_offset 8\n\t")
__ASM_CFI(".cfi_rel_offset %rbp,0\n\t")
"movq %rsp,%rbp\n\t"
__ASM_CFI(".cfi_def_cfa_register %rbp\n\t")
"subq $0x30,%rsp\n\t"
"movq %rsi,0x20(%rsp)\n\t"
"leaq -0x48(%rbp),%rsp\n\t"
"andq $~15,%rsp\n\t"
"movq %rcx,-32(%rbp)\n\t"
__ASM_CFI(".cfi_rel_offset %rcx,-32\n\t")
"movq %rdx,-24(%rbp)\n\t"
__ASM_CFI(".cfi_rel_offset %rdx,-24\n\t")
"movq %rsi,-16(%rbp)\n\t"
__ASM_CFI(".cfi_rel_offset %rsi,-16\n\t")
"movq %rdi,0x28(%rsp)\n\t"
"movq %rdi,-8(%rbp)\n\t"
__ASM_CFI(".cfi_rel_offset %rdi,-8\n\t")
/* trace the parameters */
"movq %rcx,0x10(%rbp)\n\t"
"movq %rdx,0x18(%rbp)\n\t"
"movq %r8,0x20(%rbp)\n\t"
"leaq 24(%rbp),%r8\n\t" /* stack */
"leaq -40(%rbp),%r9\n\t"
"call " __ASM_NAME("relay_trace_entry") "\n\t"
/* copy the arguments */
"movzbq 0x1a(%rbp),%rdx\n\t" /* number of args */
"movl -40(%rbp),%edx\n\t" /* number of args */
"movq $4,%rcx\n\t"
"cmp %rcx,%rdx\n\t"
"cmovgq %rdx,%rcx\n\t"
"leaq -16(,%rcx,8),%rdx\n\t"
"andq $~15,%rdx\n\t"
"subq %rdx,%rsp\n\t"
"movq 0x20(%rbp),%r8\n\t" /* original stack */
"leaq 8(%r8),%rsi\n\t"
"leaq 24(%rbp),%rsi\n\t" /* original stack */
"movq %rsp,%rdi\n\t"
"rep; movsq\n\t"
/* call the entry point */
@ -594,20 +750,19 @@ __ASM_GLOBAL_FUNC( relay_call,
"movq 24(%rsp),%xmm3\n\t"
"callq *%rax\n\t"
/* trace the return value */
"leaq -0x30(%rbp),%rsp\n\t"
"movq 0x10(%rbp),%rcx\n\t"
"movq 0x18(%rbp),%rdx\n\t"
"movq 0x20(%rbp),%r8\n\t"
"movq -32(%rbp),%rcx\n\t"
"movq -24(%rbp),%rdx\n\t"
"movq 16(%rbp),%r8\n\t" /* retaddr */
"movq %rax,%rsi\n\t"
"movaps %xmm0,0x10(%rbp)\n\t"
"movaps %xmm0,32(%rsp)\n\t"
"movq %rax,%r9\n\t"
"call " __ASM_NAME("relay_trace_exit") "\n\t"
/* restore return value and return */
"movq %rsi,%rax\n\t"
"movaps 0x10(%rbp),%xmm0\n\t"
"movq 0x20(%rsp),%rsi\n\t"
"movaps 32(%rsp),%xmm0\n\t"
"movq -16(%rbp),%rsi\n\t"
__ASM_CFI(".cfi_same_value %rsi\n\t")
"movq 0x28(%rsp),%rdi\n\t"
"movq -8(%rbp),%rdi\n\t"
__ASM_CFI(".cfi_same_value %rdi\n\t")
"movq %rbp,%rsp\n\t"
__ASM_CFI(".cfi_def_cfa_register %rsp\n\t")

View File

@ -86,6 +86,7 @@ typedef struct
typedef struct
{
int nb_args;
int args_str_offset;
enum arg_type args[MAX_ARGUMENTS];
} ORD_FUNCTION;

View File

@ -94,6 +94,88 @@ static int has_relays( DLLSPEC *spec )
return 0;
}
static int cmp_func_args( const void *p1, const void *p2 )
{
const ORDDEF *odp1 = *(const ORDDEF **)p1;
const ORDDEF *odp2 = *(const ORDDEF **)p2;
return odp2->u.func.nb_args - odp1->u.func.nb_args;
}
static void get_arg_string( ORDDEF *odp, char str[MAX_ARGUMENTS + 1] )
{
int i;
for (i = 0; i < odp->u.func.nb_args; i++)
{
switch (odp->u.func.args[i])
{
case ARG_STR: str[i] = 's'; break;
case ARG_WSTR: str[i] = 'w'; break;
case ARG_FLOAT: str[i] = 'f'; break;
case ARG_DOUBLE: str[i] = 'd'; break;
case ARG_INT64:
case ARG_INT128:
if (get_ptr_size() == 4)
{
str[i] = (odp->u.func.args[i] == ARG_INT64) ? 'j' : 'k';
break;
}
/* fall through */
case ARG_LONG:
case ARG_PTR:
default:
str[i] = 'i';
break;
}
}
if (target_cpu == CPU_x86 && odp->type == TYPE_THISCALL) str[0] = 't';
/* append return value */
if (get_ptr_size() == 4 && (odp->flags & FLAG_RET64))
strcpy( str + i, "J" );
else
strcpy( str + i, "I" );
}
/*******************************************************************
* build_args_string
*/
static char *build_args_string( DLLSPEC *spec )
{
int i, count = 0, len = 1;
char *p, *buffer;
char str[MAX_ARGUMENTS + 2];
ORDDEF **funcs;
funcs = xmalloc( (spec->limit + 1 - spec->base) * sizeof(*funcs) );
for (i = spec->base; i <= spec->limit; i++)
{
ORDDEF *odp = spec->ordinals[i];
if (!needs_relay( odp )) continue;
funcs[count++] = odp;
len += odp->u.func.nb_args + 1;
}
/* sort functions by decreasing number of arguments */
qsort( funcs, count, sizeof(*funcs), cmp_func_args );
buffer = xmalloc( len );
buffer[0] = 0;
/* build the arguments string, reusing substrings where possible */
for (i = 0; i < count; i++)
{
get_arg_string( funcs[i], str );
if (!(p = strstr( buffer, str )))
{
p = buffer + strlen( buffer );
strcpy( p, str );
}
funcs[i]->u.func.args_str_offset = p - buffer;
}
free( funcs );
return buffer;
}
/*******************************************************************
* output_relay_debug
*
@ -101,8 +183,7 @@ static int has_relays( DLLSPEC *spec )
*/
static void output_relay_debug( DLLSPEC *spec )
{
int i, j;
unsigned int pos, args, flags;
int i;
/* first the table of entry point offsets */
@ -120,33 +201,10 @@ static void output_relay_debug( DLLSPEC *spec )
output( "\t.long 0\n" );
}
/* then the table of argument types */
/* then the strings of argument types */
output( "\t.align %d\n", get_alignment(4) );
output( ".L__wine_spec_relay_arg_types:\n" );
for (i = spec->base; i <= spec->limit; i++)
{
ORDDEF *odp = spec->ordinals[i];
unsigned int mask = 0;
if (needs_relay( odp ))
{
for (j = pos = 0; pos < 16 && j < odp->u.func.nb_args; j++)
{
switch (odp->u.func.args[j])
{
case ARG_STR: mask |= 1 << (2 * pos++); break;
case ARG_WSTR: mask |= 2 << (2 * pos++); break;
case ARG_INT64:
case ARG_DOUBLE: pos += 8 / get_ptr_size(); break;
case ARG_INT128: pos += (target_cpu == CPU_x86) ? 4 : 1; break;
default: pos++; break;
}
}
}
output( "\t.long 0x%08x\n", mask );
}
output( ".L__wine_spec_relay_args_string:\n" );
output( "\t%s \"%s\"\n", get_asm_string_keyword(), build_args_string( spec ));
/* then the relay thunks */
@ -164,9 +222,6 @@ static void output_relay_debug( DLLSPEC *spec )
output( ".L__wine_spec_relay_entry_point_%d:\n", i );
output_cfi( ".cfi_startproc" );
args = get_args_size(odp) / get_ptr_size();
flags = 0;
switch (target_cpu)
{
case CPU_x86:
@ -175,13 +230,8 @@ static void output_relay_debug( DLLSPEC *spec )
output( "\tpopl %%eax\n" );
output( "\tpushl %%ecx\n" );
output( "\tpushl %%eax\n" );
flags |= 2;
}
output( "\tpushl %%esp\n" );
output_cfi( ".cfi_adjust_cfa_offset 4" );
if (odp->flags & FLAG_RET64) flags |= 1;
output( "\tpushl $%u\n", (flags << 24) | (args << 16) | (i - spec->base) );
output( "\tpushl $%u\n", (odp->u.func.args_str_offset << 16) | (i - spec->base) );
output_cfi( ".cfi_adjust_cfa_offset 4" );
if (UsePIC)
@ -195,9 +245,9 @@ static void output_relay_debug( DLLSPEC *spec )
output_cfi( ".cfi_adjust_cfa_offset 4" );
output( "\tcall *4(%%eax)\n" );
output_cfi( ".cfi_adjust_cfa_offset -12" );
output_cfi( ".cfi_adjust_cfa_offset -8" );
if (odp->type == TYPE_STDCALL || odp->type == TYPE_THISCALL)
output( "\tret $%u\n", args * get_ptr_size() );
output( "\tret $%u\n", get_args_size( odp ));
else
output( "\tret\n" );
break;
@ -205,18 +255,17 @@ static void output_relay_debug( DLLSPEC *spec )
case CPU_ARM:
{
unsigned int mask, val, count = 0;
unsigned int stack_size = min( 16, (args * 4 + 7) & ~7 );
unsigned int stack_size = min( 16, (get_args_size( odp ) + 7) & ~7 );
if (odp->flags & FLAG_RET64) flags |= 1;
val = (flags << 24) | (args << 16) | (i - spec->base);
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 {LR}\n" );
output( "\tmov r2, SP\n");
output( "\tpush {LR}\n" );
output( "\tsub SP, #4\n");
for (mask = 0xff; mask; mask <<= 8)
if (val & mask) output( "\t%s r1,#%u\n", count++ ? "add" : "mov", val & mask );
@ -233,7 +282,7 @@ static void output_relay_debug( DLLSPEC *spec )
}
case CPU_ARM64:
switch (args)
switch (odp->u.func.nb_args)
{
default:
case 8:
@ -250,12 +299,10 @@ static void output_relay_debug( DLLSPEC *spec )
/* fall through */
case 0: break;
}
output( "\tmov x2, SP\n");
output( "\tstp x29, x30, [SP,#-16]!\n" );
output( "\tstp x8, x9, [SP,#-16]!\n" );
output( "\tmov x2, SP\n");
if (odp->flags & FLAG_RET64) flags |= 1;
output( "\tmov w1, #%u\n", (flags << 24) );
if (args) output( "\tadd w1, w1, #%u\n", (args << 16) );
output( "\tmov w1, #%u\n", odp->u.func.args_str_offset << 16 );
if (i - spec->base) output( "\tadd w1, w1, #%u\n", i - spec->base );
output( "\tadrp x0, .L__wine_spec_relay_descr\n");
output( "\tadd x0, x0, #:lo12:.L__wine_spec_relay_descr\n");
@ -263,31 +310,27 @@ static void output_relay_debug( DLLSPEC *spec )
output( "\tblr x3\n");
output( "\tadd SP, SP, #16\n" );
output( "\tldp x29, x30, [SP], #16\n" );
if (args) output( "\tadd SP, SP, #%u\n", 8 * ((min(args, 8) + 1) & 0xe) );
if (odp->u.func.nb_args)
output( "\tadd SP, SP, #%u\n", 8 * ((min(odp->u.func.nb_args, 8) + 1) & ~1) );
output( "\tret\n");
break;
case CPU_x86_64:
output( "\tsubq $40,%%rsp\n" );
output_cfi( ".cfi_adjust_cfa_offset 40" );
switch (args)
switch (odp->u.func.nb_args)
{
default: output( "\tmovq %%%s,72(%%rsp)\n", is_float_arg( odp, 3 ) ? "xmm3" : "r9" );
default: output( "\tmovq %%%s,32(%%rsp)\n", is_float_arg( odp, 3 ) ? "xmm3" : "r9" );
/* fall through */
case 3: output( "\tmovq %%%s,64(%%rsp)\n", is_float_arg( odp, 2 ) ? "xmm2" : "r8" );
case 3: output( "\tmovq %%%s,24(%%rsp)\n", is_float_arg( odp, 2 ) ? "xmm2" : "r8" );
/* fall through */
case 2: output( "\tmovq %%%s,56(%%rsp)\n", is_float_arg( odp, 1 ) ? "xmm1" : "rdx" );
case 2: output( "\tmovq %%%s,16(%%rsp)\n", is_float_arg( odp, 1 ) ? "xmm1" : "rdx" );
/* fall through */
case 1: output( "\tmovq %%%s,48(%%rsp)\n", is_float_arg( odp, 0 ) ? "xmm0" : "rcx" );
case 1: output( "\tmovq %%%s,8(%%rsp)\n", is_float_arg( odp, 0 ) ? "xmm0" : "rcx" );
/* fall through */
case 0: break;
}
output( "\tleaq 40(%%rsp),%%r8\n" );
output( "\tmovq $%u,%%rdx\n", (flags << 24) | (args << 16) | (i - spec->base) );
output( "\tmovl $%u,%%edx\n", (odp->u.func.args_str_offset << 16) | (i - spec->base) );
output( "\tleaq .L__wine_spec_relay_descr(%%rip),%%rcx\n" );
output( "\tcallq *8(%%rcx)\n" );
output( "\taddq $40,%%rsp\n" );
output_cfi( ".cfi_adjust_cfa_offset -40" );
output( "\tret\n" );
break;
@ -432,12 +475,12 @@ void output_exports( DLLSPEC *spec )
}
output( ".L__wine_spec_relay_descr:\n" );
output( "\t%s 0xdeb90001\n", get_asm_ptr_keyword() ); /* magic */
output( "\t%s 0,0\n", get_asm_ptr_keyword() ); /* relay funcs */
output( "\t%s 0xdeb90002\n", get_asm_ptr_keyword() ); /* magic */
output( "\t%s 0\n", get_asm_ptr_keyword() ); /* relay func */
output( "\t%s 0\n", get_asm_ptr_keyword() ); /* private data */
output( "\t%s __wine_spec_relay_entry_points\n", get_asm_ptr_keyword() );
output( "\t%s .L__wine_spec_relay_entry_point_offsets\n", get_asm_ptr_keyword() );
output( "\t%s .L__wine_spec_relay_arg_types\n", get_asm_ptr_keyword() );
output( "\t%s .L__wine_spec_relay_args_string\n", get_asm_ptr_keyword() );
output_relay_debug( spec );
}