Add support for specific EOI PIC command.
[wine] / dlls / kernel / relay16.c
1 /*
2  * Copyright 1993 Robert J. Amstadt
3  * Copyright 1995 Alexandre Julliard
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  */
19
20 #include "config.h"
21 #include "wine/port.h"
22
23 #include <assert.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <stdio.h>
27
28 #include "windef.h"
29 #include "wine/winbase16.h"
30 #include "module.h"
31 #include "stackframe.h"
32 #include "selectors.h"
33 #include "builtin16.h"
34 #include "syslevel.h"
35 #include "wine/library.h"
36 #include "wine/debug.h"
37
38 WINE_DEFAULT_DEBUG_CHANNEL(relay);
39
40 /*
41  * Stubs for the CallTo16/CallFrom16 routines on non-Intel architectures
42  * (these will never be called but need to be present to satisfy the linker ...)
43  */
44 #ifndef __i386__
45 /***********************************************************************
46  *              __wine_call_from_16_word (KERNEL32.@)
47  */
48 WORD __wine_call_from_16_word()
49 {
50     assert( FALSE );
51 }
52
53 /***********************************************************************
54  *              __wine_call_from_16_long (KERNEL32.@)
55  */
56 LONG __wine_call_from_16_long()
57 {
58     assert( FALSE );
59 }
60
61 /***********************************************************************
62  *              __wine_call_from_16_regs (KERNEL32.@)
63  */
64 void __wine_call_from_16_regs()
65 {
66     assert( FALSE );
67 }
68
69 DWORD WINAPI CALL32_CBClient( FARPROC proc, LPWORD args, DWORD *esi )
70 { assert( FALSE ); }
71
72 DWORD WINAPI CALL32_CBClientEx( FARPROC proc, LPWORD args, DWORD *esi, INT *nArgs )
73 { assert( FALSE ); }
74 #endif
75
76
77 /***********************************************************************
78  *           RELAY_ShowDebugmsgRelay
79  *
80  * Simple function to decide if a particular debugging message is
81  * wanted.
82  */
83 static int RELAY_ShowDebugmsgRelay(const char *func)
84 {
85   /* from relay32/relay386.c */
86   extern const char **debug_relay_excludelist,**debug_relay_includelist;
87
88   if(debug_relay_excludelist || debug_relay_includelist) {
89     const char *term = strchr(func, ':');
90     const char **listitem;
91     int len, len2, itemlen, show;
92
93     if(debug_relay_excludelist) {
94       show = 1;
95       listitem = debug_relay_excludelist;
96     } else {
97       show = 0;
98       listitem = debug_relay_includelist;
99     }
100     assert(term);
101     assert(strlen(term) > 2);
102     len = term - func;
103     len2 = strchr(func, '.') - func;
104     assert(len2 && len2 > 0 && len2 < 64);
105     term += 2;
106     for(; *listitem; listitem++) {
107       itemlen = strlen(*listitem);
108       if((itemlen == len && !strncasecmp(*listitem, func, len)) ||
109          (itemlen == len2 && !strncasecmp(*listitem, func, len2)) ||
110          !strcasecmp(*listitem, term)) {
111         show = !show;
112        break;
113       }
114     }
115     return show;
116   }
117   return 1;
118 }
119
120
121 /***********************************************************************
122  *           get_entry_point
123  *
124  * Return the ordinal, name, and type info corresponding to a CS:IP address.
125  */
126 static const CALLFROM16 *get_entry_point( STACK16FRAME *frame, LPSTR name, WORD *pOrd )
127 {
128     WORD i, max_offset;
129     register BYTE *p;
130     NE_MODULE *pModule;
131     ET_BUNDLE *bundle;
132     ET_ENTRY *entry;
133
134     if (!(pModule = NE_GetPtr( FarGetOwner16( GlobalHandle16( frame->module_cs ) ))))
135         return NULL;
136
137     max_offset = 0;
138     *pOrd = 0;
139     bundle = (ET_BUNDLE *)((BYTE *)pModule + pModule->entry_table);
140     do
141     {
142         entry = (ET_ENTRY *)((BYTE *)bundle+6);
143         for (i = bundle->first + 1; i <= bundle->last; i++)
144         {
145             if ((entry->offs < frame->entry_ip)
146             && (entry->segnum == 1) /* code segment ? */
147             && (entry->offs >= max_offset))
148             {
149                 max_offset = entry->offs;
150                 *pOrd = i;
151             }
152             entry++;
153         }
154     } while ( (bundle->next)
155            && (bundle = (ET_BUNDLE *)((BYTE *)pModule+bundle->next)));
156
157     /* Search for the name in the resident names table */
158     /* (built-in modules have no non-resident table)   */
159
160     p = (BYTE *)pModule + pModule->name_table;
161     while (*p)
162     {
163         p += *p + 1 + sizeof(WORD);
164         if (*(WORD *)(p + *p + 1) == *pOrd) break;
165     }
166
167     sprintf( name, "%.*s.%d: %.*s",
168              *((BYTE *)pModule + pModule->name_table),
169              (char *)pModule + pModule->name_table + 1,
170              *pOrd, *p, (char *)(p + 1) );
171
172     /* Retrieve entry point call structure */
173     p = MapSL( MAKESEGPTR( frame->module_cs, frame->callfrom_ip ) );
174     /* p now points to lret, get the start of CALLFROM16 structure */
175     return (CALLFROM16 *)(p - (BYTE *)&((CALLFROM16 *)0)->lret);
176 }
177
178
179 /***********************************************************************
180  *           RELAY_DebugCallFrom16
181  */
182 void RELAY_DebugCallFrom16( CONTEXT86 *context )
183 {
184     STACK16FRAME *frame;
185     WORD ordinal;
186     char *args16, funstr[80];
187     const CALLFROM16 *call;
188     int i;
189
190     if (!TRACE_ON(relay)) return;
191
192     frame = CURRENT_STACK16;
193     call = get_entry_point( frame, funstr, &ordinal );
194     if (!call) return; /* happens for the two snoop register relays */
195     if (!RELAY_ShowDebugmsgRelay(funstr)) return;
196     DPRINTF( "%04lx:Call %s(",GetCurrentThreadId(),funstr);
197     args16 = (char *)(frame + 1);
198
199     if (call->lret == 0xcb66)  /* cdecl */
200     {
201         for (i = 0; i < 20; i++)
202         {
203             int type = (call->arg_types[i / 10] >> (3 * (i % 10))) & 7;
204
205             if (type == ARG_NONE) break;
206             if (i) DPRINTF( "," );
207             switch(type)
208             {
209             case ARG_WORD:
210             case ARG_SWORD:
211                 DPRINTF( "%04x", *(WORD *)args16 );
212                 args16 += sizeof(WORD);
213                 break;
214             case ARG_LONG:
215                 DPRINTF( "%08x", *(int *)args16 );
216                 args16 += sizeof(int);
217                 break;
218             case ARG_PTR:
219                 DPRINTF( "%04x:%04x", *(WORD *)(args16+2), *(WORD *)args16 );
220                 args16 += sizeof(SEGPTR);
221                 break;
222             case ARG_STR:
223                 DPRINTF( "%08x %s", *(int *)args16,
224                          debugstr_a( MapSL(*(SEGPTR *)args16 )));
225                 args16 += sizeof(int);
226                 break;
227             case ARG_SEGSTR:
228                 DPRINTF( "%04x:%04x %s", *(WORD *)(args16+2), *(WORD *)args16,
229                          debugstr_a( MapSL(*(SEGPTR *)args16 )) );
230                 args16 += sizeof(SEGPTR);
231                 break;
232             default:
233                 break;
234             }
235         }
236     }
237     else  /* not cdecl */
238     {
239         /* Start with the last arg */
240         args16 += call->nArgs;
241         for (i = 0; i < 20; i++)
242         {
243             int type = (call->arg_types[i / 10] >> (3 * (i % 10))) & 7;
244
245             if (type == ARG_NONE) break;
246             if (i) DPRINTF( "," );
247             switch(type)
248             {
249             case ARG_WORD:
250             case ARG_SWORD:
251                 args16 -= sizeof(WORD);
252                 DPRINTF( "%04x", *(WORD *)args16 );
253                 break;
254             case ARG_LONG:
255                 args16 -= sizeof(int);
256                 DPRINTF( "%08x", *(int *)args16 );
257                 break;
258             case ARG_PTR:
259                 args16 -= sizeof(SEGPTR);
260                 DPRINTF( "%04x:%04x", *(WORD *)(args16+2), *(WORD *)args16 );
261                 break;
262             case ARG_STR:
263                 args16 -= sizeof(int);
264                 DPRINTF( "%08x %s", *(int *)args16,
265                          debugstr_a( MapSL(*(SEGPTR *)args16 )));
266                 break;
267             case ARG_SEGSTR:
268                 args16 -= sizeof(SEGPTR);
269                 DPRINTF( "%04x:%04x %s", *(WORD *)(args16+2), *(WORD *)args16,
270                          debugstr_a( MapSL(*(SEGPTR *)args16 )) );
271                 break;
272             default:
273                 break;
274             }
275         }
276     }
277
278     DPRINTF( ") ret=%04x:%04x ds=%04x\n", frame->cs, frame->ip, frame->ds );
279
280     if (call->arg_types[0] & ARG_REGISTER)
281         DPRINTF("     AX=%04x BX=%04x CX=%04x DX=%04x SI=%04x DI=%04x ES=%04x EFL=%08lx\n",
282                 (WORD)context->Eax, (WORD)context->Ebx, (WORD)context->Ecx,
283                 (WORD)context->Edx, (WORD)context->Esi, (WORD)context->Edi,
284                 (WORD)context->SegEs, context->EFlags );
285
286     SYSLEVEL_CheckNotLevel( 2 );
287 }
288
289
290 /***********************************************************************
291  *           RELAY_DebugCallFrom16Ret
292  */
293 void RELAY_DebugCallFrom16Ret( CONTEXT86 *context, int ret_val )
294 {
295     STACK16FRAME *frame;
296     WORD ordinal;
297     char funstr[80];
298     const CALLFROM16 *call;
299
300     if (!TRACE_ON(relay)) return;
301     frame = CURRENT_STACK16;
302     call = get_entry_point( frame, funstr, &ordinal );
303     if (!call) return;
304     if (!RELAY_ShowDebugmsgRelay(funstr)) return;
305     DPRINTF( "%04lx:Ret  %s() ",GetCurrentThreadId(),funstr);
306
307     if (call->arg_types[0] & ARG_REGISTER)
308     {
309         DPRINTF("retval=none ret=%04x:%04x ds=%04x\n",
310                 (WORD)context->SegCs, LOWORD(context->Eip), (WORD)context->SegDs);
311         DPRINTF("     AX=%04x BX=%04x CX=%04x DX=%04x SI=%04x DI=%04x ES=%04x EFL=%08lx\n",
312                 (WORD)context->Eax, (WORD)context->Ebx, (WORD)context->Ecx,
313                 (WORD)context->Edx, (WORD)context->Esi, (WORD)context->Edi,
314                 (WORD)context->SegEs, context->EFlags );
315     }
316     else if (call->arg_types[0] & ARG_RET16)
317     {
318         DPRINTF( "retval=%04x ret=%04x:%04x ds=%04x\n",
319                  ret_val & 0xffff, frame->cs, frame->ip, frame->ds );
320     }
321     else
322     {
323         DPRINTF( "retval=%08x ret=%04x:%04x ds=%04x\n",
324                  ret_val, frame->cs, frame->ip, frame->ds );
325     }
326     SYSLEVEL_CheckNotLevel( 2 );
327 }