2 * 386-specific Win32 relay functions
4 * Copyright 1997 Alexandre Julliard
12 #include "builtin32.h"
13 #include "selectors.h"
17 /***********************************************************************
20 * Stack layout on entry to this function:
25 * (esp) return addr to relay code
27 int RELAY_CallFrom32( int ret_addr
, ... )
32 unsigned int mask
, typemask
;
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);
40 assert(TRACE_ON(relay
));
41 func
= (FARPROC32
)BUILTIN32_GetEntryPoint( buffer
, relay_addr
- 5,
43 printf( "Call %s(", buffer
);
45 for (i
= 0, mask
= 3; i
< nb_args
; i
++, mask
<<= 2)
48 if ((typemask
& mask
) && HIWORD(args
[i
]))
50 if (typemask
& (2<<(2*i
)))
53 lstrcpynWtoA( buff
, (LPWSTR
)args
[i
], sizeof(buff
) );
54 buff
[sizeof(buff
)-1]='\0';
55 printf( "%08x L", args
[i
] );
56 debug_dumpstr( buff
);
59 printf( "%08x ", args
[i
] );
60 debug_dumpstr((LPCSTR
)args
[i
]);
63 else printf( "%08x", args
[i
] );
66 printf( ") ret=%08x fs=%04x\n", ret_addr
, fs
);
67 if (*relay_addr
== 0xc3) /* cdecl */
69 LRESULT (*cfunc
)() = (LRESULT(*)())func
;
72 case 0: ret
= cfunc(); break;
73 case 1: ret
= cfunc(args
[0]); break;
74 case 2: ret
= cfunc(args
[0],args
[1]); break;
75 case 3: ret
= cfunc(args
[0],args
[1],args
[2]); break;
76 case 4: ret
= cfunc(args
[0],args
[1],args
[2],args
[3]); break;
77 case 5: ret
= cfunc(args
[0],args
[1],args
[2],args
[3],args
[4]); break;
78 case 6: ret
= cfunc(args
[0],args
[1],args
[2],args
[3],args
[4],
80 case 7: ret
= cfunc(args
[0],args
[1],args
[2],args
[3],args
[4],args
[5],
82 case 8: ret
= cfunc(args
[0],args
[1],args
[2],args
[3],args
[4],args
[5],
83 args
[6],args
[7]); break;
84 case 9: ret
= cfunc(args
[0],args
[1],args
[2],args
[3],args
[4],args
[5],
85 args
[6],args
[7],args
[8]); break;
86 case 10: ret
= cfunc(args
[0],args
[1],args
[2],args
[3],args
[4],args
[5],
87 args
[6],args
[7],args
[8],args
[9]); break;
88 case 11: 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]); break;
90 case 12: ret
= cfunc(args
[0],args
[1],args
[2],args
[3],args
[4],args
[5],
91 args
[6],args
[7],args
[8],args
[9],args
[10],
93 case 13: ret
= cfunc(args
[0],args
[1],args
[2],args
[3],args
[4],args
[5],
94 args
[6],args
[7],args
[8],args
[9],args
[10],args
[11],
96 case 14: ret
= cfunc(args
[0],args
[1],args
[2],args
[3],args
[4],args
[5],
97 args
[6],args
[7],args
[8],args
[9],args
[10],args
[11],
98 args
[12],args
[13]); break;
99 case 15: ret
= cfunc(args
[0],args
[1],args
[2],args
[3],args
[4],args
[5],
100 args
[6],args
[7],args
[8],args
[9],args
[10],args
[11],
101 args
[12],args
[13],args
[14]); break;
103 fprintf( stderr
, "RELAY_CallFrom32: Unsupported nb args %d\n",
112 case 0: ret
= func(); break;
113 case 1: ret
= func(args
[0]); break;
114 case 2: ret
= func(args
[0],args
[1]); break;
115 case 3: ret
= func(args
[0],args
[1],args
[2]); break;
116 case 4: ret
= func(args
[0],args
[1],args
[2],args
[3]); break;
117 case 5: ret
= func(args
[0],args
[1],args
[2],args
[3],args
[4]); break;
118 case 6: ret
= func(args
[0],args
[1],args
[2],args
[3],args
[4],
120 case 7: ret
= func(args
[0],args
[1],args
[2],args
[3],args
[4],args
[5],
122 case 8: ret
= func(args
[0],args
[1],args
[2],args
[3],args
[4],args
[5],
123 args
[6],args
[7]); break;
124 case 9: ret
= func(args
[0],args
[1],args
[2],args
[3],args
[4],args
[5],
125 args
[6],args
[7],args
[8]); break;
126 case 10: ret
= func(args
[0],args
[1],args
[2],args
[3],args
[4],args
[5],
127 args
[6],args
[7],args
[8],args
[9]); break;
128 case 11: 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]); break;
130 case 12: ret
= func(args
[0],args
[1],args
[2],args
[3],args
[4],args
[5],
131 args
[6],args
[7],args
[8],args
[9],args
[10],
133 case 13: ret
= func(args
[0],args
[1],args
[2],args
[3],args
[4],args
[5],
134 args
[6],args
[7],args
[8],args
[9],args
[10],args
[11],
136 case 14: ret
= func(args
[0],args
[1],args
[2],args
[3],args
[4],args
[5],
137 args
[6],args
[7],args
[8],args
[9],args
[10],args
[11],
138 args
[12],args
[13]); break;
139 case 15: ret
= func(args
[0],args
[1],args
[2],args
[3],args
[4],args
[5],
140 args
[6],args
[7],args
[8],args
[9],args
[10],args
[11],
141 args
[12],args
[13],args
[14]); break;
143 fprintf( stderr
, "RELAY_CallFrom32: Unsupported nb args %d\n",
148 printf( "Ret %s() retval=%08x ret=%08x fs=%04x\n",
149 buffer
, ret
, ret_addr
, fs
);
154 /***********************************************************************
155 * RELAY_CallFrom32Regs
157 * 'context' contains the register contents at the point of call of
158 * the REG_ENTRY_POINT. The stack layout of the stack pointed to by
159 * ESP_reg(&context) is as follows:
161 * If debugmsg(relay) is OFF:
164 * (esp) return addr to caller
165 * (esp-4) function entry point
167 * If debugmsg(relay) is ON:
170 * (esp+4) return addr to caller
171 * (esp) return addr to DEBUG_ENTRY_POINT
172 * (esp-4) function entry point
174 * As the called function might change the stack layout
175 * (e.g. FT_Prolog, FT_ExitNN), we remove all modifications to the stack,
176 * so that the called function sees (in both cases):
180 * (esp) return addr to caller
181 * ... >128 bytes space free to be modified (ensured by the assembly glue)
183 * NOTE: This routine makes no assumption about the relative position of
184 * its own stack to the stack pointed to by ESP_reg(&context),
185 * except that the latter must have >128 bytes space to grow.
186 * This means the assembly glue could even switch stacks completely
187 * (e.g. to allow for large stacks).
191 void RELAY_CallFrom32Regs( CONTEXT context
)
193 typedef void (CALLBACK
*entry_point_t
)(CONTEXT
*);
194 entry_point_t entry_point
= *(entry_point_t
*) (ESP_reg(&context
) - 4);
196 if (!TRACE_ON(relay
))
198 /* Simply call the entry point */
199 entry_point( &context
);
204 unsigned int typemask
;
210 * Fixup the context structure because of the extra parameter
211 * pushed by the relay debugging code.
212 * Note that this implicitly does a RET on the CALL from the
213 * DEBUG_ENTRY_POINT to the REG_ENTRY_POINT; setting the EIP register
214 * ensures that the assembly glue will directly return to the
215 * caller, just as in the non-debugging case.
218 relay_addr
= *(BYTE
**) ESP_reg(&context
);
219 ESP_reg(&context
) += sizeof(BYTE
*);
220 EIP_reg(&context
) = *(DWORD
*)ESP_reg(&context
);
222 BUILTIN32_GetEntryPoint( buffer
, relay_addr
- 5, &typemask
);
223 printf("Call %s(regs) ret=%08x\n", buffer
, *(int *)ESP_reg(&context
) );
224 printf(" EAX=%08lx EBX=%08lx ECX=%08lx EDX=%08lx ESI=%08lx EDI=%08lx\n",
225 EAX_reg(&context
), EBX_reg(&context
), ECX_reg(&context
),
226 EDX_reg(&context
), ESI_reg(&context
), EDI_reg(&context
) );
227 printf(" EBP=%08lx ESP=%08lx EIP=%08lx DS=%04lx ES=%04lx FS=%04lx GS=%04lx EFL=%08lx\n",
228 EBP_reg(&context
), ESP_reg(&context
), EIP_reg(&context
),
229 DS_reg(&context
), ES_reg(&context
), FS_reg(&context
),
230 GS_reg(&context
), EFL_reg(&context
) );
232 /* Now call the real function */
233 entry_point( &context
);
235 printf("Ret %s() retval=regs ret=%08x\n", buffer
, *(int *)ESP_reg(&context
) );
236 printf(" EAX=%08lx EBX=%08lx ECX=%08lx EDX=%08lx ESI=%08lx EDI=%08lx\n",
237 EAX_reg(&context
), EBX_reg(&context
), ECX_reg(&context
),
238 EDX_reg(&context
), ESI_reg(&context
), EDI_reg(&context
) );
239 printf(" EBP=%08lx ESP=%08lx EIP=%08lx DS=%04lx ES=%04lx FS=%04lx GS=%04lx EFL=%08lx\n",
240 EBP_reg(&context
), ESP_reg(&context
), EIP_reg(&context
),
241 DS_reg(&context
), ES_reg(&context
), FS_reg(&context
),
242 GS_reg(&context
), EFL_reg(&context
) );
246 #endif /* __i386__ */