Use SendNotifyMessage() for WM_SYNCPAINT.
[wine/gsoc_dplay.git] / relay32 / relay386.c
blob33ba0e6e0a7a8dd49fc8d13304e7e952dd37c543
1 /*
2 * 386-specific Win32 relay functions
4 * Copyright 1997 Alexandre Julliard
5 */
8 #include <assert.h>
9 #include <string.h>
10 #include <stdio.h>
12 #include "config.h"
13 #include "winnt.h"
14 #include "selectors.h"
15 #include "stackframe.h"
16 #include "syslevel.h"
17 #include "main.h"
18 #include "module.h"
19 #include "process.h"
20 #include "debugtools.h"
22 DEFAULT_DEBUG_CHANNEL(relay);
24 char **debug_relay_excludelist = NULL, **debug_relay_includelist = NULL;
26 /***********************************************************************
27 * RELAY_ShowDebugmsgRelay
29 * Simple function to decide if a particular debugging message is
30 * wanted. Called from RELAY_CallFrom32 and from in if1632/relay.c
32 int RELAY_ShowDebugmsgRelay(const char *func) {
34 if(debug_relay_excludelist || debug_relay_includelist) {
35 const char *term = strchr(func, ':');
36 char **listitem;
37 int len, len2, itemlen, show;
39 if(debug_relay_excludelist) {
40 show = 1;
41 listitem = debug_relay_excludelist;
42 } else {
43 show = 0;
44 listitem = debug_relay_includelist;
46 assert(term);
47 assert(strlen(term) > 2);
48 len = term - func;
49 len2 = strchr(func, '.') - func;
50 assert(len2 && len2 > 0 && len2 < 64);
51 term += 2;
52 for(; *listitem; listitem++) {
53 itemlen = strlen(*listitem);
54 if((itemlen == len && !strncasecmp(*listitem, func, len)) ||
55 (itemlen == len2 && !strncasecmp(*listitem, func, len2)) ||
56 !strcasecmp(*listitem, term)) {
57 show = !show;
58 break;
61 return show;
63 return 1;
67 #ifdef __i386__
69 typedef struct
71 BYTE call; /* 0xe8 call callfrom32 (relative) */
72 DWORD callfrom32 WINE_PACKED; /* RELAY_CallFrom32 relative addr */
73 BYTE ret; /* 0xc2 ret $n or 0xc3 ret */
74 WORD args; /* nb of args to remove from the stack */
75 void *orig; /* original entry point */
76 DWORD argtypes; /* argument types */
77 } DEBUG_ENTRY_POINT;
80 /***********************************************************************
81 * find_exported_name
83 * Find the name of an exported function.
85 static const char *find_exported_name( const char *module,
86 IMAGE_EXPORT_DIRECTORY *exp, int ordinal )
88 int i;
89 const char *ret = NULL;
91 WORD *ordptr = (WORD *)(module + exp->AddressOfNameOrdinals);
92 for (i = 0; i < exp->NumberOfNames; i++, ordptr++)
93 if (*ordptr + exp->Base == ordinal) break;
94 if (i < exp->NumberOfNames)
95 ret = module + ((DWORD*)(module + exp->AddressOfNames))[i];
96 return ret;
100 /***********************************************************************
101 * get_entry_point
103 * Get the name of the DLL entry point corresponding to a relay address.
105 static void get_entry_point( char *buffer, DEBUG_ENTRY_POINT *relay )
107 IMAGE_DATA_DIRECTORY *dir;
108 IMAGE_EXPORT_DIRECTORY *exp = NULL;
109 DEBUG_ENTRY_POINT *debug;
110 char *base = NULL;
111 const char *name;
112 int ordinal = 0;
113 WINE_MODREF *wm;
115 /* First find the module */
117 for (wm = PROCESS_Current()->modref_list; wm; wm = wm->next)
119 if (!(wm->flags & WINE_MODREF_INTERNAL)) continue;
120 base = (char *)wm->module;
121 dir = &PE_HEADER(base)->OptionalHeader.DataDirectory[IMAGE_FILE_EXPORT_DIRECTORY];
122 if (!dir->Size) continue;
123 exp = (IMAGE_EXPORT_DIRECTORY *)(base + dir->VirtualAddress);
124 debug = (DEBUG_ENTRY_POINT *)((char *)exp + dir->Size);
125 if (debug <= relay && relay < debug + exp->NumberOfFunctions)
127 ordinal = relay - debug;
128 break;
132 /* Now find the function */
134 name = find_exported_name( base, exp, ordinal + exp->Base );
135 sprintf( buffer, "%s.%ld: %s", base + exp->Name, ordinal + exp->Base, name ? name : "@" );
139 /***********************************************************************
140 * RELAY_PrintArgs
142 static inline void RELAY_PrintArgs( int *args, int nb_args, unsigned int typemask )
144 while (nb_args--)
146 if ((typemask & 3) && HIWORD(*args))
148 if (typemask & 2)
149 DPRINTF( "%08x %s", *args, debugstr_w((LPWSTR)*args) );
150 else
151 DPRINTF( "%08x %s", *args, debugstr_a((LPCSTR)*args) );
153 else DPRINTF( "%08x", *args );
154 if (nb_args) DPRINTF( "," );
155 args++;
156 typemask >>= 2;
161 typedef LONGLONG WINAPI (*LONGLONG_FARPROC)();
163 /***********************************************************************
164 * RELAY_CallFrom32
166 * Stack layout on entry to this function:
167 * ... ...
168 * (esp+12) arg2
169 * (esp+8) arg1
170 * (esp+4) ret_addr
171 * (esp) return addr to relay code
173 static LONGLONG RELAY_CallFrom32( int ret_addr, ... )
175 LONGLONG ret;
176 char buffer[80];
177 BOOL ret64;
179 int *args = &ret_addr + 1;
180 /* Relay addr is the return address for this function */
181 BYTE *relay_addr = (BYTE *)__builtin_return_address(0);
182 DEBUG_ENTRY_POINT *relay = (DEBUG_ENTRY_POINT *)(relay_addr - 5);
183 WORD nb_args = relay->args / sizeof(int);
185 get_entry_point( buffer, relay );
187 DPRINTF( "Call %s(", buffer );
188 RELAY_PrintArgs( args, nb_args, relay->argtypes );
189 DPRINTF( ") ret=%08x fs=%04x\n", ret_addr, __get_fs() );
190 ret64 = (relay->argtypes & 0x80000000) && (nb_args < 16);
192 /* the user driver functions may be called with the window lock held */
193 if (memcmp( buffer, "x11drv.", 7 ) && memcmp( buffer, "ttydrv.", 7 ))
194 SYSLEVEL_CheckNotLevel( 2 );
196 if (relay->ret == 0xc3) /* cdecl */
198 LONGLONG (*cfunc)() = relay->orig;
199 switch(nb_args)
201 case 0: ret = cfunc(); break;
202 case 1: ret = cfunc(args[0]); break;
203 case 2: ret = cfunc(args[0],args[1]); break;
204 case 3: ret = cfunc(args[0],args[1],args[2]); break;
205 case 4: ret = cfunc(args[0],args[1],args[2],args[3]); break;
206 case 5: ret = cfunc(args[0],args[1],args[2],args[3],args[4]); break;
207 case 6: ret = cfunc(args[0],args[1],args[2],args[3],args[4],
208 args[5]); break;
209 case 7: ret = cfunc(args[0],args[1],args[2],args[3],args[4],args[5],
210 args[6]); break;
211 case 8: ret = cfunc(args[0],args[1],args[2],args[3],args[4],args[5],
212 args[6],args[7]); break;
213 case 9: ret = cfunc(args[0],args[1],args[2],args[3],args[4],args[5],
214 args[6],args[7],args[8]); break;
215 case 10: ret = cfunc(args[0],args[1],args[2],args[3],args[4],args[5],
216 args[6],args[7],args[8],args[9]); break;
217 case 11: 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]); break;
219 case 12: ret = cfunc(args[0],args[1],args[2],args[3],args[4],args[5],
220 args[6],args[7],args[8],args[9],args[10],
221 args[11]); break;
222 case 13: ret = cfunc(args[0],args[1],args[2],args[3],args[4],args[5],
223 args[6],args[7],args[8],args[9],args[10],args[11],
224 args[12]); break;
225 case 14: ret = cfunc(args[0],args[1],args[2],args[3],args[4],args[5],
226 args[6],args[7],args[8],args[9],args[10],args[11],
227 args[12],args[13]); break;
228 case 15: ret = cfunc(args[0],args[1],args[2],args[3],args[4],args[5],
229 args[6],args[7],args[8],args[9],args[10],args[11],
230 args[12],args[13],args[14]); break;
231 case 16: ret = cfunc(args[0],args[1],args[2],args[3],args[4],args[5],
232 args[6],args[7],args[8],args[9],args[10],args[11],
233 args[12],args[13],args[14],args[15]); break;
234 default:
235 ERR( "Unsupported nb of args %d\n", nb_args );
236 assert(FALSE);
239 else /* stdcall */
241 LONGLONG_FARPROC func = relay->orig;
242 switch(nb_args)
244 case 0: ret = func(); break;
245 case 1: ret = func(args[0]); break;
246 case 2: ret = func(args[0],args[1]); break;
247 case 3: ret = func(args[0],args[1],args[2]); break;
248 case 4: ret = func(args[0],args[1],args[2],args[3]); break;
249 case 5: ret = func(args[0],args[1],args[2],args[3],args[4]); break;
250 case 6: ret = func(args[0],args[1],args[2],args[3],args[4],
251 args[5]); break;
252 case 7: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
253 args[6]); break;
254 case 8: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
255 args[6],args[7]); break;
256 case 9: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
257 args[6],args[7],args[8]); break;
258 case 10: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
259 args[6],args[7],args[8],args[9]); break;
260 case 11: 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]); break;
262 case 12: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
263 args[6],args[7],args[8],args[9],args[10],
264 args[11]); break;
265 case 13: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
266 args[6],args[7],args[8],args[9],args[10],args[11],
267 args[12]); break;
268 case 14: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
269 args[6],args[7],args[8],args[9],args[10],args[11],
270 args[12],args[13]); break;
271 case 15: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
272 args[6],args[7],args[8],args[9],args[10],args[11],
273 args[12],args[13],args[14]); break;
274 case 16: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
275 args[6],args[7],args[8],args[9],args[10],args[11],
276 args[12],args[13],args[14],args[15]); break;
277 default:
278 ERR( "Unsupported nb of args %d\n", nb_args );
279 assert(FALSE);
282 if (ret64)
283 DPRINTF( "Ret %s() retval=%08x%08x ret=%08x fs=%04x\n",
284 buffer, (UINT)(ret >> 32), (UINT)ret, ret_addr, __get_fs() );
285 else
286 DPRINTF( "Ret %s() retval=%08x ret=%08x fs=%04x\n",
287 buffer, (UINT)ret, ret_addr, __get_fs() );
289 if (memcmp( buffer, "x11drv.", 7 ) && memcmp( buffer, "ttydrv.", 7 ))
290 SYSLEVEL_CheckNotLevel( 2 );
292 return ret;
296 /***********************************************************************
297 * RELAY_CallFrom32Regs
299 * Stack layout (esp is context->Esp, not the current %esp):
301 * ...
302 * (esp+4) first arg
303 * (esp) return addr to caller
304 * (esp-4) return addr to DEBUG_ENTRY_POINT
305 * (esp-8) ptr to relay entry code for RELAY_CallFrom32Regs
306 * ... >128 bytes space free to be modified (ensured by the assembly glue)
309 void WINAPI RELAY_DoCallFrom32Regs( CONTEXT86 *context );
310 DEFINE_REGS_ENTRYPOINT_0( RELAY_CallFrom32Regs, RELAY_DoCallFrom32Regs )
311 void WINAPI RELAY_DoCallFrom32Regs( CONTEXT86 *context )
313 char buffer[80];
314 int* args;
315 FARPROC func;
316 BYTE *entry_point;
318 BYTE *relay_addr = *((BYTE **)context->Esp - 1);
319 DEBUG_ENTRY_POINT *relay = (DEBUG_ENTRY_POINT *)(relay_addr - 5);
320 WORD nb_args = (relay->args & ~0x8000) / sizeof(int);
322 /* remove extra stuff from the stack */
323 context->Eip = stack32_pop(context);
324 args = (int *)context->Esp;
325 context->Esp += 4 * nb_args;
327 assert(TRACE_ON(relay));
329 entry_point = (BYTE *)relay->orig;
330 assert( *entry_point == 0xe8 /* lcall */ );
331 func = *(FARPROC *)(entry_point + 5);
333 get_entry_point( buffer, relay );
335 DPRINTF( "Call %s(", buffer );
336 RELAY_PrintArgs( args, nb_args, relay->argtypes );
337 DPRINTF( ") ret=%08lx fs=%04lx\n", context->Eip, context->SegFs );
339 DPRINTF(" eax=%08lx ebx=%08lx ecx=%08lx edx=%08lx esi=%08lx edi=%08lx\n",
340 context->Eax, context->Ebx, context->Ecx,
341 context->Edx, context->Esi, context->Edi );
342 DPRINTF(" ebp=%08lx esp=%08lx ds=%04lx es=%04lx gs=%04lx flags=%08lx\n",
343 context->Ebp, context->Esp, context->SegDs,
344 context->SegEs, context->SegGs, context->EFlags );
346 SYSLEVEL_CheckNotLevel( 2 );
348 /* Now call the real function */
349 switch(nb_args)
351 case 0: func(context); break;
352 case 1: func(args[0],context); break;
353 case 2: func(args[0],args[1],context); break;
354 case 3: func(args[0],args[1],args[2],context); break;
355 case 4: func(args[0],args[1],args[2],args[3],context); break;
356 case 5: func(args[0],args[1],args[2],args[3],args[4],context); break;
357 case 6: func(args[0],args[1],args[2],args[3],args[4],args[5],context); break;
358 case 7: func(args[0],args[1],args[2],args[3],args[4],args[5],args[6],context); break;
359 case 8: func(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7],context); break;
360 case 9: func(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7],args[8],
361 context); break;
362 case 10: func(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7],args[8],
363 args[9],context); break;
364 case 11: func(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7],args[8],
365 args[9],args[10],context); break;
366 case 12: func(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7],args[8],
367 args[9],args[10],args[11],context); break;
368 case 13: func(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7],args[8],
369 args[9],args[10],args[11],args[12],context); break;
370 case 14: func(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7],args[8],
371 args[9],args[10],args[11],args[12],args[13],context); break;
372 case 15: func(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7],args[8],
373 args[9],args[10],args[11],args[12],args[13],args[14],context); break;
374 case 16: func(args[0],args[1],args[2],args[3],args[4],args[5], args[6],args[7],args[8],
375 args[9],args[10],args[11],args[12],args[13],args[14],args[15],context); break;
376 default:
377 ERR( "Unsupported nb of args %d\n", nb_args );
378 assert(FALSE);
381 DPRINTF( "Ret %s() retval=%08lx ret=%08lx fs=%04lx\n",
382 buffer, context->Eax, context->Eip, context->SegFs );
384 DPRINTF(" eax=%08lx ebx=%08lx ecx=%08lx edx=%08lx esi=%08lx edi=%08lx\n",
385 context->Eax, context->Ebx, context->Ecx,
386 context->Edx, context->Esi, context->Edi );
387 DPRINTF(" ebp=%08lx esp=%08lx ds=%04lx es=%04lx gs=%04lx flags=%08lx\n",
388 context->Ebp, context->Esp, context->SegDs,
389 context->SegEs, context->SegGs, context->EFlags );
391 SYSLEVEL_CheckNotLevel( 2 );
395 /***********************************************************************
396 * RELAY_SetupDLL
398 * Setup relay debugging for a built-in dll.
400 void RELAY_SetupDLL( const char *module )
402 IMAGE_DATA_DIRECTORY *dir;
403 IMAGE_EXPORT_DIRECTORY *exports;
404 DEBUG_ENTRY_POINT *debug;
405 DWORD *funcs;
406 int i;
407 const char *name, *dllname;
409 dir = &PE_HEADER(module)->OptionalHeader.DataDirectory[IMAGE_FILE_EXPORT_DIRECTORY];
410 if (!dir->Size) return;
411 exports = (IMAGE_EXPORT_DIRECTORY *)(module + dir->VirtualAddress);
412 debug = (DEBUG_ENTRY_POINT *)((char *)exports + dir->Size);
413 funcs = (DWORD *)(module + exports->AddressOfFunctions);
414 dllname = module + exports->Name;
416 for (i = 0; i < exports->NumberOfFunctions; i++, funcs++, debug++)
418 int on = 1;
420 if (!debug->call) continue; /* not a normal function */
421 if (debug->call != 0xe8 && debug->call != 0xe9) break; /* not a debug thunk at all */
423 if ((name = find_exported_name( module, exports, i + exports->Base )))
425 char buffer[200];
426 sprintf( buffer, "%s.%d: %s", dllname, i, name );
427 on = RELAY_ShowDebugmsgRelay(buffer);
430 if (on)
432 debug->call = 0xe8; /* call relative */
433 if (debug->args & 0x8000) /* register func */
434 debug->callfrom32 = (char *)RELAY_CallFrom32Regs - (char *)&debug->ret;
435 else
436 debug->callfrom32 = (char *)RELAY_CallFrom32 - (char *)&debug->ret;
438 else
440 debug->call = 0xe9; /* jmp relative */
441 debug->callfrom32 = (char *)debug->orig - (char *)&debug->ret;
444 debug->orig = (FARPROC)(module + (DWORD)*funcs);
445 *funcs = (char *)debug - module;
449 #else /* __i386__ */
451 void RELAY_SetupDLL( const char *module )
455 #endif /* __i386__ */