ntdll: Use a separate memory allocation for the kernel stack.
[wine.git] / dlls / krnl386.exe16 / snoop.c
blob1504f8f7cd80ca7bb73feaf372ea57b5c3e52339
1 /*
2 * 386-specific Win16 dll<->dll snooping functions
4 * Copyright 1998 Marcus Meissner
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include <assert.h>
22 #include <string.h>
23 #include <stdarg.h>
24 #include <stdio.h>
25 #include "windef.h"
26 #include "winbase.h"
27 #include "winnt.h"
28 #include "wine/winbase16.h"
29 #include "winternl.h"
30 #include "kernel16_private.h"
31 #include "wine/debug.h"
33 WINE_DEFAULT_DEBUG_CHANNEL(snoop);
35 #include "pshpack1.h"
37 typedef struct tagSNOOP16_FUN {
38 /* code part */
39 BYTE lcall; /* 0x9a call absolute with segment */
40 FARPROC16 snoop_entry;
41 /* unreached */
42 int nrofargs;
43 FARPROC16 origfun;
44 char *name;
45 } SNOOP16_FUN;
47 typedef struct tagSNOOP16_DLL {
48 HMODULE16 hmod;
49 HANDLE16 funhandle;
50 SNOOP16_FUN *funs;
51 struct tagSNOOP16_DLL *next;
52 char name[1];
53 } SNOOP16_DLL;
55 typedef struct tagSNOOP16_RETURNENTRY {
56 /* code part */
57 BYTE lcall; /* 0x9a call absolute with segment */
58 FARPROC16 snoop_return;
59 /* unreached */
60 FARPROC16 origreturn;
61 SNOOP16_DLL *dll;
62 DWORD ordinal;
63 WORD origSP;
64 WORD *args; /* saved args across a stdcall */
65 } SNOOP16_RETURNENTRY;
67 typedef struct tagSNOOP16_RETURNENTRIES {
68 SNOOP16_RETURNENTRY entry[65500/sizeof(SNOOP16_RETURNENTRY)];
69 HANDLE16 rethandle;
70 struct tagSNOOP16_RETURNENTRIES *next;
71 } SNOOP16_RETURNENTRIES;
73 #include "poppack.h"
75 static SNOOP16_DLL *firstdll = NULL;
76 static SNOOP16_RETURNENTRIES *firstrets = NULL;
78 void
79 SNOOP16_RegisterDLL(HMODULE16 hModule,LPCSTR name) {
80 SNOOP16_DLL **dll = &(firstdll);
81 const char *p;
82 char *q;
84 if (!TRACE_ON(snoop)) return;
86 TRACE("hmod=%x, name=%s\n", hModule, name);
88 while (*dll) {
89 if ((*dll)->hmod == hModule)
91 /* another dll, loaded at the same address */
92 GlobalUnlock16((*dll)->funhandle);
93 GlobalFree16((*dll)->funhandle);
94 break;
96 dll = &((*dll)->next);
99 if (*dll)
100 *dll = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, *dll, sizeof(SNOOP16_DLL)+strlen(name));
101 else
102 *dll = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(SNOOP16_DLL)+strlen(name));
104 (*dll)->next = NULL;
105 (*dll)->hmod = hModule;
106 if ((p=strrchr(name,'\\')))
107 name = p+1;
108 strcpy( (*dll)->name, name );
109 if ((q=strrchr((*dll)->name,'.')))
110 *q='\0';
111 (*dll)->funhandle = GlobalHandleToSel16(GLOBAL_Alloc(GMEM_ZEROINIT,65535,0,LDT_FLAGS_CODE));
112 (*dll)->funs = GlobalLock16((*dll)->funhandle);
113 if (!(*dll)->funs) {
114 HeapFree(GetProcessHeap(),0,*dll);
115 FIXME("out of memory\n");
116 return;
120 FARPROC16
121 SNOOP16_GetProcAddress16(HMODULE16 hmod,DWORD ordinal,FARPROC16 origfun) {
122 SNOOP16_DLL *dll = firstdll;
123 SNOOP16_FUN *fun;
124 NE_MODULE *pModule = NE_GetPtr(hmod);
125 unsigned char *cpnt;
126 char name[200];
128 if (!TRACE_ON(snoop) || !pModule || !HIWORD(origfun))
129 return origfun;
130 if (!*(LPBYTE)MapSL((SEGPTR)origfun)) /* 0x00 is an impossible opcode, possible dataref. */
131 return origfun;
132 while (dll) {
133 if (hmod == dll->hmod)
134 break;
135 dll=dll->next;
137 if (!dll) /* probably internal */
138 return origfun;
139 if (ordinal>65535/sizeof(SNOOP16_FUN))
140 return origfun;
141 fun = dll->funs+ordinal;
142 /* already done? */
143 fun->lcall = 0x9a;
144 fun->snoop_entry = GetProcAddress16( GetModuleHandle16( "KERNEL" ), "__wine_snoop_entry" );
145 fun->origfun = origfun;
146 if (fun->name)
147 return (FARPROC16)(SEGPTR)MAKELONG(((char*)fun-(char*)dll->funs),dll->funhandle);
148 cpnt = (unsigned char *)pModule + pModule->ne_restab;
149 while (*cpnt) {
150 cpnt += *cpnt + 1 + sizeof(WORD);
151 if (*(WORD*)(cpnt+*cpnt+1) == ordinal) {
152 sprintf(name,"%.*s",*cpnt,cpnt+1);
153 break;
156 /* Now search the non-resident names table */
158 if (!*cpnt && pModule->nrname_handle) {
159 cpnt = GlobalLock16( pModule->nrname_handle );
160 while (*cpnt) {
161 cpnt += *cpnt + 1 + sizeof(WORD);
162 if (*(WORD*)(cpnt+*cpnt+1) == ordinal) {
163 sprintf(name,"%.*s",*cpnt,cpnt+1);
164 break;
168 if (*cpnt)
170 fun->name = HeapAlloc(GetProcessHeap(),0,strlen(name)+1);
171 strcpy( fun->name, name );
173 else
174 fun->name = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,1); /* empty string */
176 if (!SNOOP16_ShowDebugmsgSnoop(dll->name, ordinal, fun->name))
177 return origfun;
179 /* more magic. do not try to snoop thunk data entries (MMSYSTEM) */
180 if (strchr(fun->name,'_')) {
181 char *s=strchr(fun->name,'_');
183 if (!_strnicmp(s,"_thunkdata",10)) {
184 HeapFree(GetProcessHeap(),0,fun->name);
185 fun->name = NULL;
186 return origfun;
189 fun->lcall = 0x9a;
190 fun->snoop_entry = GetProcAddress16( GetModuleHandle16( "KERNEL" ), "__wine_snoop_entry" );
191 fun->origfun = origfun;
192 fun->nrofargs = -1;
193 return (FARPROC16)(SEGPTR)MAKELONG(((char*)fun-(char*)dll->funs),dll->funhandle);
196 #define CALLER1REF (*(DWORD*)(MapSL( MAKESEGPTR(context->SegSs,LOWORD(context->Esp)+4))))
197 void WINAPI __wine_snoop_entry( CONTEXT *context )
199 DWORD ordinal=0;
200 DWORD entry=(DWORD)MapSL( MAKESEGPTR(context->SegCs,LOWORD(context->Eip)) )-5;
201 WORD xcs = context->SegCs;
202 SNOOP16_DLL *dll = firstdll;
203 SNOOP16_FUN *fun = NULL;
204 SNOOP16_RETURNENTRIES **rets = &firstrets;
205 SNOOP16_RETURNENTRY *ret;
206 unsigned i=0;
207 int max;
209 while (dll) {
210 if (xcs == dll->funhandle) {
211 fun = (SNOOP16_FUN*)entry;
212 ordinal = fun-dll->funs;
213 break;
215 dll=dll->next;
217 if (!dll) {
218 FIXME("entrypoint 0x%08lx not found\n",entry);
219 return; /* oops */
221 while (*rets) {
222 for (i=0;i<ARRAY_SIZE((*rets)->entry);i++)
223 if (!(*rets)->entry[i].origreturn)
224 break;
225 if (i!=ARRAY_SIZE((*rets)->entry))
226 break;
227 rets = &((*rets)->next);
229 if (!*rets) {
230 HANDLE16 hand = GlobalHandleToSel16(GLOBAL_Alloc(GMEM_ZEROINIT,65535,0,LDT_FLAGS_CODE));
231 *rets = GlobalLock16(hand);
232 (*rets)->rethandle = hand;
233 i = 0; /* entry 0 is free */
235 ret = &((*rets)->entry[i]);
236 ret->lcall = 0x9a;
237 ret->snoop_return = GetProcAddress16( GetModuleHandle16( "KERNEL" ), "__wine_snoop_return" );
238 ret->origreturn = (FARPROC16)CALLER1REF;
239 CALLER1REF = MAKELONG((char*)&(ret->lcall)-(char*)((*rets)->entry),(*rets)->rethandle);
240 ret->dll = dll;
241 ret->args = NULL;
242 ret->ordinal = ordinal;
243 ret->origSP = LOWORD(context->Esp);
245 context->Eip= LOWORD(fun->origfun);
246 context->SegCs = HIWORD(fun->origfun);
249 TRACE("\1CALL %s.%ld: %s(", dll->name, ordinal, fun->name);
250 if (fun->nrofargs>0) {
251 max = fun->nrofargs;
252 if (max>16) max=16;
253 for (i=max;i--;)
254 TRACE("%04x%s",*(WORD*)((char *) MapSL( MAKESEGPTR(context->SegSs,LOWORD(context->Esp)) )+8+sizeof(WORD)*i),i?",":"");
255 if (max!=fun->nrofargs)
256 TRACE(" ...");
257 } else if (fun->nrofargs<0) {
258 TRACE("<unknown, check return>");
259 ret->args = HeapAlloc(GetProcessHeap(),0,16*sizeof(WORD));
260 memcpy(ret->args,(LPBYTE)((char *) MapSL( MAKESEGPTR(context->SegSs,LOWORD(context->Esp)) )+8),sizeof(WORD)*16);
262 TRACE(") ret=%04x:%04x\n",HIWORD(ret->origreturn),LOWORD(ret->origreturn));
265 void WINAPI __wine_snoop_return( CONTEXT *context )
267 SNOOP16_RETURNENTRY *ret = (SNOOP16_RETURNENTRY*)((char *) MapSL( MAKESEGPTR(context->SegCs,LOWORD(context->Eip)) )-5);
269 /* We haven't found out the nrofargs yet. If we called a cdecl
270 * function it is too late anyway and we can just set '0' (which
271 * will be the difference between orig and current SP
272 * If pascal -> everything ok.
274 if (ret->dll->funs[ret->ordinal].nrofargs<0) {
275 ret->dll->funs[ret->ordinal].nrofargs=(LOWORD(context->Esp)-ret->origSP-4)/2;
277 context->Eip = LOWORD(ret->origreturn);
278 context->SegCs = HIWORD(ret->origreturn);
279 TRACE("\1RET %s.%ld: %s(", ret->dll->name, ret->ordinal, ret->dll->funs[ret->ordinal].name);
280 if (ret->args) {
281 int i,max;
283 max = ret->dll->funs[ret->ordinal].nrofargs;
284 if (max>16)
285 max=16;
286 if (max<0)
287 max=0;
289 for (i=max;i--;)
290 TRACE("%04x%s",ret->args[i],i?",":"");
291 if (max!=ret->dll->funs[ret->ordinal].nrofargs)
292 TRACE(" ...");
293 HeapFree(GetProcessHeap(),0,ret->args);
294 ret->args = NULL;
296 TRACE(") retval = %04x:%04x ret=%04x:%04x\n",
297 (WORD)context->Edx,(WORD)context->Eax,
298 HIWORD(ret->origreturn),LOWORD(ret->origreturn));
299 ret->origreturn = NULL; /* mark as empty */