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