Added regedit unit test, a couple minor changes to regedit.
[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 = strchr( *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 )) 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 *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     if ((name = find_exported_name( base, exp, ordinal + exp->Base )))
230         sprintf( buffer, "%s.%s", base + exp->Name, name );
231     else
232         sprintf( buffer, "%s.%ld", base + exp->Name, ordinal + exp->Base );
233 }
234
235
236 /***********************************************************************
237  *           RELAY_PrintArgs
238  */
239 static inline void RELAY_PrintArgs( int *args, int nb_args, unsigned int typemask )
240 {
241     while (nb_args--)
242     {
243         if ((typemask & 3) && HIWORD(*args))
244         {
245             if (typemask & 2)
246                 DPRINTF( "%08x %s", *args, debugstr_w((LPWSTR)*args) );
247             else
248                 DPRINTF( "%08x %s", *args, debugstr_a((LPCSTR)*args) );
249         }
250         else DPRINTF( "%08x", *args );
251         if (nb_args) DPRINTF( "," );
252         args++;
253         typemask >>= 2;
254     }
255 }
256
257
258 typedef LONGLONG (*LONGLONG_CPROC)();
259 typedef LONGLONG (WINAPI *LONGLONG_FARPROC)();
260
261
262 /***********************************************************************
263  *           call_cdecl_function
264  */
265 static LONGLONG call_cdecl_function( LONGLONG_CPROC func, int nb_args, const int *args )
266 {
267     LONGLONG ret;
268     switch(nb_args)
269     {
270     case 0: ret = func(); break;
271     case 1: ret = func(args[0]); break;
272     case 2: ret = func(args[0],args[1]); break;
273     case 3: ret = func(args[0],args[1],args[2]); break;
274     case 4: ret = func(args[0],args[1],args[2],args[3]); break;
275     case 5: ret = func(args[0],args[1],args[2],args[3],args[4]); break;
276     case 6: ret = func(args[0],args[1],args[2],args[3],args[4],
277                        args[5]); break;
278     case 7: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
279                        args[6]); break;
280     case 8: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
281                        args[6],args[7]); break;
282     case 9: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
283                        args[6],args[7],args[8]); break;
284     case 10: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
285                         args[6],args[7],args[8],args[9]); break;
286     case 11: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
287                         args[6],args[7],args[8],args[9],args[10]); break;
288     case 12: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
289                         args[6],args[7],args[8],args[9],args[10],
290                         args[11]); break;
291     case 13: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
292                         args[6],args[7],args[8],args[9],args[10],args[11],
293                         args[12]); break;
294     case 14: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
295                         args[6],args[7],args[8],args[9],args[10],args[11],
296                         args[12],args[13]); break;
297     case 15: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
298                         args[6],args[7],args[8],args[9],args[10],args[11],
299                         args[12],args[13],args[14]); break;
300     case 16: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
301                         args[6],args[7],args[8],args[9],args[10],args[11],
302                         args[12],args[13],args[14],args[15]); break;
303     default:
304         ERR( "Unsupported nb of args %d\n", nb_args );
305         assert(FALSE);
306     }
307     return ret;
308 }
309
310
311 /***********************************************************************
312  *           call_stdcall_function
313  */
314 static LONGLONG call_stdcall_function( LONGLONG_FARPROC func, int nb_args, const int *args )
315 {
316     LONGLONG ret;
317     switch(nb_args)
318     {
319     case 0: ret = func(); break;
320     case 1: ret = func(args[0]); break;
321     case 2: ret = func(args[0],args[1]); break;
322     case 3: ret = func(args[0],args[1],args[2]); break;
323     case 4: ret = func(args[0],args[1],args[2],args[3]); break;
324     case 5: ret = func(args[0],args[1],args[2],args[3],args[4]); break;
325     case 6: ret = func(args[0],args[1],args[2],args[3],args[4],
326                        args[5]); break;
327     case 7: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
328                        args[6]); break;
329     case 8: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
330                        args[6],args[7]); break;
331     case 9: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
332                        args[6],args[7],args[8]); break;
333     case 10: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
334                         args[6],args[7],args[8],args[9]); break;
335     case 11: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
336                         args[6],args[7],args[8],args[9],args[10]); break;
337     case 12: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
338                         args[6],args[7],args[8],args[9],args[10],
339                         args[11]); break;
340     case 13: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
341                         args[6],args[7],args[8],args[9],args[10],args[11],
342                         args[12]); break;
343     case 14: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
344                         args[6],args[7],args[8],args[9],args[10],args[11],
345                         args[12],args[13]); break;
346     case 15: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
347                         args[6],args[7],args[8],args[9],args[10],args[11],
348                         args[12],args[13],args[14]); break;
349     case 16: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
350                         args[6],args[7],args[8],args[9],args[10],args[11],
351                         args[12],args[13],args[14],args[15]); break;
352     default:
353         ERR( "Unsupported nb of args %d\n", nb_args );
354         assert(FALSE);
355     }
356     return ret;
357 }
358
359
360 /***********************************************************************
361  *           RELAY_CallFrom32
362  *
363  * Stack layout on entry to this function:
364  *  ...      ...
365  * (esp+12)  arg2
366  * (esp+8)   arg1
367  * (esp+4)   ret_addr
368  * (esp)     return addr to relay code
369  */
370 static LONGLONG RELAY_CallFrom32( int ret_addr, ... )
371 {
372     LONGLONG ret;
373     char buffer[80];
374
375     int *args = &ret_addr + 1;
376     /* Relay addr is the return address for this function */
377     BYTE *relay_addr = (BYTE *)__builtin_return_address(0);
378     DEBUG_ENTRY_POINT *relay = (DEBUG_ENTRY_POINT *)(relay_addr - 5);
379     WORD nb_args = relay->args / sizeof(int);
380
381     if (TRACE_ON(relay))
382     {
383         get_entry_point( buffer, relay );
384
385         DPRINTF( "%08lx:Call %s(", GetCurrentThreadId(), buffer );
386         RELAY_PrintArgs( args, nb_args, relay->argtypes );
387         DPRINTF( ") ret=%08x\n", ret_addr );
388     }
389
390     if (relay->ret == 0xc3) /* cdecl */
391     {
392         ret = call_cdecl_function( (LONGLONG_CPROC)relay->orig, nb_args, args );
393     }
394     else  /* stdcall */
395     {
396         ret = call_stdcall_function( (LONGLONG_FARPROC)relay->orig, nb_args, args );
397     }
398
399     if (TRACE_ON(relay))
400     {
401         BOOL ret64 = (relay->argtypes & 0x80000000) && (nb_args < 16);
402         if (ret64)
403             DPRINTF( "%08lx:Ret  %s() retval=%08x%08x ret=%08x\n",
404                      GetCurrentThreadId(),
405                      buffer, (UINT)(ret >> 32), (UINT)ret, ret_addr );
406         else
407             DPRINTF( "%08lx:Ret  %s() retval=%08x ret=%08x\n",
408                      GetCurrentThreadId(),
409                      buffer, (UINT)ret, ret_addr );
410     }
411     return ret;
412 }
413
414
415 /***********************************************************************
416  *           RELAY_CallFrom32Regs
417  *
418  * Stack layout (esp is context->Esp, not the current %esp):
419  *
420  * ...
421  * (esp+4) first arg
422  * (esp)   return addr to caller
423  * (esp-4) return addr to DEBUG_ENTRY_POINT
424  * (esp-8) ptr to relay entry code for RELAY_CallFrom32Regs
425  *  ...    >128 bytes space free to be modified (ensured by the assembly glue)
426  */
427 void WINAPI RELAY_DoCallFrom32Regs( CONTEXT86 *context )
428 {
429     char buffer[80];
430     int* args;
431     int args_copy[17];
432     BYTE *entry_point;
433
434     BYTE *relay_addr = *((BYTE **)context->Esp - 1);
435     DEBUG_ENTRY_POINT *relay = (DEBUG_ENTRY_POINT *)(relay_addr - 5);
436     WORD nb_args = (relay->args & ~0x8000) / sizeof(int);
437
438     /* remove extra stuff from the stack */
439     context->Eip = stack32_pop(context);
440     args = (int *)context->Esp;
441     if (relay->ret == 0xc2) /* stdcall */
442         context->Esp += nb_args * sizeof(int);
443
444     entry_point = (BYTE *)relay->orig;
445     assert( *entry_point == 0xe8 /* lcall */ );
446
447     if (TRACE_ON(relay))
448     {
449         get_entry_point( buffer, relay );
450
451         DPRINTF( "%08lx:Call %s(", GetCurrentThreadId(), buffer );
452         RELAY_PrintArgs( args, nb_args, relay->argtypes );
453         DPRINTF( ") ret=%08lx fs=%04lx\n", context->Eip, context->SegFs );
454
455         DPRINTF(" eax=%08lx ebx=%08lx ecx=%08lx edx=%08lx esi=%08lx edi=%08lx\n",
456                 context->Eax, context->Ebx, context->Ecx,
457                 context->Edx, context->Esi, context->Edi );
458         DPRINTF(" ebp=%08lx esp=%08lx ds=%04lx es=%04lx gs=%04lx flags=%08lx\n",
459                 context->Ebp, context->Esp, context->SegDs,
460                 context->SegEs, context->SegGs, context->EFlags );
461     }
462
463     /* Now call the real function */
464
465     memcpy( args_copy, args, nb_args * sizeof(args[0]) );
466     args_copy[nb_args] = (int)context;  /* append context argument */
467     if (relay->ret == 0xc3) /* cdecl */
468     {
469         call_cdecl_function( *(LONGLONG_CPROC *)(entry_point + 5), nb_args+1, args_copy );
470     }
471     else  /* stdcall */
472     {
473         call_stdcall_function( *(LONGLONG_FARPROC *)(entry_point + 5), nb_args+1, args_copy );
474     }
475
476     if (TRACE_ON(relay))
477     {
478         DPRINTF( "%08lx:Ret  %s() retval=%08lx ret=%08lx fs=%04lx\n",
479                  GetCurrentThreadId(),
480                  buffer, context->Eax, context->Eip, context->SegFs );
481
482         DPRINTF(" eax=%08lx ebx=%08lx ecx=%08lx edx=%08lx esi=%08lx edi=%08lx\n",
483                 context->Eax, context->Ebx, context->Ecx,
484                 context->Edx, context->Esi, context->Edi );
485         DPRINTF(" ebp=%08lx esp=%08lx ds=%04lx es=%04lx gs=%04lx flags=%08lx\n",
486                 context->Ebp, context->Esp, context->SegDs,
487                 context->SegEs, context->SegGs, context->EFlags );
488     }
489 }
490
491 void WINAPI RELAY_CallFrom32Regs(void);
492 __ASM_GLOBAL_FUNC( RELAY_CallFrom32Regs,
493                    "call " __ASM_NAME("__wine_call_from_32_regs") "\n\t"
494                    ".long " __ASM_NAME("RELAY_DoCallFrom32Regs") ",0" );
495
496 /***********************************************************************
497  *           RELAY_SetupDLL
498  *
499  * Setup relay debugging for a built-in dll.
500  */
501 void RELAY_SetupDLL( const char *module )
502 {
503     IMAGE_DATA_DIRECTORY *dir;
504     IMAGE_EXPORT_DIRECTORY *exports;
505     DEBUG_ENTRY_POINT *debug;
506     DWORD *funcs;
507     int i;
508     const char *name, *dllname;
509
510     dir = &PE_HEADER(module)->OptionalHeader.DataDirectory[IMAGE_FILE_EXPORT_DIRECTORY];
511     if (!dir->Size) return;
512     exports = (IMAGE_EXPORT_DIRECTORY *)(module + dir->VirtualAddress);
513     debug = (DEBUG_ENTRY_POINT *)((char *)exports + dir->Size);
514     funcs = (DWORD *)(module + exports->AddressOfFunctions);
515     dllname = module + exports->Name;
516
517     for (i = 0; i < exports->NumberOfFunctions; i++, funcs++, debug++)
518     {
519         int on = 1;
520
521         if (!debug->call) continue;  /* not a normal function */
522         if (debug->call != 0xe8 && debug->call != 0xe9) break; /* not a debug thunk at all */
523
524         if ((name = find_exported_name( module, exports, i + exports->Base )))
525             on = check_relay_include( dllname, name );
526
527         if (on)
528         {
529             debug->call = 0xe8;  /* call relative */
530             if (debug->args & 0x8000)  /* register func */
531                 debug->callfrom32 = (char *)RELAY_CallFrom32Regs - (char *)&debug->ret;
532             else
533                 debug->callfrom32 = (char *)RELAY_CallFrom32 - (char *)&debug->ret;
534         }
535         else
536         {
537             debug->call = 0xe9;  /* jmp relative */
538             debug->callfrom32 = (char *)debug->orig - (char *)&debug->ret;
539         }
540
541         debug->orig = (FARPROC)(module + (DWORD)*funcs);
542         *funcs = (char *)debug - module;
543     }
544 }
545
546 #else  /* __i386__ */
547
548 void RELAY_SetupDLL( const char *module )
549 {
550 }
551
552 #endif /* __i386__ */