Changed the GDI driver interface to pass an opaque PHYSDEV pointer
[wine] / relay32 / relay386.c
1 /*
2  * 386-specific Win32 relay functions
3  *
4  * Copyright 1997 Alexandre Julliard
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21
22 #include "config.h"
23
24 #include <assert.h>
25 #include <string.h>
26 #include <stdio.h>
27
28 #include "winnt.h"
29 #include "stackframe.h"
30 #include "module.h"
31 #include "wine/debug.h"
32
33 WINE_DEFAULT_DEBUG_CHANNEL(relay);
34
35 char **debug_relay_excludelist = NULL, **debug_relay_includelist = NULL;
36
37 /***********************************************************************
38  *           RELAY_ShowDebugmsgRelay
39  *
40  * Simple function to decide if a particular debugging message is
41  * wanted.  Called from RELAY_CallFrom32 and from in if1632/relay.c
42  */
43 int RELAY_ShowDebugmsgRelay(const char *func) {
44
45   if(debug_relay_excludelist || debug_relay_includelist) {
46     const char *term = strchr(func, ':');
47     char **listitem;
48     int len, len2, itemlen, show;
49
50     if(debug_relay_excludelist) {
51       show = 1;
52       listitem = debug_relay_excludelist;
53     } else {
54       show = 0;
55       listitem = debug_relay_includelist;
56     }
57     assert(term);
58     assert(strlen(term) > 2);
59     len = term - func;
60     len2 = strchr(func, '.') - func;
61     assert(len2 && len2 > 0 && len2 < 64);
62     term += 2;
63     for(; *listitem; listitem++) {
64       itemlen = strlen(*listitem);
65       if((itemlen == len && !strncasecmp(*listitem, func, len)) ||
66          (itemlen == len2 && !strncasecmp(*listitem, func, len2)) ||
67          !strcasecmp(*listitem, term)) {
68         show = !show;
69        break;
70       }
71     }
72     return show;
73   }
74   return 1;
75 }
76
77
78 #ifdef __i386__
79
80 typedef struct
81 {
82     BYTE          call;                    /* 0xe8 call callfrom32 (relative) */
83     DWORD         callfrom32 WINE_PACKED;  /* RELAY_CallFrom32 relative addr */
84     BYTE          ret;                     /* 0xc2 ret $n  or  0xc3 ret */
85     WORD          args;                    /* nb of args to remove from the stack */
86     void         *orig;                    /* original entry point */
87     DWORD         argtypes;                /* argument types */
88 } DEBUG_ENTRY_POINT;
89
90
91 /***********************************************************************
92  *           find_exported_name
93  *
94  * Find the name of an exported function.
95  */
96 static const char *find_exported_name( const char *module,
97                                        IMAGE_EXPORT_DIRECTORY *exp, int ordinal )
98 {
99     int i;
100     const char *ret = NULL;
101
102     WORD *ordptr = (WORD *)(module + exp->AddressOfNameOrdinals);
103     for (i = 0; i < exp->NumberOfNames; i++, ordptr++)
104         if (*ordptr + exp->Base == ordinal) break;
105     if (i < exp->NumberOfNames)
106         ret = module + ((DWORD*)(module + exp->AddressOfNames))[i];
107     return ret;
108 }
109
110
111 /***********************************************************************
112  *           get_entry_point
113  *
114  * Get the name of the DLL entry point corresponding to a relay address.
115  */
116 static void get_entry_point( char *buffer, DEBUG_ENTRY_POINT *relay )
117 {
118     IMAGE_DATA_DIRECTORY *dir;
119     IMAGE_EXPORT_DIRECTORY *exp = NULL;
120     DEBUG_ENTRY_POINT *debug;
121     char *base = NULL;
122     const char *name;
123     int ordinal = 0;
124     WINE_MODREF *wm;
125
126     /* First find the module */
127
128     for (wm = MODULE_modref_list; wm; wm = wm->next)
129     {
130         if (!(wm->flags & WINE_MODREF_INTERNAL)) continue;
131         base = (char *)wm->module;
132         dir = &PE_HEADER(base)->OptionalHeader.DataDirectory[IMAGE_FILE_EXPORT_DIRECTORY];
133         if (!dir->Size) continue;
134         exp = (IMAGE_EXPORT_DIRECTORY *)(base + dir->VirtualAddress);
135         debug = (DEBUG_ENTRY_POINT *)((char *)exp + dir->Size);
136         if (debug <= relay && relay < debug + exp->NumberOfFunctions)
137         {
138             ordinal = relay - debug;
139             break;
140         }
141     }
142
143     /* Now find the function */
144
145     if ((name = find_exported_name( base, exp, ordinal + exp->Base )))
146         sprintf( buffer, "%s.%s", base + exp->Name, name );
147     else
148         sprintf( buffer, "%s.%ld", base + exp->Name, ordinal + exp->Base );
149 }
150
151
152 /***********************************************************************
153  *           RELAY_PrintArgs
154  */
155 static inline void RELAY_PrintArgs( int *args, int nb_args, unsigned int typemask )
156 {
157     while (nb_args--)
158     {
159         if ((typemask & 3) && HIWORD(*args))
160         {
161             if (typemask & 2)
162                 DPRINTF( "%08x %s", *args, debugstr_w((LPWSTR)*args) );
163             else
164                 DPRINTF( "%08x %s", *args, debugstr_a((LPCSTR)*args) );
165         }
166         else DPRINTF( "%08x", *args );
167         if (nb_args) DPRINTF( "," );
168         args++;
169         typemask >>= 2;
170     }
171 }
172
173
174 typedef LONGLONG (*LONGLONG_CPROC)();
175 typedef LONGLONG (WINAPI *LONGLONG_FARPROC)();
176
177
178 /***********************************************************************
179  *           call_cdecl_function
180  */
181 static LONGLONG call_cdecl_function( LONGLONG_CPROC func, int nb_args, const int *args )
182 {
183     LONGLONG ret;
184     switch(nb_args)
185     {
186     case 0: ret = func(); break;
187     case 1: ret = func(args[0]); break;
188     case 2: ret = func(args[0],args[1]); break;
189     case 3: ret = func(args[0],args[1],args[2]); break;
190     case 4: ret = func(args[0],args[1],args[2],args[3]); break;
191     case 5: ret = func(args[0],args[1],args[2],args[3],args[4]); break;
192     case 6: ret = func(args[0],args[1],args[2],args[3],args[4],
193                        args[5]); break;
194     case 7: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
195                        args[6]); break;
196     case 8: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
197                        args[6],args[7]); break;
198     case 9: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
199                        args[6],args[7],args[8]); break;
200     case 10: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
201                         args[6],args[7],args[8],args[9]); break;
202     case 11: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
203                         args[6],args[7],args[8],args[9],args[10]); break;
204     case 12: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
205                         args[6],args[7],args[8],args[9],args[10],
206                         args[11]); break;
207     case 13: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
208                         args[6],args[7],args[8],args[9],args[10],args[11],
209                         args[12]); break;
210     case 14: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
211                         args[6],args[7],args[8],args[9],args[10],args[11],
212                         args[12],args[13]); break;
213     case 15: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
214                         args[6],args[7],args[8],args[9],args[10],args[11],
215                         args[12],args[13],args[14]); break;
216     case 16: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
217                         args[6],args[7],args[8],args[9],args[10],args[11],
218                         args[12],args[13],args[14],args[15]); break;
219     default:
220         ERR( "Unsupported nb of args %d\n", nb_args );
221         assert(FALSE);
222     }
223     return ret;
224 }
225
226
227 /***********************************************************************
228  *           call_stdcall_function
229  */
230 static LONGLONG call_stdcall_function( LONGLONG_FARPROC func, int nb_args, const int *args )
231 {
232     LONGLONG ret;
233     switch(nb_args)
234     {
235     case 0: ret = func(); break;
236     case 1: ret = func(args[0]); break;
237     case 2: ret = func(args[0],args[1]); break;
238     case 3: ret = func(args[0],args[1],args[2]); break;
239     case 4: ret = func(args[0],args[1],args[2],args[3]); break;
240     case 5: ret = func(args[0],args[1],args[2],args[3],args[4]); break;
241     case 6: ret = func(args[0],args[1],args[2],args[3],args[4],
242                        args[5]); break;
243     case 7: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
244                        args[6]); break;
245     case 8: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
246                        args[6],args[7]); break;
247     case 9: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
248                        args[6],args[7],args[8]); break;
249     case 10: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
250                         args[6],args[7],args[8],args[9]); break;
251     case 11: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
252                         args[6],args[7],args[8],args[9],args[10]); break;
253     case 12: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
254                         args[6],args[7],args[8],args[9],args[10],
255                         args[11]); break;
256     case 13: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
257                         args[6],args[7],args[8],args[9],args[10],args[11],
258                         args[12]); break;
259     case 14: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
260                         args[6],args[7],args[8],args[9],args[10],args[11],
261                         args[12],args[13]); break;
262     case 15: 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],args[11],
264                         args[12],args[13],args[14]); break;
265     case 16: 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],args[13],args[14],args[15]); break;
268     default:
269         ERR( "Unsupported nb of args %d\n", nb_args );
270         assert(FALSE);
271     }
272     return ret;
273 }
274
275
276 /***********************************************************************
277  *           RELAY_CallFrom32
278  *
279  * Stack layout on entry to this function:
280  *  ...      ...
281  * (esp+12)  arg2
282  * (esp+8)   arg1
283  * (esp+4)   ret_addr
284  * (esp)     return addr to relay code
285  */
286 static LONGLONG RELAY_CallFrom32( int ret_addr, ... )
287 {
288     LONGLONG ret;
289     char buffer[80];
290     BOOL ret64;
291
292     int *args = &ret_addr + 1;
293     /* Relay addr is the return address for this function */
294     BYTE *relay_addr = (BYTE *)__builtin_return_address(0);
295     DEBUG_ENTRY_POINT *relay = (DEBUG_ENTRY_POINT *)(relay_addr - 5);
296     WORD nb_args = relay->args / sizeof(int);
297
298     get_entry_point( buffer, relay );
299
300     DPRINTF( "%08lx:Call %s(", GetCurrentThreadId(), buffer );
301     RELAY_PrintArgs( args, nb_args, relay->argtypes );
302     DPRINTF( ") ret=%08x\n", ret_addr );
303     ret64 = (relay->argtypes & 0x80000000) && (nb_args < 16);
304
305     if (relay->ret == 0xc3) /* cdecl */
306     {
307         ret = call_cdecl_function( (LONGLONG_CPROC)relay->orig, nb_args, args );
308     }
309     else  /* stdcall */
310     {
311         ret = call_stdcall_function( (LONGLONG_FARPROC)relay->orig, nb_args, args );
312     }
313
314     if (ret64)
315         DPRINTF( "%08lx:Ret  %s() retval=%08x%08x ret=%08x\n",
316                  GetCurrentThreadId(),
317                  buffer, (UINT)(ret >> 32), (UINT)ret, ret_addr );
318     else
319         DPRINTF( "%08lx:Ret  %s() retval=%08x ret=%08x\n",
320                  GetCurrentThreadId(),
321                  buffer, (UINT)ret, ret_addr );
322
323     return ret;
324 }
325
326
327 /***********************************************************************
328  *           RELAY_CallFrom32Regs
329  *
330  * Stack layout (esp is context->Esp, not the current %esp):
331  *
332  * ...
333  * (esp+4) first arg
334  * (esp)   return addr to caller
335  * (esp-4) return addr to DEBUG_ENTRY_POINT
336  * (esp-8) ptr to relay entry code for RELAY_CallFrom32Regs
337  *  ...    >128 bytes space free to be modified (ensured by the assembly glue)
338  */
339 void WINAPI RELAY_DoCallFrom32Regs( CONTEXT86 *context )
340 {
341     char buffer[80];
342     int* args;
343     int args_copy[17];
344     BYTE *entry_point;
345
346     BYTE *relay_addr = *((BYTE **)context->Esp - 1);
347     DEBUG_ENTRY_POINT *relay = (DEBUG_ENTRY_POINT *)(relay_addr - 5);
348     WORD nb_args = (relay->args & ~0x8000) / sizeof(int);
349
350     /* remove extra stuff from the stack */
351     context->Eip = stack32_pop(context);
352     args = (int *)context->Esp;
353     if (relay->ret == 0xc2) /* stdcall */
354         context->Esp += nb_args * sizeof(int);
355
356     assert(TRACE_ON(relay));
357
358     entry_point = (BYTE *)relay->orig;
359     assert( *entry_point == 0xe8 /* lcall */ );
360
361     get_entry_point( buffer, relay );
362
363     DPRINTF( "%08lx:Call %s(", GetCurrentThreadId(), buffer );
364     RELAY_PrintArgs( args, nb_args, relay->argtypes );
365     DPRINTF( ") ret=%08lx fs=%04lx\n", context->Eip, context->SegFs );
366
367     DPRINTF(" eax=%08lx ebx=%08lx ecx=%08lx edx=%08lx esi=%08lx edi=%08lx\n",
368             context->Eax, context->Ebx, context->Ecx,
369             context->Edx, context->Esi, context->Edi );
370     DPRINTF(" ebp=%08lx esp=%08lx ds=%04lx es=%04lx gs=%04lx flags=%08lx\n",
371             context->Ebp, context->Esp, context->SegDs,
372             context->SegEs, context->SegGs, context->EFlags );
373
374     /* Now call the real function */
375
376     memcpy( args_copy, args, nb_args * sizeof(args[0]) );
377     args_copy[nb_args] = (int)context;  /* append context argument */
378     if (relay->ret == 0xc3) /* cdecl */
379     {
380         call_cdecl_function( *(LONGLONG_CPROC *)(entry_point + 5), nb_args+1, args_copy );
381     }
382     else  /* stdcall */
383     {
384         call_stdcall_function( *(LONGLONG_FARPROC *)(entry_point + 5), nb_args+1, args_copy );
385     }
386
387     DPRINTF( "%08lx:Ret  %s() retval=%08lx ret=%08lx fs=%04lx\n",
388              GetCurrentThreadId(),
389              buffer, context->Eax, context->Eip, context->SegFs );
390
391     DPRINTF(" eax=%08lx ebx=%08lx ecx=%08lx edx=%08lx esi=%08lx edi=%08lx\n",
392             context->Eax, context->Ebx, context->Ecx,
393             context->Edx, context->Esi, context->Edi );
394     DPRINTF(" ebp=%08lx esp=%08lx ds=%04lx es=%04lx gs=%04lx flags=%08lx\n",
395             context->Ebp, context->Esp, context->SegDs,
396             context->SegEs, context->SegGs, context->EFlags );
397 }
398
399 void WINAPI RELAY_CallFrom32Regs(void);
400 __ASM_GLOBAL_FUNC( RELAY_CallFrom32Regs,
401                    "call " __ASM_NAME("__wine_call_from_32_regs") "\n\t"
402                    ".long " __ASM_NAME("RELAY_DoCallFrom32Regs") ",0" );
403
404 /***********************************************************************
405  *           RELAY_SetupDLL
406  *
407  * Setup relay debugging for a built-in dll.
408  */
409 void RELAY_SetupDLL( const char *module )
410 {
411     IMAGE_DATA_DIRECTORY *dir;
412     IMAGE_EXPORT_DIRECTORY *exports;
413     DEBUG_ENTRY_POINT *debug;
414     DWORD *funcs;
415     int i;
416     const char *name, *dllname;
417
418     dir = &PE_HEADER(module)->OptionalHeader.DataDirectory[IMAGE_FILE_EXPORT_DIRECTORY];
419     if (!dir->Size) return;
420     exports = (IMAGE_EXPORT_DIRECTORY *)(module + dir->VirtualAddress);
421     debug = (DEBUG_ENTRY_POINT *)((char *)exports + dir->Size);
422     funcs = (DWORD *)(module + exports->AddressOfFunctions);
423     dllname = module + exports->Name;
424
425     for (i = 0; i < exports->NumberOfFunctions; i++, funcs++, debug++)
426     {
427         int on = 1;
428
429         if (!debug->call) continue;  /* not a normal function */
430         if (debug->call != 0xe8 && debug->call != 0xe9) break; /* not a debug thunk at all */
431
432         if ((name = find_exported_name( module, exports, i + exports->Base )))
433         {
434             char buffer[200];
435             sprintf( buffer, "%s.%d: %s", dllname, i, name );
436             on = RELAY_ShowDebugmsgRelay(buffer);
437         }
438
439         if (on)
440         {
441             debug->call = 0xe8;  /* call relative */
442             if (debug->args & 0x8000)  /* register func */
443                 debug->callfrom32 = (char *)RELAY_CallFrom32Regs - (char *)&debug->ret;
444             else
445                 debug->callfrom32 = (char *)RELAY_CallFrom32 - (char *)&debug->ret;
446         }
447         else
448         {
449             debug->call = 0xe9;  /* jmp relative */
450             debug->callfrom32 = (char *)debug->orig - (char *)&debug->ret;
451         }
452
453         debug->orig = (FARPROC)(module + (DWORD)*funcs);
454         *funcs = (char *)debug - module;
455     }
456 }
457
458 #else  /* __i386__ */
459
460 void RELAY_SetupDLL( const char *module )
461 {
462 }
463
464 #endif /* __i386__ */