2 * 386-specific Win32 relay functions
4 * Copyright 1997 Alexandre Julliard
12 #include "builtin32.h"
13 #include "selectors.h"
14 #include "stackframe.h"
19 #include "debugtools.h"
21 DEFAULT_DEBUG_CHANNEL(relay
);
23 char **debug_relay_excludelist
= NULL
, **debug_relay_includelist
= NULL
;
25 /***********************************************************************
26 * RELAY_ShowDebugmsgRelay
28 * Simple function to decide if a particular debugging message is
29 * wanted. Called from RELAY_CallFrom32 and from in if1632/relay.c
31 int RELAY_ShowDebugmsgRelay(const char *func
) {
33 if(debug_relay_excludelist
|| debug_relay_includelist
) {
34 const char *term
= strchr(func
, ':');
36 int len
, len2
, itemlen
, show
;
38 if(debug_relay_excludelist
) {
40 listitem
= debug_relay_excludelist
;
43 listitem
= debug_relay_includelist
;
46 assert(strlen(term
) > 2);
48 len2
= strchr(func
, '.') - func
;
49 assert(len2
&& len2
> 0 && len2
< 64);
51 for(; *listitem
; listitem
++) {
52 itemlen
= strlen(*listitem
);
53 if((itemlen
== len
&& !lstrncmpiA(*listitem
, func
, len
)) ||
54 (itemlen
== len2
&& !lstrncmpiA(*listitem
, func
, len2
)) ||
55 !strcasecmp(*listitem
, term
)) {
70 BYTE call
; /* 0xe8 call callfrom32 (relative) */
71 DWORD callfrom32 WINE_PACKED
; /* RELAY_CallFrom32 relative addr */
72 BYTE ret
; /* 0xc2 ret $n or 0xc3 ret */
73 WORD args
; /* nb of args to remove from the stack */
74 FARPROC orig
; /* original entry point */
75 DWORD argtypes
; /* argument types */
79 /***********************************************************************
82 * Find the name of an exported function.
84 static const char *find_exported_name( const char *module
,
85 IMAGE_EXPORT_DIRECTORY
*exp
, int ordinal
)
88 const char *ret
= NULL
;
90 WORD
*ordptr
= (WORD
*)(module
+ exp
->AddressOfNameOrdinals
);
91 for (i
= 0; i
< exp
->NumberOfNames
; i
++, ordptr
++)
92 if (*ordptr
+ exp
->Base
== ordinal
) break;
93 if (i
< exp
->NumberOfNames
)
94 ret
= module
+ ((DWORD
*)(module
+ exp
->AddressOfNames
))[i
];
99 /***********************************************************************
102 * Get the name of the DLL entry point corresponding to a relay address.
104 static void get_entry_point( char *buffer
, DEBUG_ENTRY_POINT
*relay
)
106 IMAGE_DATA_DIRECTORY
*dir
;
107 IMAGE_EXPORT_DIRECTORY
*exp
= NULL
;
108 DEBUG_ENTRY_POINT
*debug
;
114 /* First find the module */
116 for (wm
= PROCESS_Current()->modref_list
; wm
; wm
= wm
->next
)
118 if (!(wm
->flags
& WINE_MODREF_INTERNAL
)) continue;
119 base
= (char *)wm
->module
;
120 dir
= &PE_HEADER(base
)->OptionalHeader
.DataDirectory
[IMAGE_FILE_EXPORT_DIRECTORY
];
121 if (!dir
->Size
) continue;
122 exp
= (IMAGE_EXPORT_DIRECTORY
*)(base
+ dir
->VirtualAddress
);
123 debug
= (DEBUG_ENTRY_POINT
*)((char *)exp
+ dir
->Size
);
124 if (debug
<= relay
&& relay
< debug
+ exp
->NumberOfFunctions
)
126 ordinal
= relay
- debug
;
131 /* Now find the function */
133 name
= find_exported_name( base
, exp
, ordinal
+ exp
->Base
);
134 sprintf( buffer
, "%s.%ld: %s", base
+ exp
->Name
, ordinal
+ exp
->Base
, name
? name
: "@" );
138 /***********************************************************************
141 static inline void RELAY_PrintArgs( int *args
, int nb_args
, unsigned int typemask
)
145 if ((typemask
& 3) && HIWORD(*args
))
148 DPRINTF( "%08x %s", *args
, debugstr_w((LPWSTR
)*args
) );
150 DPRINTF( "%08x %s", *args
, debugstr_a((LPCSTR
)*args
) );
152 else DPRINTF( "%08x", *args
);
153 if (nb_args
) DPRINTF( "," );
160 /***********************************************************************
163 * Stack layout on entry to this function:
168 * (esp) return addr to relay code
170 static int RELAY_CallFrom32( int ret_addr
, ... )
175 int *args
= &ret_addr
+ 1;
176 /* Relay addr is the return address for this function */
177 BYTE
*relay_addr
= (BYTE
*)__builtin_return_address(0);
178 DEBUG_ENTRY_POINT
*relay
= (DEBUG_ENTRY_POINT
*)(relay_addr
- 5);
179 WORD nb_args
= relay
->args
/ sizeof(int);
181 get_entry_point( buffer
, relay
);
183 DPRINTF( "Call %s(", buffer
);
184 RELAY_PrintArgs( args
, nb_args
, relay
->argtypes
);
185 DPRINTF( ") ret=%08x fs=%04x\n", ret_addr
, __get_fs() );
187 /* the user driver functions may be called with the window lock held */
188 if (memcmp( buffer
, "x11drv.", 7 ) && memcmp( buffer
, "ttydrv.", 7 ))
189 SYSLEVEL_CheckNotLevel( 2 );
191 if (relay
->ret
== 0xc3) /* cdecl */
193 LRESULT (*cfunc
)() = (LRESULT(*)())relay
->orig
;
196 case 0: ret
= cfunc(); break;
197 case 1: ret
= cfunc(args
[0]); break;
198 case 2: ret
= cfunc(args
[0],args
[1]); break;
199 case 3: ret
= cfunc(args
[0],args
[1],args
[2]); break;
200 case 4: ret
= cfunc(args
[0],args
[1],args
[2],args
[3]); break;
201 case 5: ret
= cfunc(args
[0],args
[1],args
[2],args
[3],args
[4]); break;
202 case 6: ret
= cfunc(args
[0],args
[1],args
[2],args
[3],args
[4],
204 case 7: ret
= cfunc(args
[0],args
[1],args
[2],args
[3],args
[4],args
[5],
206 case 8: ret
= cfunc(args
[0],args
[1],args
[2],args
[3],args
[4],args
[5],
207 args
[6],args
[7]); break;
208 case 9: ret
= cfunc(args
[0],args
[1],args
[2],args
[3],args
[4],args
[5],
209 args
[6],args
[7],args
[8]); break;
210 case 10: ret
= cfunc(args
[0],args
[1],args
[2],args
[3],args
[4],args
[5],
211 args
[6],args
[7],args
[8],args
[9]); break;
212 case 11: ret
= cfunc(args
[0],args
[1],args
[2],args
[3],args
[4],args
[5],
213 args
[6],args
[7],args
[8],args
[9],args
[10]); break;
214 case 12: ret
= cfunc(args
[0],args
[1],args
[2],args
[3],args
[4],args
[5],
215 args
[6],args
[7],args
[8],args
[9],args
[10],
217 case 13: ret
= cfunc(args
[0],args
[1],args
[2],args
[3],args
[4],args
[5],
218 args
[6],args
[7],args
[8],args
[9],args
[10],args
[11],
220 case 14: ret
= cfunc(args
[0],args
[1],args
[2],args
[3],args
[4],args
[5],
221 args
[6],args
[7],args
[8],args
[9],args
[10],args
[11],
222 args
[12],args
[13]); break;
223 case 15: ret
= cfunc(args
[0],args
[1],args
[2],args
[3],args
[4],args
[5],
224 args
[6],args
[7],args
[8],args
[9],args
[10],args
[11],
225 args
[12],args
[13],args
[14]); break;
226 case 16: ret
= cfunc(args
[0],args
[1],args
[2],args
[3],args
[4],args
[5],
227 args
[6],args
[7],args
[8],args
[9],args
[10],args
[11],
228 args
[12],args
[13],args
[14],args
[15]); break;
230 ERR( "Unsupported nb of args %d\n", nb_args
);
236 FARPROC func
= relay
->orig
;
239 case 0: ret
= func(); break;
240 case 1: ret
= func(args
[0]); break;
241 case 2: ret
= func(args
[0],args
[1]); break;
242 case 3: ret
= func(args
[0],args
[1],args
[2]); break;
243 case 4: ret
= func(args
[0],args
[1],args
[2],args
[3]); break;
244 case 5: ret
= func(args
[0],args
[1],args
[2],args
[3],args
[4]); break;
245 case 6: ret
= func(args
[0],args
[1],args
[2],args
[3],args
[4],
247 case 7: ret
= func(args
[0],args
[1],args
[2],args
[3],args
[4],args
[5],
249 case 8: ret
= func(args
[0],args
[1],args
[2],args
[3],args
[4],args
[5],
250 args
[6],args
[7]); break;
251 case 9: ret
= func(args
[0],args
[1],args
[2],args
[3],args
[4],args
[5],
252 args
[6],args
[7],args
[8]); break;
253 case 10: ret
= func(args
[0],args
[1],args
[2],args
[3],args
[4],args
[5],
254 args
[6],args
[7],args
[8],args
[9]); break;
255 case 11: ret
= func(args
[0],args
[1],args
[2],args
[3],args
[4],args
[5],
256 args
[6],args
[7],args
[8],args
[9],args
[10]); break;
257 case 12: ret
= func(args
[0],args
[1],args
[2],args
[3],args
[4],args
[5],
258 args
[6],args
[7],args
[8],args
[9],args
[10],
260 case 13: ret
= func(args
[0],args
[1],args
[2],args
[3],args
[4],args
[5],
261 args
[6],args
[7],args
[8],args
[9],args
[10],args
[11],
263 case 14: ret
= func(args
[0],args
[1],args
[2],args
[3],args
[4],args
[5],
264 args
[6],args
[7],args
[8],args
[9],args
[10],args
[11],
265 args
[12],args
[13]); break;
266 case 15: ret
= func(args
[0],args
[1],args
[2],args
[3],args
[4],args
[5],
267 args
[6],args
[7],args
[8],args
[9],args
[10],args
[11],
268 args
[12],args
[13],args
[14]); break;
269 case 16: ret
= func(args
[0],args
[1],args
[2],args
[3],args
[4],args
[5],
270 args
[6],args
[7],args
[8],args
[9],args
[10],args
[11],
271 args
[12],args
[13],args
[14],args
[15]); break;
273 ERR( "Unsupported nb of args %d\n", nb_args
);
277 DPRINTF( "Ret %s() retval=%08x ret=%08x fs=%04x\n",
278 buffer
, ret
, ret_addr
, __get_fs() );
280 if (memcmp( buffer
, "x11drv.", 7 ) && memcmp( buffer
, "ttydrv.", 7 ))
281 SYSLEVEL_CheckNotLevel( 2 );
287 /***********************************************************************
288 * RELAY_CallFrom32Regs
290 * Stack layout (esp is ESP_reg(context), not the current %esp):
294 * (esp) return addr to caller
295 * (esp-4) return addr to DEBUG_ENTRY_POINT
296 * (esp-8) ptr to relay entry code for RELAY_CallFrom32Regs
297 * ... >128 bytes space free to be modified (ensured by the assembly glue)
300 void WINAPI
RELAY_DoCallFrom32Regs( CONTEXT86
*context
);
301 DEFINE_REGS_ENTRYPOINT_0( RELAY_CallFrom32Regs
, RELAY_DoCallFrom32Regs
)
302 void WINAPI
RELAY_DoCallFrom32Regs( CONTEXT86
*context
)
309 BYTE
*relay_addr
= *((BYTE
**)ESP_reg(context
) - 1);
310 DEBUG_ENTRY_POINT
*relay
= (DEBUG_ENTRY_POINT
*)(relay_addr
- 5);
311 WORD nb_args
= (relay
->args
& ~0x8000) / sizeof(int);
313 /* remove extra stuff from the stack */
314 EIP_reg(context
) = stack32_pop(context
);
315 args
= (int *)ESP_reg(context
);
316 ESP_reg(context
) += 4 * nb_args
;
318 assert(TRACE_ON(relay
));
320 entry_point
= (BYTE
*)relay
->orig
;
321 assert( *entry_point
== 0xe8 /* lcall */ );
322 func
= *(FARPROC
*)(entry_point
+ 5);
324 get_entry_point( buffer
, relay
);
326 DPRINTF( "Call %s(", buffer
);
327 RELAY_PrintArgs( args
, nb_args
, relay
->argtypes
);
328 DPRINTF( ") ret=%08lx fs=%04lx\n", EIP_reg(context
), FS_reg(context
) );
330 DPRINTF(" eax=%08lx ebx=%08lx ecx=%08lx edx=%08lx esi=%08lx edi=%08lx\n",
331 EAX_reg(context
), EBX_reg(context
), ECX_reg(context
),
332 EDX_reg(context
), ESI_reg(context
), EDI_reg(context
) );
333 DPRINTF(" ebp=%08lx esp=%08lx ds=%04lx es=%04lx gs=%04lx flags=%08lx\n",
334 EBP_reg(context
), ESP_reg(context
), DS_reg(context
),
335 ES_reg(context
), GS_reg(context
), EFL_reg(context
) );
337 SYSLEVEL_CheckNotLevel( 2 );
339 /* Now call the real function */
342 case 0: func(context
); break;
343 case 1: func(args
[0],context
); break;
344 case 2: func(args
[0],args
[1],context
); break;
345 case 3: func(args
[0],args
[1],args
[2],context
); break;
346 case 4: func(args
[0],args
[1],args
[2],args
[3],context
); break;
347 case 5: func(args
[0],args
[1],args
[2],args
[3],args
[4],context
); break;
348 case 6: func(args
[0],args
[1],args
[2],args
[3],args
[4],args
[5],context
); break;
349 case 7: func(args
[0],args
[1],args
[2],args
[3],args
[4],args
[5],args
[6],context
); break;
350 case 8: func(args
[0],args
[1],args
[2],args
[3],args
[4],args
[5],args
[6],args
[7],context
); break;
351 case 9: func(args
[0],args
[1],args
[2],args
[3],args
[4],args
[5],args
[6],args
[7],args
[8],
353 case 10: func(args
[0],args
[1],args
[2],args
[3],args
[4],args
[5],args
[6],args
[7],args
[8],
354 args
[9],context
); break;
355 case 11: func(args
[0],args
[1],args
[2],args
[3],args
[4],args
[5],args
[6],args
[7],args
[8],
356 args
[9],args
[10],context
); break;
357 case 12: func(args
[0],args
[1],args
[2],args
[3],args
[4],args
[5],args
[6],args
[7],args
[8],
358 args
[9],args
[10],args
[11],context
); break;
359 case 13: func(args
[0],args
[1],args
[2],args
[3],args
[4],args
[5],args
[6],args
[7],args
[8],
360 args
[9],args
[10],args
[11],args
[12],context
); break;
361 case 14: func(args
[0],args
[1],args
[2],args
[3],args
[4],args
[5],args
[6],args
[7],args
[8],
362 args
[9],args
[10],args
[11],args
[12],args
[13],context
); break;
363 case 15: func(args
[0],args
[1],args
[2],args
[3],args
[4],args
[5],args
[6],args
[7],args
[8],
364 args
[9],args
[10],args
[11],args
[12],args
[13],args
[14],context
); break;
365 case 16: func(args
[0],args
[1],args
[2],args
[3],args
[4],args
[5], args
[6],args
[7],args
[8],
366 args
[9],args
[10],args
[11],args
[12],args
[13],args
[14],args
[15],context
); break;
368 ERR( "Unsupported nb of args %d\n", nb_args
);
372 DPRINTF( "Ret %s() retval=%08lx ret=%08lx fs=%04lx\n",
373 buffer
, EAX_reg(context
), EIP_reg(context
), FS_reg(context
) );
374 DPRINTF(" eax=%08lx ebx=%08lx ecx=%08lx edx=%08lx esi=%08lx edi=%08lx\n",
375 EAX_reg(context
), EBX_reg(context
), ECX_reg(context
),
376 EDX_reg(context
), ESI_reg(context
), EDI_reg(context
) );
377 DPRINTF(" ebp=%08lx esp=%08lx ds=%04lx es=%04lx gs=%04lx flags=%08lx\n",
378 EBP_reg(context
), ESP_reg(context
), DS_reg(context
),
379 ES_reg(context
), GS_reg(context
), EFL_reg(context
) );
381 SYSLEVEL_CheckNotLevel( 2 );
385 /***********************************************************************
388 * Setup relay debugging for a built-in dll.
390 void RELAY_SetupDLL( const char *module
)
392 IMAGE_DATA_DIRECTORY
*dir
;
393 IMAGE_EXPORT_DIRECTORY
*exports
;
394 DEBUG_ENTRY_POINT
*debug
;
397 const char *name
, *dllname
;
399 dir
= &PE_HEADER(module
)->OptionalHeader
.DataDirectory
[IMAGE_FILE_EXPORT_DIRECTORY
];
400 if (!dir
->Size
) return;
401 exports
= (IMAGE_EXPORT_DIRECTORY
*)(module
+ dir
->VirtualAddress
);
402 debug
= (DEBUG_ENTRY_POINT
*)((char *)exports
+ dir
->Size
);
403 funcs
= (DWORD
*)(module
+ exports
->AddressOfFunctions
);
404 dllname
= module
+ exports
->Name
;
406 for (i
= 0; i
< exports
->NumberOfFunctions
; i
++, funcs
++, debug
++)
410 if (!debug
->call
) continue; /* not a normal function */
412 if ((name
= find_exported_name( module
, exports
, i
+ exports
->Base
)))
415 sprintf( buffer
, "%s.%d: %s", dllname
, i
, name
);
416 on
= RELAY_ShowDebugmsgRelay(buffer
);
421 debug
->call
= 0xe8; /* call relative */
422 if (debug
->args
& 0x8000) /* register func */
423 debug
->callfrom32
= (char *)RELAY_CallFrom32Regs
- (char *)&debug
->ret
;
425 debug
->callfrom32
= (char *)RELAY_CallFrom32
- (char *)&debug
->ret
;
429 debug
->call
= 0xe9; /* jmp relative */
430 debug
->callfrom32
= (char *)debug
->orig
- (char *)&debug
->ret
;
433 debug
->orig
= (FARPROC
)(module
+ (DWORD
)*funcs
);
434 *funcs
= (char *)debug
- module
;
440 void RELAY_SetupDLL( const char *module
)
444 #endif /* __i386__ */