- sorted API by groups
[wine] / relay32 / relay386.c
1 /*
2  * 386-specific Win32 relay functions
3  *
4  * Copyright 1997 Alexandre Julliard
5  */
6
7
8 #include <assert.h>
9 #include <string.h>
10 #include "winnt.h"
11 #include "builtin32.h"
12 #include "selectors.h"
13 #include "debugstr.h"
14 #include "debug.h"
15 #include "main.h"
16
17 char **debug_relay_excludelist = NULL, **debug_relay_includelist = NULL;
18
19 #ifdef __i386__
20 /***********************************************************************
21  *           RELAY_ShowDebugmsgRelay
22  *
23  * Simple function to decide if a particular debugging message is
24  * wanted.  Called from RELAY_CallFrom32 and from in if1632/relay.c
25  */
26 int RELAY_ShowDebugmsgRelay(const char *func) {
27
28   if(debug_relay_excludelist || debug_relay_includelist) {
29     const char *term = strchr(func, ':');
30     char **listitem;
31     int len, len2, itemlen, show;
32
33     if(debug_relay_excludelist) {
34       show = 1;
35       listitem = debug_relay_excludelist;
36     } else {
37       show = 0;
38       listitem = debug_relay_includelist;
39     }
40     assert(term);
41     assert(strlen(term) > 2);
42     len = term - func;
43     len2 = strchr(func, '.') - func;
44     assert(len2 && len2 > 0 && len2 < 64);
45     term += 2;
46     for(; *listitem; listitem++) {
47       itemlen = strlen(*listitem);
48       if((itemlen == len && !strncmp(*listitem, func, len)) ||
49          (itemlen == len2 && !strncmp(*listitem, func, len2)) ||
50          !strcmp(*listitem, term)) {
51         show = !show;
52        break;
53       }
54     }
55     return show;
56   }
57   return 1;
58 }
59
60 /***********************************************************************
61  *           RELAY_CallFrom32
62  *
63  * Stack layout on entry to this function:
64  *  ...      ...
65  * (esp+12)  arg2
66  * (esp+8)   arg1
67  * (esp+4)   ret_addr
68  * (esp)     return addr to relay code
69  */
70 int RELAY_CallFrom32( int ret_addr, ... )
71 {
72     int i, ret;
73     char buffer[80];
74     FARPROC func;
75     unsigned int mask, typemask;
76     WORD fs;
77
78     int *args = &ret_addr;
79     /* Relay addr is the return address for this function */
80     BYTE *relay_addr = (BYTE *)args[-1];
81     WORD nb_args = *(WORD *)(relay_addr + 1) / sizeof(int);
82
83     assert(TRACE_ON(relay));
84     func = (FARPROC)BUILTIN32_GetEntryPoint( buffer, relay_addr - 5,
85                                                &typemask );
86       DPRINTF( "Call %s(", buffer );
87       args++;
88       for (i = 0, mask = 3; i < nb_args; i++, mask <<= 2)
89       {
90         if (i) DPRINTF( "," );
91         if ((typemask & mask) && HIWORD(args[i]))
92         {
93             if (typemask & (2<<(2*i)))
94                 DPRINTF( "%08x L%s", args[i], debugstr_w((LPWSTR)args[i]) );
95             else
96                 DPRINTF( "%08x %s", args[i], debugstr_a((LPCSTR)args[i]) );
97         }
98         else DPRINTF( "%08x", args[i] );
99       }
100       GET_FS( fs );
101       DPRINTF( ") ret=%08x fs=%04x\n", ret_addr, fs );
102
103     if (*relay_addr == 0xc3) /* cdecl */
104     {
105         LRESULT (*cfunc)() = (LRESULT(*)())func;
106         switch(nb_args)
107         {
108         case 0: ret = cfunc(); break;
109         case 1: ret = cfunc(args[0]); break;
110         case 2: ret = cfunc(args[0],args[1]); break;
111         case 3: ret = cfunc(args[0],args[1],args[2]); break;
112         case 4: ret = cfunc(args[0],args[1],args[2],args[3]); break;
113         case 5: ret = cfunc(args[0],args[1],args[2],args[3],args[4]); break;
114         case 6: ret = cfunc(args[0],args[1],args[2],args[3],args[4],
115                             args[5]); break;
116         case 7: ret = cfunc(args[0],args[1],args[2],args[3],args[4],args[5],
117                             args[6]); break;
118         case 8: ret = cfunc(args[0],args[1],args[2],args[3],args[4],args[5],
119                             args[6],args[7]); break;
120         case 9: ret = cfunc(args[0],args[1],args[2],args[3],args[4],args[5],
121                             args[6],args[7],args[8]); break;
122         case 10: ret = cfunc(args[0],args[1],args[2],args[3],args[4],args[5],
123                              args[6],args[7],args[8],args[9]); break;
124         case 11: ret = cfunc(args[0],args[1],args[2],args[3],args[4],args[5],
125                              args[6],args[7],args[8],args[9],args[10]); break;
126         case 12: ret = cfunc(args[0],args[1],args[2],args[3],args[4],args[5],
127                              args[6],args[7],args[8],args[9],args[10],
128                              args[11]); break;
129         case 13: ret = cfunc(args[0],args[1],args[2],args[3],args[4],args[5],
130                              args[6],args[7],args[8],args[9],args[10],args[11],
131                              args[12]); break;
132         case 14: ret = cfunc(args[0],args[1],args[2],args[3],args[4],args[5],
133                              args[6],args[7],args[8],args[9],args[10],args[11],
134                              args[12],args[13]); break;
135         case 15: ret = cfunc(args[0],args[1],args[2],args[3],args[4],args[5],
136                              args[6],args[7],args[8],args[9],args[10],args[11],
137                              args[12],args[13],args[14]); break;
138         case 16: ret = cfunc(args[0],args[1],args[2],args[3],args[4],args[5],
139                              args[6],args[7],args[8],args[9],args[10],args[11],
140                              args[12],args[13],args[14],args[15]); break;
141         default:
142             ERR(relay, "Unsupported nb args %d\n",
143                      nb_args );
144             assert(FALSE);
145         }
146     }
147     else  /* stdcall */
148     {
149         switch(nb_args)
150         {
151         case 0: ret = func(); break;
152         case 1: ret = func(args[0]); break;
153         case 2: ret = func(args[0],args[1]); break;
154         case 3: ret = func(args[0],args[1],args[2]); break;
155         case 4: ret = func(args[0],args[1],args[2],args[3]); break;
156         case 5: ret = func(args[0],args[1],args[2],args[3],args[4]); break;
157         case 6: ret = func(args[0],args[1],args[2],args[3],args[4],
158                            args[5]); break;
159         case 7: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
160                            args[6]); break;
161         case 8: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
162                            args[6],args[7]); break;
163         case 9: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
164                            args[6],args[7],args[8]); break;
165         case 10: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
166                             args[6],args[7],args[8],args[9]); break;
167         case 11: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
168                             args[6],args[7],args[8],args[9],args[10]); break;
169         case 12: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
170                             args[6],args[7],args[8],args[9],args[10],
171                             args[11]); break;
172         case 13: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
173                             args[6],args[7],args[8],args[9],args[10],args[11],
174                             args[12]); break;
175         case 14: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
176                             args[6],args[7],args[8],args[9],args[10],args[11],
177                             args[12],args[13]); break;
178         case 15: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
179                             args[6],args[7],args[8],args[9],args[10],args[11],
180                             args[12],args[13],args[14]); break;
181         case 16: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
182                             args[6],args[7],args[8],args[9],args[10],args[11],
183                             args[12],args[13],args[14],args[15]); break;
184         default:
185             ERR(relay, "Unsupported nb args %d\n",nb_args );
186             assert(FALSE);
187         }
188     }
189     DPRINTF( "Ret  %s() retval=%08x ret=%08x fs=%04x\n",
190              buffer, ret, ret_addr, fs );
191     return ret;
192 }
193
194
195 /***********************************************************************
196  *           RELAY_CallFrom32Regs
197  *
198  * 'context' contains the register contents at the point of call of
199  * the REG_ENTRY_POINT. The stack layout of the stack pointed to by
200  * ESP_reg(&context) is as follows:
201  *
202  * If debugmsg(relay) is OFF:
203  *  ...    ...
204  * (esp+4) args
205  * (esp)   return addr to caller
206  * (esp-4) function entry point
207  *
208  * If debugmsg(relay) is ON:
209  *  ...    ...
210  * (esp+8) args
211  * (esp+4) return addr to caller
212  * (esp)   return addr to DEBUG_ENTRY_POINT
213  * (esp-4) function entry point
214  *
215  * As the called function might change the stack layout
216  * (e.g. FT_Prolog, FT_ExitNN), we remove all modifications to the stack,
217  * so that the called function sees (in both cases):
218  *
219  *  ...    ...
220  * (esp+4) args
221  * (esp)   return addr to caller
222  *  ...    >128 bytes space free to be modified (ensured by the assembly glue)
223  *
224  * NOTE: This routine makes no assumption about the relative position of
225  *       its own stack to the stack pointed to by ESP_reg(&context),
226  *       except that the latter must have >128 bytes space to grow.
227  *       This means the assembly glue could even switch stacks completely
228  *       (e.g. to allow for large stacks).
229  *
230  */
231
232 void RELAY_CallFrom32Regs( CONTEXT context )
233 {
234     typedef void (CALLBACK *entry_point_t)(CONTEXT *);
235     entry_point_t entry_point = *(entry_point_t*) (ESP_reg(&context) - 4);
236
237     __RESTORE_ES;
238
239     if (!TRACE_ON(relay))
240     {
241         /* Simply call the entry point */
242         entry_point( &context );
243     }
244     else
245     {
246         char buffer[80];
247         unsigned int typemask;
248         BYTE *relay_addr;
249
250         /*
251          * Fixup the context structure because of the extra parameter
252          * pushed by the relay debugging code.
253          * Note that this implicitly does a RET on the CALL from the
254          * DEBUG_ENTRY_POINT to the REG_ENTRY_POINT;  setting the EIP register
255          * ensures that the assembly glue will directly return to the
256          * caller, just as in the non-debugging case.
257          */
258
259         relay_addr = *(BYTE **) ESP_reg(&context); 
260         if (BUILTIN32_GetEntryPoint( buffer, relay_addr - 5, &typemask )) {
261             /* correct win32 spec generated register function found. 
262              * remove extra call stuff from stack
263              */
264             ESP_reg(&context) += sizeof(BYTE *);
265             EIP_reg(&context) = *(DWORD *)ESP_reg(&context);
266             DPRINTF("Call %s(regs) ret=%08x\n", buffer, *(int *)ESP_reg(&context) );
267             DPRINTF(" EAX=%08lx EBX=%08lx ECX=%08lx EDX=%08lx ESI=%08lx EDI=%08lx\n",
268                     EAX_reg(&context), EBX_reg(&context), ECX_reg(&context),
269                     EDX_reg(&context), ESI_reg(&context), EDI_reg(&context) );
270             DPRINTF(" EBP=%08lx ESP=%08lx EIP=%08lx DS=%04lx ES=%04lx FS=%04lx GS=%04lx EFL=%08lx\n",
271                     EBP_reg(&context), ESP_reg(&context), EIP_reg(&context),
272                     DS_reg(&context), ES_reg(&context), FS_reg(&context),
273                     GS_reg(&context), EFL_reg(&context) );
274
275             /* Now call the real function */
276             entry_point( &context );
277
278
279             DPRINTF("Ret  %s() retval=regs ret=%08x\n", buffer, *(int *)ESP_reg(&context) );
280             DPRINTF(" EAX=%08lx EBX=%08lx ECX=%08lx EDX=%08lx ESI=%08lx EDI=%08lx\n",
281                     EAX_reg(&context), EBX_reg(&context), ECX_reg(&context),
282                     EDX_reg(&context), ESI_reg(&context), EDI_reg(&context) );
283             DPRINTF(" EBP=%08lx ESP=%08lx EIP=%08lx DS=%04lx ES=%04lx FS=%04lx GS=%04lx EFL=%08lx\n",
284                     EBP_reg(&context), ESP_reg(&context), EIP_reg(&context),
285                     DS_reg(&context), ES_reg(&context), FS_reg(&context),
286                     GS_reg(&context), EFL_reg(&context) );
287         } else
288             /* WINE internal register function found. Do not remove anything.
289              * Do not print any debuginfo (it is not a normal relayed one).
290              * Currently only used for snooping.
291              */
292            entry_point( &context );
293     }
294 }
295 #endif  /* __i386__ */