Combined implementations of ShellExecute/Ex.
[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 #include "config.h"
22 #include "wine/port.h"
23
24 #include <assert.h>
25 #include <string.h>
26 #include <stdio.h>
27
28 #include "winnt.h"
29 #include "winreg.h"
30 #include "stackframe.h"
31 #include "module.h"
32 #include "wine/debug.h"
33
34 WINE_DEFAULT_DEBUG_CHANNEL(relay);
35 WINE_DECLARE_DEBUG_CHANNEL(snoop);
36
37 const char **debug_relay_excludelist = NULL;
38 const char **debug_relay_includelist = NULL;
39 const char **debug_snoop_excludelist = NULL;
40 const char **debug_snoop_includelist = NULL;
41
42 /***********************************************************************
43  *           build_list
44  *
45  * Build a function list from a ';'-separated string.
46  */
47 static const char **build_list( const char *buffer )
48 {
49     int count = 1;
50     const char *p = buffer;
51     const char **ret;
52
53     while ((p = strchr( p, ';' )))
54     {
55         count++;
56         p++;
57     }
58     /* allocate count+1 pointers, plus the space for a copy of the string */
59     if ((ret = HeapAlloc( GetProcessHeap(), 0, (count+1) * sizeof(char*) + strlen(buffer) + 1 )))
60     {
61         char *str = (char *)(ret + count + 1);
62         char *p = str;
63
64         strcpy( str, buffer );
65         count = 0;
66         for (;;)
67         {
68             ret[count++] = p;
69             if (!(p = strchr( p, ';' ))) break;
70             *p++ = 0;
71         }
72         ret[count++] = NULL;
73     }
74     return ret;
75 }
76
77
78 /***********************************************************************
79  *           RELAY_InitDebugLists
80  *
81  * Build the relay include/exclude function lists.
82  */
83 void RELAY_InitDebugLists(void)
84 {
85     char buffer[1024];
86     HKEY hkey;
87     DWORD count, type;
88
89     if (RegOpenKeyA( HKEY_LOCAL_MACHINE, "Software\\Wine\\Wine\\Config\\Debug", &hkey )) return;
90
91     count = sizeof(buffer);
92     if (!RegQueryValueExA( hkey, "RelayInclude", NULL, &type, buffer, &count ))
93     {
94         TRACE("RelayInclude = %s\n", buffer );
95         debug_relay_includelist = build_list( buffer );
96     }
97
98     count = sizeof(buffer);
99     if (!RegQueryValueExA( hkey, "RelayExclude", NULL, &type, buffer, &count ))
100     {
101         TRACE( "RelayExclude = %s\n", buffer );
102         debug_relay_excludelist = build_list( buffer );
103     }
104
105     count = sizeof(buffer);
106     if (!RegQueryValueExA( hkey, "SnoopInclude", NULL, &type, buffer, &count ))
107     {
108         TRACE_(snoop)( "SnoopInclude = %s\n", buffer );
109         debug_snoop_includelist = build_list( buffer );
110     }
111
112     count = sizeof(buffer);
113     if (!RegQueryValueExA( hkey, "SnoopExclude", NULL, &type, buffer, &count ))
114     {
115         TRACE_(snoop)( "SnoopExclude = %s\n", buffer );
116         debug_snoop_excludelist = build_list( buffer );
117     }
118
119     RegCloseKey( hkey );
120 }
121
122
123 #ifdef __i386__
124
125 typedef struct
126 {
127     BYTE          call;                    /* 0xe8 call callfrom32 (relative) */
128     DWORD         callfrom32 WINE_PACKED;  /* RELAY_CallFrom32 relative addr */
129     BYTE          ret;                     /* 0xc2 ret $n  or  0xc3 ret */
130     WORD          args;                    /* nb of args to remove from the stack */
131     void         *orig;                    /* original entry point */
132     DWORD         argtypes;                /* argument types */
133 } DEBUG_ENTRY_POINT;
134
135
136 /***********************************************************************
137  *           check_relay_include
138  *
139  * Check if a given function must be included in the relay output.
140  */
141 static BOOL check_relay_include( const char *module, const char *func )
142 {
143     const char **listitem;
144     BOOL show;
145
146     if (!debug_relay_excludelist && !debug_relay_includelist) return TRUE;
147     if (debug_relay_excludelist)
148     {
149         show = TRUE;
150         listitem = debug_relay_excludelist;
151     }
152     else
153     {
154         show = FALSE;
155         listitem = debug_relay_includelist;
156     }
157     for(; *listitem; listitem++)
158     {
159         char *p = strrchr( *listitem, '.' );
160         if (p && p > *listitem)  /* check module and function */
161         {
162             int len = p - *listitem;
163             if (strncasecmp( *listitem, module, len-1 ) || module[len]) continue;
164             if (!strcmp( p + 1, func ) || !strcmp( p + 1, "*" )) return !show;
165         }
166         else  /* function only */
167         {
168             if (!strcmp( *listitem, func )) return !show;
169         }
170     }
171     return show;
172 }
173
174
175 /***********************************************************************
176  *           find_exported_name
177  *
178  * Find the name of an exported function.
179  */
180 static const char *find_exported_name( const char *module,
181                                        IMAGE_EXPORT_DIRECTORY *exp, int ordinal )
182 {
183     int i;
184     const char *ret = NULL;
185
186     WORD *ordptr = (WORD *)(module + exp->AddressOfNameOrdinals);
187     for (i = 0; i < exp->NumberOfNames; i++, ordptr++)
188         if (*ordptr + exp->Base == ordinal) break;
189     if (i < exp->NumberOfNames)
190         ret = module + ((DWORD*)(module + exp->AddressOfNames))[i];
191     return ret;
192 }
193
194
195 /***********************************************************************
196  *           get_entry_point
197  *
198  * Get the name of the DLL entry point corresponding to a relay address.
199  */
200 static void get_entry_point( char *buffer, DEBUG_ENTRY_POINT *relay )
201 {
202     IMAGE_DATA_DIRECTORY *dir;
203     IMAGE_EXPORT_DIRECTORY *exp = NULL;
204     DEBUG_ENTRY_POINT *debug;
205     char *p, *base = NULL;
206     const char *name;
207     int ordinal = 0;
208     WINE_MODREF *wm;
209
210     /* First find the module */
211
212     for (wm = MODULE_modref_list; wm; wm = wm->next)
213     {
214         if (!(wm->flags & WINE_MODREF_INTERNAL)) continue;
215         base = (char *)wm->module;
216         dir = &PE_HEADER(base)->OptionalHeader.DataDirectory[IMAGE_FILE_EXPORT_DIRECTORY];
217         if (!dir->Size) continue;
218         exp = (IMAGE_EXPORT_DIRECTORY *)(base + dir->VirtualAddress);
219         debug = (DEBUG_ENTRY_POINT *)((char *)exp + dir->Size);
220         if (debug <= relay && relay < debug + exp->NumberOfFunctions)
221         {
222             ordinal = relay - debug;
223             break;
224         }
225     }
226
227     /* Now find the function */
228
229     strcpy( buffer, base + exp->Name );
230     p = buffer + strlen(buffer);
231     if (p > buffer + 4 && !strcasecmp( p - 4, ".dll" )) p -= 4;
232
233     if ((name = find_exported_name( base, exp, ordinal + exp->Base )))
234         sprintf( p, ".%s", name );
235     else
236         sprintf( p, ".%ld", ordinal + exp->Base );
237 }
238
239
240 /***********************************************************************
241  *           RELAY_PrintArgs
242  */
243 static inline void RELAY_PrintArgs( int *args, int nb_args, unsigned int typemask )
244 {
245     while (nb_args--)
246     {
247         if ((typemask & 3) && HIWORD(*args))
248         {
249             if (typemask & 2)
250                 DPRINTF( "%08x %s", *args, debugstr_w((LPWSTR)*args) );
251             else
252                 DPRINTF( "%08x %s", *args, debugstr_a((LPCSTR)*args) );
253         }
254         else DPRINTF( "%08x", *args );
255         if (nb_args) DPRINTF( "," );
256         args++;
257         typemask >>= 2;
258     }
259 }
260
261
262 typedef LONGLONG (*LONGLONG_CPROC)();
263 typedef LONGLONG (WINAPI *LONGLONG_FARPROC)();
264
265
266 /***********************************************************************
267  *           call_cdecl_function
268  */
269 static LONGLONG call_cdecl_function( LONGLONG_CPROC func, int nb_args, const int *args )
270 {
271     LONGLONG ret;
272     switch(nb_args)
273     {
274     case 0: ret = func(); break;
275     case 1: ret = func(args[0]); break;
276     case 2: ret = func(args[0],args[1]); break;
277     case 3: ret = func(args[0],args[1],args[2]); break;
278     case 4: ret = func(args[0],args[1],args[2],args[3]); break;
279     case 5: ret = func(args[0],args[1],args[2],args[3],args[4]); break;
280     case 6: ret = func(args[0],args[1],args[2],args[3],args[4],
281                        args[5]); break;
282     case 7: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
283                        args[6]); break;
284     case 8: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
285                        args[6],args[7]); break;
286     case 9: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
287                        args[6],args[7],args[8]); break;
288     case 10: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
289                         args[6],args[7],args[8],args[9]); break;
290     case 11: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
291                         args[6],args[7],args[8],args[9],args[10]); break;
292     case 12: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
293                         args[6],args[7],args[8],args[9],args[10],
294                         args[11]); break;
295     case 13: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
296                         args[6],args[7],args[8],args[9],args[10],args[11],
297                         args[12]); break;
298     case 14: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
299                         args[6],args[7],args[8],args[9],args[10],args[11],
300                         args[12],args[13]); break;
301     case 15: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
302                         args[6],args[7],args[8],args[9],args[10],args[11],
303                         args[12],args[13],args[14]); break;
304     case 16: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
305                         args[6],args[7],args[8],args[9],args[10],args[11],
306                         args[12],args[13],args[14],args[15]); break;
307     default:
308         ERR( "Unsupported nb of args %d\n", nb_args );
309         assert(FALSE);
310     }
311     return ret;
312 }
313
314
315 /***********************************************************************
316  *           call_stdcall_function
317  */
318 static LONGLONG call_stdcall_function( LONGLONG_FARPROC func, int nb_args, const int *args )
319 {
320     LONGLONG ret;
321     switch(nb_args)
322     {
323     case 0: ret = func(); break;
324     case 1: ret = func(args[0]); break;
325     case 2: ret = func(args[0],args[1]); break;
326     case 3: ret = func(args[0],args[1],args[2]); break;
327     case 4: ret = func(args[0],args[1],args[2],args[3]); break;
328     case 5: ret = func(args[0],args[1],args[2],args[3],args[4]); break;
329     case 6: ret = func(args[0],args[1],args[2],args[3],args[4],
330                        args[5]); break;
331     case 7: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
332                        args[6]); break;
333     case 8: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
334                        args[6],args[7]); break;
335     case 9: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
336                        args[6],args[7],args[8]); break;
337     case 10: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
338                         args[6],args[7],args[8],args[9]); break;
339     case 11: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
340                         args[6],args[7],args[8],args[9],args[10]); break;
341     case 12: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
342                         args[6],args[7],args[8],args[9],args[10],
343                         args[11]); break;
344     case 13: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
345                         args[6],args[7],args[8],args[9],args[10],args[11],
346                         args[12]); break;
347     case 14: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
348                         args[6],args[7],args[8],args[9],args[10],args[11],
349                         args[12],args[13]); break;
350     case 15: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
351                         args[6],args[7],args[8],args[9],args[10],args[11],
352                         args[12],args[13],args[14]); break;
353     case 16: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
354                         args[6],args[7],args[8],args[9],args[10],args[11],
355                         args[12],args[13],args[14],args[15]); break;
356     default:
357         ERR( "Unsupported nb of args %d\n", nb_args );
358         assert(FALSE);
359     }
360     return ret;
361 }
362
363
364 /***********************************************************************
365  *           RELAY_CallFrom32
366  *
367  * Stack layout on entry to this function:
368  *  ...      ...
369  * (esp+12)  arg2
370  * (esp+8)   arg1
371  * (esp+4)   ret_addr
372  * (esp)     return addr to relay code
373  */
374 static LONGLONG RELAY_CallFrom32( int ret_addr, ... )
375 {
376     LONGLONG ret;
377     char buffer[80];
378
379     int *args = &ret_addr + 1;
380     /* Relay addr is the return address for this function */
381     BYTE *relay_addr = (BYTE *)__builtin_return_address(0);
382     DEBUG_ENTRY_POINT *relay = (DEBUG_ENTRY_POINT *)(relay_addr - 5);
383     WORD nb_args = relay->args / sizeof(int);
384
385     if (TRACE_ON(relay))
386     {
387         get_entry_point( buffer, relay );
388
389         DPRINTF( "%08lx:Call %s(", GetCurrentThreadId(), buffer );
390         RELAY_PrintArgs( args, nb_args, relay->argtypes );
391         DPRINTF( ") ret=%08x\n", ret_addr );
392     }
393
394     if (relay->ret == 0xc3) /* cdecl */
395     {
396         ret = call_cdecl_function( (LONGLONG_CPROC)relay->orig, nb_args, args );
397     }
398     else  /* stdcall */
399     {
400         ret = call_stdcall_function( (LONGLONG_FARPROC)relay->orig, nb_args, args );
401     }
402
403     if (TRACE_ON(relay))
404     {
405         BOOL ret64 = (relay->argtypes & 0x80000000) && (nb_args < 16);
406         if (ret64)
407             DPRINTF( "%08lx:Ret  %s() retval=%08x%08x ret=%08x\n",
408                      GetCurrentThreadId(),
409                      buffer, (UINT)(ret >> 32), (UINT)ret, ret_addr );
410         else
411             DPRINTF( "%08lx:Ret  %s() retval=%08x ret=%08x\n",
412                      GetCurrentThreadId(),
413                      buffer, (UINT)ret, ret_addr );
414     }
415     return ret;
416 }
417
418
419 /***********************************************************************
420  *           RELAY_CallFrom32Regs
421  *
422  * Stack layout (esp is context->Esp, not the current %esp):
423  *
424  * ...
425  * (esp+4) first arg
426  * (esp)   return addr to caller
427  * (esp-4) return addr to DEBUG_ENTRY_POINT
428  * (esp-8) ptr to relay entry code for RELAY_CallFrom32Regs
429  *  ...    >128 bytes space free to be modified (ensured by the assembly glue)
430  */
431 void WINAPI RELAY_DoCallFrom32Regs( CONTEXT86 *context )
432 {
433     char buffer[80];
434     int* args;
435     int args_copy[17];
436     BYTE *entry_point;
437
438     BYTE *relay_addr = *((BYTE **)context->Esp - 1);
439     DEBUG_ENTRY_POINT *relay = (DEBUG_ENTRY_POINT *)(relay_addr - 5);
440     WORD nb_args = (relay->args & ~0x8000) / sizeof(int);
441
442     /* remove extra stuff from the stack */
443     context->Eip = stack32_pop(context);
444     args = (int *)context->Esp;
445     if (relay->ret == 0xc2) /* stdcall */
446         context->Esp += nb_args * sizeof(int);
447
448     entry_point = (BYTE *)relay->orig;
449     assert( *entry_point == 0xe8 /* lcall */ );
450
451     if (TRACE_ON(relay))
452     {
453         get_entry_point( buffer, relay );
454
455         DPRINTF( "%08lx:Call %s(", GetCurrentThreadId(), buffer );
456         RELAY_PrintArgs( args, nb_args, relay->argtypes );
457         DPRINTF( ") ret=%08lx fs=%04lx\n", context->Eip, context->SegFs );
458
459         DPRINTF(" eax=%08lx ebx=%08lx ecx=%08lx edx=%08lx esi=%08lx edi=%08lx\n",
460                 context->Eax, context->Ebx, context->Ecx,
461                 context->Edx, context->Esi, context->Edi );
462         DPRINTF(" ebp=%08lx esp=%08lx ds=%04lx es=%04lx gs=%04lx flags=%08lx\n",
463                 context->Ebp, context->Esp, context->SegDs,
464                 context->SegEs, context->SegGs, context->EFlags );
465     }
466
467     /* Now call the real function */
468
469     memcpy( args_copy, args, nb_args * sizeof(args[0]) );
470     args_copy[nb_args] = (int)context;  /* append context argument */
471     if (relay->ret == 0xc3) /* cdecl */
472     {
473         call_cdecl_function( *(LONGLONG_CPROC *)(entry_point + 5), nb_args+1, args_copy );
474     }
475     else  /* stdcall */
476     {
477         call_stdcall_function( *(LONGLONG_FARPROC *)(entry_point + 5), nb_args+1, args_copy );
478     }
479
480     if (TRACE_ON(relay))
481     {
482         DPRINTF( "%08lx:Ret  %s() retval=%08lx ret=%08lx fs=%04lx\n",
483                  GetCurrentThreadId(),
484                  buffer, context->Eax, context->Eip, context->SegFs );
485
486         DPRINTF(" eax=%08lx ebx=%08lx ecx=%08lx edx=%08lx esi=%08lx edi=%08lx\n",
487                 context->Eax, context->Ebx, context->Ecx,
488                 context->Edx, context->Esi, context->Edi );
489         DPRINTF(" ebp=%08lx esp=%08lx ds=%04lx es=%04lx gs=%04lx flags=%08lx\n",
490                 context->Ebp, context->Esp, context->SegDs,
491                 context->SegEs, context->SegGs, context->EFlags );
492     }
493 }
494
495 void WINAPI RELAY_CallFrom32Regs(void);
496 __ASM_GLOBAL_FUNC( RELAY_CallFrom32Regs,
497                    "call " __ASM_NAME("__wine_call_from_32_regs") "\n\t"
498                    ".long " __ASM_NAME("RELAY_DoCallFrom32Regs") ",0" );
499
500 /***********************************************************************
501  *           RELAY_SetupDLL
502  *
503  * Setup relay debugging for a built-in dll.
504  */
505 void RELAY_SetupDLL( const char *module )
506 {
507     IMAGE_DATA_DIRECTORY *dir;
508     IMAGE_EXPORT_DIRECTORY *exports;
509     DEBUG_ENTRY_POINT *debug;
510     DWORD *funcs;
511     int i;
512     const char *name;
513     char *p, dllname[80];
514
515     dir = &PE_HEADER(module)->OptionalHeader.DataDirectory[IMAGE_FILE_EXPORT_DIRECTORY];
516     if (!dir->Size) return;
517     exports = (IMAGE_EXPORT_DIRECTORY *)(module + dir->VirtualAddress);
518     debug = (DEBUG_ENTRY_POINT *)((char *)exports + dir->Size);
519     funcs = (DWORD *)(module + exports->AddressOfFunctions);
520     strcpy( dllname, module + exports->Name );
521     p = dllname + strlen(dllname) - 4;
522     if (p > dllname && !strcasecmp( p, ".dll" )) *p = 0;
523
524     for (i = 0; i < exports->NumberOfFunctions; i++, funcs++, debug++)
525     {
526         int on = 1;
527
528         if (!debug->call) continue;  /* not a normal function */
529         if (debug->call != 0xe8 && debug->call != 0xe9) break; /* not a debug thunk at all */
530
531         if ((name = find_exported_name( module, exports, i + exports->Base )))
532             on = check_relay_include( dllname, name );
533
534         if (on)
535         {
536             debug->call = 0xe8;  /* call relative */
537             if (debug->args & 0x8000)  /* register func */
538                 debug->callfrom32 = (char *)RELAY_CallFrom32Regs - (char *)&debug->ret;
539             else
540                 debug->callfrom32 = (char *)RELAY_CallFrom32 - (char *)&debug->ret;
541         }
542         else
543         {
544             debug->call = 0xe9;  /* jmp relative */
545             debug->callfrom32 = (char *)debug->orig - (char *)&debug->ret;
546         }
547
548         debug->orig = (FARPROC)(module + (DWORD)*funcs);
549         *funcs = (char *)debug - module;
550     }
551 }
552
553 #else  /* __i386__ */
554
555 void RELAY_SetupDLL( const char *module )
556 {
557 }
558
559 #endif /* __i386__ */