GlobalSmartPageUnlock() stub added.
[wine/dcerpc.git] / if1632 / relay.c
blob1c0d8264f36aed7cee67a78758fd1741ce79f92a
1 /*
2 * Copyright 1993 Robert J. Amstadt
3 * Copyright 1995 Alexandre Julliard
4 */
6 #include <assert.h>
7 #include <stdlib.h>
8 #include <string.h>
9 #include "wine/winbase16.h"
10 #include "winnt.h"
11 #include "global.h"
12 #include "heap.h"
13 #include "module.h"
14 #include "stackframe.h"
15 #include "task.h"
16 #include "syslevel.h"
17 #include "debugstr.h"
18 #include "debugtools.h"
19 #include "main.h"
21 DEFAULT_DEBUG_CHANNEL(relay)
24 /***********************************************************************
25 * RELAY_Init
27 BOOL RELAY_Init(void)
29 WORD codesel;
31 /* Allocate the code selector for CallTo16 routines */
33 extern void Call16_Ret_Start(), Call16_Ret_End();
34 extern void CallTo16_Ret();
35 extern void CALL32_CBClient_Ret();
36 extern void CALL32_CBClientEx_Ret();
37 extern DWORD CallTo16_RetAddr;
38 extern DWORD CALL32_CBClient_RetAddr;
39 extern DWORD CALL32_CBClientEx_RetAddr;
41 codesel = GLOBAL_CreateBlock( GMEM_FIXED, (void *)Call16_Ret_Start,
42 (int)Call16_Ret_End - (int)Call16_Ret_Start,
43 0, TRUE, TRUE, FALSE, NULL );
44 if (!codesel) return FALSE;
46 /* Patch the return addresses for CallTo16 routines */
48 CallTo16_RetAddr =
49 MAKELONG( (int)CallTo16_Ret -(int)Call16_Ret_Start, codesel );
50 CALL32_CBClient_RetAddr =
51 MAKELONG( (int)CALL32_CBClient_Ret -(int)Call16_Ret_Start, codesel );
52 CALL32_CBClientEx_RetAddr =
53 MAKELONG( (int)CALL32_CBClientEx_Ret -(int)Call16_Ret_Start, codesel );
55 /* Create built-in modules */
56 if (!BUILTIN_Init()) return FALSE;
58 /* Initialize thunking */
59 return THUNK_Init();
63 /* from relay32/relay386.c */
64 extern char **debug_relay_excludelist,**debug_relay_includelist;
66 /***********************************************************************
67 * RELAY_DebugCallFrom16
69 void RELAY_DebugCallFrom16( CONTEXT86 *context )
71 STACK16FRAME *frame;
72 WORD ordinal;
73 char *args16, funstr[80];
74 const char *args;
75 int i, usecdecl, reg_func;
77 if (!TRACE_ON(relay)) return;
79 frame = CURRENT_STACK16;
80 args = BUILTIN_GetEntryPoint16(frame->entry_cs,frame->entry_ip,funstr,&ordinal);
81 if (!args) return; /* happens for the two snoop register relays */
82 if (!RELAY_ShowDebugmsgRelay(funstr)) return;
83 DPRINTF( "Call %s(",funstr);
84 VA_START16( args16 );
86 usecdecl = ( *args == 'c' );
87 args += 2;
88 reg_func = ( memcmp( args, "regs_", 5 ) == 0 );
89 args += 5;
91 if (usecdecl)
93 while (*args)
95 switch(*args)
97 case 'w':
98 case 's':
99 DPRINTF( "0x%04x", *(WORD *)args16 );
100 args16 += 2;
101 break;
102 case 'l':
103 DPRINTF( "0x%08x", *(int *)args16 );
104 args16 += 4;
105 break;
106 case 't':
107 DPRINTF( "%04x:%04x", *(WORD *)(args16+2), *(WORD *)args16 );
108 if (HIWORD(*(SEGPTR *)args16))
109 debug_dumpstr( (LPSTR)PTR_SEG_TO_LIN(*(SEGPTR *)args16 ));
110 args16 += 4;
111 break;
112 case 'p':
113 DPRINTF( "%04x:%04x", *(WORD *)(args16+2), *(WORD *)args16 );
114 args16 += 4;
115 break;
116 case 'T':
117 DPRINTF( "%04x:%04x", *(WORD *)(args16+2), *(WORD *)args16 );
118 if (HIWORD( *(SEGPTR *)args16 ))
119 debug_dumpstr( (LPSTR)PTR_SEG_TO_LIN(*(SEGPTR *)args16 ));
120 args16 += 4;
121 break;
123 args++;
124 if (*args) DPRINTF( "," );
127 else /* not cdecl */
129 /* Start with the last arg */
130 for (i = 0; args[i]; i++)
132 switch(args[i])
134 case 'w':
135 case 's':
136 args16 += 2;
137 break;
138 case 'l':
139 case 'p':
140 case 't':
141 case 'T':
142 args16 += 4;
143 break;
147 while (*args)
149 switch(*args)
151 case 'w':
152 case 's':
153 args16 -= 2;
154 DPRINTF( "0x%04x", *(WORD *)args16 );
155 break;
156 case 'l':
157 args16 -= 4;
158 DPRINTF( "0x%08x", *(int *)args16 );
159 break;
160 case 't':
161 args16 -= 4;
162 DPRINTF( "0x%08x", *(int *)args16 );
163 if (HIWORD(*(SEGPTR *)args16))
164 debug_dumpstr( (LPSTR)PTR_SEG_TO_LIN(*(SEGPTR *)args16 ));
165 break;
166 case 'p':
167 args16 -= 4;
168 DPRINTF( "%04x:%04x", *(WORD *)(args16+2), *(WORD *)args16 );
169 break;
170 case 'T':
171 args16 -= 4;
172 DPRINTF( "%04x:%04x", *(WORD *)(args16+2), *(WORD *)args16 );
173 if (HIWORD( *(SEGPTR *)args16 ))
174 debug_dumpstr( (LPSTR)PTR_SEG_TO_LIN(*(SEGPTR *)args16 ));
175 break;
177 args++;
178 if (*args) DPRINTF( "," );
182 DPRINTF( ") ret=%04x:%04x ds=%04x\n", frame->cs, frame->ip, frame->ds );
183 VA_END16( args16 );
185 if (reg_func)
186 DPRINTF(" AX=%04x BX=%04x CX=%04x DX=%04x SI=%04x DI=%04x ES=%04x EFL=%08lx\n",
187 AX_reg(context), BX_reg(context), CX_reg(context),
188 DX_reg(context), SI_reg(context), DI_reg(context),
189 (WORD)ES_reg(context), EFL_reg(context) );
191 SYSLEVEL_CheckNotLevel( 2 );
195 /***********************************************************************
196 * RELAY_DebugCallFrom16Ret
198 void RELAY_DebugCallFrom16Ret( CONTEXT86 *context, int ret_val )
200 STACK16FRAME *frame;
201 WORD ordinal;
202 char funstr[80];
203 const char *args;
205 if (!TRACE_ON(relay)) return;
206 frame = CURRENT_STACK16;
207 args = BUILTIN_GetEntryPoint16(frame->entry_cs,frame->entry_ip,funstr,&ordinal);
208 if (!args) return;
209 if (!RELAY_ShowDebugmsgRelay(funstr)) return;
210 DPRINTF( "Ret %s() ",funstr);
212 if ( memcmp( args+2, "long_", 5 ) == 0 )
214 DPRINTF( "retval=0x%08x ret=%04x:%04x ds=%04x\n",
215 ret_val, frame->cs, frame->ip, frame->ds );
217 else if ( memcmp( args+2, "word_", 5 ) == 0 )
219 DPRINTF( "retval=0x%04x ret=%04x:%04x ds=%04x\n",
220 ret_val & 0xffff, frame->cs, frame->ip, frame->ds );
222 else if ( memcmp( args+2, "regs_", 5 ) == 0 )
224 DPRINTF("retval=none ret=%04x:%04x ds=%04x\n",
225 (WORD)CS_reg(context), IP_reg(context), (WORD)DS_reg(context));
226 DPRINTF(" AX=%04x BX=%04x CX=%04x DX=%04x SI=%04x DI=%04x ES=%04x EFL=%08lx\n",
227 AX_reg(context), BX_reg(context), CX_reg(context),
228 DX_reg(context), SI_reg(context), DI_reg(context),
229 (WORD)ES_reg(context), EFL_reg(context) );
232 SYSLEVEL_CheckNotLevel( 2 );
236 /***********************************************************************
237 * RELAY_Unimplemented16
239 * This function is called for unimplemented 16-bit entry points (declared
240 * as 'stub' in the spec file).
242 void RELAY_Unimplemented16(void)
244 WORD ordinal;
245 char name[80];
246 STACK16FRAME *frame = CURRENT_STACK16;
247 BUILTIN_GetEntryPoint16(frame->entry_cs,frame->entry_ip,name,&ordinal);
248 MESSAGE("No handler for Win16 routine %s (called from %04x:%04x)\n",
249 name, frame->cs, frame->ip );
250 ExitProcess(1);
254 /***********************************************************************
255 * RELAY_DebugCallTo16
257 * 'stack' points to the called function address on the 32-bit stack.
258 * Stack layout:
259 * ... ...
260 * (stack+8) arg2
261 * (stack+4) arg1
262 * (stack) func to call
264 void RELAY_DebugCallTo16( int* stack, int nb_args )
266 TEB *teb;
268 if (!TRACE_ON(relay)) return;
269 teb = NtCurrentTeb();
271 if (nb_args == -1) /* Register function */
273 CONTEXT86 *context = (CONTEXT86 *)stack[0];
274 WORD *stack16 = (WORD *)THREAD_STACK16(teb);
275 DPRINTF("CallTo16(func=%04lx:%04x,ds=%04lx",
276 CS_reg(context), IP_reg(context), DS_reg(context) );
277 nb_args = stack[1] / sizeof(WORD);
278 while (nb_args--) {
279 --stack16;
280 DPRINTF( ",0x%04x", *stack16 );
282 DPRINTF(") ss:sp=%04x:%04x\n", SELECTOROF(teb->cur_stack),
283 OFFSETOF(teb->cur_stack) );
284 DPRINTF(" AX=%04x BX=%04x CX=%04x DX=%04x SI=%04x DI=%04x BP=%04x ES=%04x FS=%04x\n",
285 AX_reg(context), BX_reg(context), CX_reg(context),
286 DX_reg(context), SI_reg(context), DI_reg(context),
287 BP_reg(context), (WORD)ES_reg(context), (WORD)FS_reg(context) );
289 else
291 DPRINTF("CallTo16(func=%04x:%04x,ds=%04x",
292 HIWORD(stack[0]), LOWORD(stack[0]),
293 SELECTOROF(teb->cur_stack) );
294 stack++;
295 while (nb_args--) {
296 DPRINTF(",0x%04x", *stack );
297 stack++;
299 DPRINTF(") ss:sp=%04x:%04x\n", SELECTOROF(teb->cur_stack),
300 OFFSETOF(teb->cur_stack) );
303 SYSLEVEL_CheckNotLevel( 2 );
307 /***********************************************************************
308 * RELAY_DebugCallTo16Ret
310 void RELAY_DebugCallTo16Ret( int ret_val )
312 if (!TRACE_ON(relay)) return;
314 DPRINTF("CallTo16() ss:sp=%04x:%04x retval=0x%08x\n",
315 SELECTOROF(NtCurrentTeb()->cur_stack),
316 OFFSETOF(NtCurrentTeb()->cur_stack), ret_val);
317 SYSLEVEL_CheckNotLevel( 2 );
321 /**********************************************************************
322 * Catch (KERNEL.55)
324 * Real prototype is:
325 * INT16 WINAPI Catch( LPCATCHBUF lpbuf );
327 void WINAPI Catch16( CONTEXT86 *context )
329 VA_LIST16 valist;
330 SEGPTR buf;
331 LPCATCHBUF lpbuf;
333 VA_START16( valist );
334 buf = VA_ARG16( valist, SEGPTR );
335 lpbuf = (LPCATCHBUF)PTR_SEG_TO_LIN( buf );
336 VA_END16( valist );
338 /* Note: we don't save the current ss, as the catch buffer is */
339 /* only 9 words long. Hopefully no one will have the silly */
340 /* idea to change the current stack before calling Throw()... */
342 /* Windows uses:
343 * lpbuf[0] = ip
344 * lpbuf[1] = cs
345 * lpbuf[2] = sp
346 * lpbuf[3] = bp
347 * lpbuf[4] = si
348 * lpbuf[5] = di
349 * lpbuf[6] = ds
350 * lpbuf[7] = unused
351 * lpbuf[8] = ss
354 lpbuf[0] = IP_reg(context);
355 lpbuf[1] = CS_reg(context);
356 /* Windows pushes 4 more words before saving sp */
357 lpbuf[2] = SP_reg(context) - 4 * sizeof(WORD);
358 lpbuf[3] = BP_reg(context);
359 lpbuf[4] = SI_reg(context);
360 lpbuf[5] = DI_reg(context);
361 lpbuf[6] = DS_reg(context);
362 lpbuf[7] = 0;
363 lpbuf[8] = SS_reg(context);
364 AX_reg(context) = 0; /* Return 0 */
368 /**********************************************************************
369 * Throw (KERNEL.56)
371 * Real prototype is:
372 * INT16 WINAPI Throw( LPCATCHBUF lpbuf, INT16 retval );
374 void WINAPI Throw16( CONTEXT86 *context )
376 VA_LIST16 valist;
377 SEGPTR buf;
378 LPCATCHBUF lpbuf;
379 STACK16FRAME *pFrame;
380 STACK32FRAME *frame32;
381 TEB *teb = NtCurrentTeb();
383 VA_START16( valist );
384 AX_reg(context) = VA_ARG16( valist, WORD ); /* retval */
385 buf = VA_ARG16( valist, SEGPTR );
386 lpbuf = (LPCATCHBUF)PTR_SEG_TO_LIN( buf );
387 VA_END16( valist );
389 /* Find the frame32 corresponding to the frame16 we are jumping to */
390 pFrame = THREAD_STACK16(teb);
391 frame32 = pFrame->frame32;
392 while (frame32 && frame32->frame16)
394 if (OFFSETOF(frame32->frame16) < OFFSETOF(teb->cur_stack))
395 break; /* Something strange is going on */
396 if (OFFSETOF(frame32->frame16) > lpbuf[2])
398 /* We found the right frame */
399 pFrame->frame32 = frame32;
400 break;
402 frame32 = ((STACK16FRAME *)PTR_SEG_TO_LIN(frame32->frame16))->frame32;
405 IP_reg(context) = lpbuf[0];
406 CS_reg(context) = lpbuf[1];
407 SP_reg(context) = lpbuf[2] + 4 * sizeof(WORD) - sizeof(WORD) /*extra arg*/;
408 BP_reg(context) = lpbuf[3];
409 SI_reg(context) = lpbuf[4];
410 DI_reg(context) = lpbuf[5];
411 DS_reg(context) = lpbuf[6];
413 if (lpbuf[8] != SS_reg(context))
414 ERR("Switching stack segment with Throw() not supported; expect crash now\n" );
416 if (TRACE_ON(relay)) /* Make sure we have a valid entry point address */
418 static FARPROC16 entryPoint = NULL;
420 if (!entryPoint) /* Get entry point for Throw() */
421 entryPoint = NE_GetEntryPoint( GetModuleHandle16("KERNEL"), 56 );
422 pFrame->entry_cs = SELECTOROF(entryPoint);
423 pFrame->entry_ip = OFFSETOF(entryPoint);
428 /**********************************************************************
429 * RELAY_CallProc32W
431 * Helper for CallProc[Ex]32W
433 static DWORD RELAY_CallProc32W(int Ex)
435 DWORD nrofargs, argconvmask;
436 FARPROC proc32;
437 DWORD *args, ret;
438 VA_LIST16 valist;
439 int i;
440 int aix;
441 dbg_decl_str(relay, 1024);
443 SYSLEVEL_ReleaseWin16Lock();
445 VA_START16( valist );
446 nrofargs = VA_ARG16( valist, DWORD );
447 argconvmask = VA_ARG16( valist, DWORD );
448 proc32 = VA_ARG16( valist, FARPROC );
449 dsprintf(relay, "CallProc32W(%ld,%ld,%p, Ex%d args[",nrofargs,argconvmask,proc32,Ex);
450 args = (DWORD*)HEAP_xalloc( GetProcessHeap(), 0,
451 sizeof(DWORD)*nrofargs );
452 /* CallProcEx doesn't need its args reversed */
453 for (i=0;i<nrofargs;i++) {
454 if (Ex) {
455 aix = i;
456 } else {
457 aix = nrofargs - i - 1;
459 if (argconvmask & (1<<i))
461 SEGPTR ptr = VA_ARG16( valist, SEGPTR );
462 args[aix] = (DWORD)PTR_SEG_TO_LIN(ptr);
463 dsprintf(relay,"%08lx(%p),",ptr,PTR_SEG_TO_LIN(ptr));
465 else
467 args[aix] = VA_ARG16( valist, DWORD );
468 dsprintf(relay,"%ld,",args[aix]);
471 dsprintf(relay,"])");
472 VA_END16( valist );
474 if (!proc32) ret = 0;
475 else switch (nrofargs)
477 case 0: ret = proc32();
478 break;
479 case 1: ret = proc32(args[0]);
480 break;
481 case 2: ret = proc32(args[0],args[1]);
482 break;
483 case 3: ret = proc32(args[0],args[1],args[2]);
484 break;
485 case 4: ret = proc32(args[0],args[1],args[2],args[3]);
486 break;
487 case 5: ret = proc32(args[0],args[1],args[2],args[3],args[4]);
488 break;
489 case 6: ret = proc32(args[0],args[1],args[2],args[3],args[4],args[5]);
490 break;
491 case 7: ret = proc32(args[0],args[1],args[2],args[3],args[4],args[5],args[6]);
492 break;
493 case 8: ret = proc32(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7]);
494 break;
495 case 9: ret = proc32(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7],args[8]);
496 break;
497 case 10: ret = proc32(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7],args[8],args[9]);
498 break;
499 case 11: ret = proc32(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7],args[8],args[9],args[10]);
500 break;
501 default:
502 /* FIXME: should go up to 32 arguments */
503 ERR("Unsupported number of arguments %ld, please report.\n",nrofargs);
504 ret = 0;
505 break;
507 /* POP nrofargs DWORD arguments and 3 DWORD parameters */
508 if (!Ex) STACK16_POP( NtCurrentTeb(), (3 + nrofargs) * sizeof(DWORD) );
510 TRACE("%s - returns %08lx\n",dbg_str(relay),ret);
511 HeapFree( GetProcessHeap(), 0, args );
513 SYSLEVEL_RestoreWin16Lock();
515 return ret;
519 /**********************************************************************
520 * CallProc32W (KERNEL.517)
522 DWORD WINAPI CallProc32W_16()
524 return RELAY_CallProc32W(0);
528 /**********************************************************************
529 * CallProcEx32W() (KERNEL.518)
531 * C - style linkage to CallProc32W - caller pops stack.
533 DWORD WINAPI CallProcEx32W_16()
535 return RELAY_CallProc32W(TRUE);