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