rebased to master after sw 3rd party completed
[dyninst.git] / dyninstAPI_RT / src / RTwinnt.c
1 /*
2  * See the dyninst/COPYRIGHT file for copyright information.
3  * 
4  * We provide the Paradyn Tools (below described as "Paradyn")
5  * on an AS IS basis, and do not warrant its validity or performance.
6  * We reserve the right to update, modify, or discontinue this
7  * software at any time.  We shall have no obligation to supply such
8  * updates or modifications or any other form of support to you.
9  * 
10  * By your use of Paradyn, you understand and agree that we (or any
11  * other person or entity with proprietary rights in Paradyn) are
12  * under no obligation to provide either maintenance services,
13  * update services, notices of latent defects, or correction of
14  * defects for Paradyn.
15  * 
16  * This library is free software; you can redistribute it and/or
17  * modify it under the terms of the GNU Lesser General Public
18  * License as published by the Free Software Foundation; either
19  * version 2.1 of the License, or (at your option) any later version.
20  * 
21  * This library is distributed in the hope that it will be useful,
22  * but WITHOUT ANY WARRANTY; without even the implied warranty of
23  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
24  * Lesser General Public License for more details.
25  * 
26  * You should have received a copy of the GNU Lesser General Public
27  * License along with this library; if not, write to the Free Software
28  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
29  */
30
31 /************************************************************************
32  * $Id: RTwinnt.c,v 1.22 2006/06/09 03:50:49 jodom Exp $
33  * RTwinnt.c: runtime instrumentation functions for Windows NT
34  ************************************************************************/
35 #include "dyninstAPI_RT/h/dyninstAPI_RT.h"
36 #include "RTcommon.h"
37 #include <windows.h>
38 #include <Dbghelp.h>
39 #include <Psapi.h>
40 #include <stdio.h>
41 #include <stdlib.h>
42 //#define WIN32_LEAN_AND_MEAN
43 #include <windows.h>
44 #include <mmsystem.h>
45 #include <errno.h>
46 #include <limits.h>
47 #include <process.h>
48 #include <fcntl.h>
49 #include <sys/types.h>
50 #include <sys/stat.h>
51 #include <io.h>
52 #include <stdio.h>
53 #include <assert.h>
54 //#include <winsock2.h>
55
56 extern unsigned long dyninstTrapTableUsed;
57 extern unsigned long dyninstTrapTableVersion;
58 extern trapMapping_t *dyninstTrapTable;
59 extern unsigned long dyninstTrapTableIsSorted;
60 extern void DYNINSTBaseInit();
61 extern double DYNINSTstaticHeap_512K_lowmemHeap_1[];
62 extern double DYNINSTstaticHeap_16M_anyHeap_1[];
63 extern unsigned long sizeOfLowMemHeap1;
64 extern unsigned long sizeOfAnyHeap1;
65
66 /************************************************************************
67  * void DYNINSTbreakPoint(void)
68  *
69  * stop oneself.
70 ************************************************************************/
71
72 void DYNINSTbreakPoint(void) {
73   /* TODO: how do we stop all threads? */
74     DYNINST_break_point_event = 1;
75     DebugBreak();
76         DYNINST_break_point_event = 0;
77 }
78
79 void DYNINSTsafeBreakPoint() {
80     DYNINSTbreakPoint();
81 }
82
83 static dyntid_t initial_thread_tid;
84
85 /* this function is automatically called when windows loads this dll
86  if we are launching a mutatee to instrument, dyninst will place
87  the correct values in libdyninstAPI_RT_DLL_localPid and
88  libdyninstAPI_RT_DLL_localCause and they will be passed to
89  DYNINSTinit to correctly initialize the dll.  this keeps us
90  from having to instrument two steps from the mutator (load and then 
91  the execution of DYNINSTinit()
92 */
93
94 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
95 {
96    static int DllMainCalledOnce = 0;
97    //fprintf(stderr,"RTLIB: In DllMain staticmode=%d %s[%d]\n", DYNINSTstaticMode, __FILE__,__LINE__);
98
99    if(DllMainCalledOnce)
100       return 1;
101    DllMainCalledOnce++;
102
103    DYNINSTinit();
104
105 #if defined(cap_mutatee_traps)
106    if (DYNINSTstaticMode) {
107       DYNINSTinitializeTrapHandler();
108    }
109 #endif
110
111    return 1; 
112 }
113  
114
115
116 char gLoadLibraryErrorString[ERROR_STRING_LENGTH];
117 int DYNINSTloadLibrary(char *libname)
118 {
119     HMODULE res;
120     gLoadLibraryErrorString[0] = '\0';
121     res = LoadLibrary(libname);
122     if (res == NULL) {
123         FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), 
124                   MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
125                   gLoadLibraryErrorString, ERROR_STRING_LENGTH, NULL);
126         return 0;
127     }
128     return 1;
129 }
130
131 /************************************************************************
132  * void DYNINSTasyncConnect()
133  *
134  * Connect to mutator's async handler thread. <pid> is pid of mutator
135  ************************************************************************/
136 //CRITICAL_SECTION comms_mutex;
137
138 int async_socket = -1;
139 int connect_port = 0;
140
141 int DYNINSTasyncConnect(int mutatorpid)
142 {
143   int sock_fd;
144   struct sockaddr_in sadr;
145   struct in_addr *inadr;
146   struct hostent *hostptr;
147   
148   WORD wsversion = MAKEWORD(2,0);
149   WSADATA wsadata;
150   rtBPatch_asyncEventRecord ev;
151
152   if (async_socket != -1) 
153   {
154           /*fprintf(stderr, "%s[%d]:  already connected\n", __FILE__, __LINE__);*/
155       return 0;
156   }
157
158   RTprintf("%s[%d]:  inside DYNINSTasyncConnect\n", __FILE__, __LINE__);
159
160   if (0 == connect_port) 
161   {
162     fprintf(stderr, "%s[%d]:  DYNINSTasyncConnect, no port\n",
163             __FILE__, __LINE__);    
164   }
165
166   WSAStartup(wsversion, &wsadata);
167    
168   RTprintf("%s[%d]:  DYNINSTasyncConnect before gethostbyname\n", __FILE__, __LINE__);
169
170   hostptr = gethostbyname("localhost");
171   inadr = (struct in_addr *) ((void*) hostptr->h_addr_list[0]);
172
173   RTprintf("%s[%d]:  inside DYNINSTasyncConnect before memset\n", __FILE__, __LINE__);
174
175   memset((void*) &sadr, 0, sizeof(sadr));
176   sadr.sin_family = PF_INET;
177   sadr.sin_port = htons((u_short)connect_port);
178   sadr.sin_addr = *inadr;
179
180   RTprintf("%s[%d]:   DYNINSTasyncConnect before socket\n", __FILE__, __LINE__);
181
182   sock_fd = socket(PF_INET, SOCK_STREAM, 0);
183
184   if (sock_fd == INVALID_SOCKET) 
185   {
186     fprintf(stderr, "DYNINST: socket failed: %d\n", WSAGetLastError());
187   }
188
189   RTprintf("%s[%d]:   DYNINSTasyncConnect before connect\n", __FILE__, __LINE__);
190
191   if (connect(sock_fd, (struct sockaddr *) &sadr, sizeof(sadr)) == SOCKET_ERROR) 
192   {
193     fprintf(stderr, "DYNINSTasyncConnect: connect failed: %d\n", WSAGetLastError());
194   }
195
196   /* maybe need to do fcntl to set nonblocking writes on this fd */
197
198   async_socket = sock_fd;
199
200   RTprintf("%s[%d]:   DYNINSTasyncConnect before write\n", __FILE__, __LINE__);
201
202   /* after connecting, we need to send along our pid */
203   ev.type = rtBPatch_newConnectionEvent;
204   ev.pid = _getpid();
205
206   if (!DYNINSTwriteEvent((void *) &ev, sizeof(rtBPatch_asyncEventRecord))) 
207   {
208     fprintf(stderr, "%s[%d]:  DYNINSTwriteEventFailed\n", __FILE__, __LINE__);
209   }
210
211   /* initialize comms mutex */
212
213   //InitializeCriticalSection(&comms_mutex);
214   //fprintf(stderr, "%s[%d]: DYNINSTasyncConnect appears to have succeeded\n", __FILE__, __LINE__);
215
216   RTprintf("%s[%d]:  leaving DYNINSTasyncConnect\n", __FILE__, __LINE__);
217
218   return 1; /*true*/
219 }
220
221 int DYNINSTasyncDisconnect()
222 {
223   WSACleanup();
224   return _close (async_socket);
225 }
226
227 void printSysError(unsigned errNo) {
228     char buf[1000];
229     FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, errNo, 
230                   MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
231                   buf, 1000, NULL);
232
233     fprintf(stderr, "*** System error [%d]: %s\n", errNo, buf);
234     fflush(stderr);
235 }
236
237 int DYNINSTwriteEvent(void *ev, size_t sz)
238 {
239   DYNINSTasyncConnect(DYNINST_mutatorPid);
240
241   if (send((SOCKET)async_socket, ev, sz, 0) != sz) 
242   {
243     printSysError(WSAGetLastError());
244     printf("DYNINSTwriteTrace: send error %d, %d %d\n",
245            WSAGetLastError(), sz, async_socket);
246
247     if (async_socket == -1)
248       return 1;
249     return 0;
250   }
251   return 1;
252 }
253
254 int dyn_pid_self()
255 {
256    return _getpid();
257 }
258
259 int dyn_lwp_self()
260 {
261         /* getCurrentThreadId() is conflicting with SD-Dyninst instrumentation. 
262         So I'm doing the massively unportable thing here and hard-coding the assembly
263         FOR GREAT JUSTICE! */
264 /*    return GetCurrentThreadId(); */
265         /* This will do stack frame setup, but that seems harmless in this context... */
266         __asm
267     {
268         mov     EAX,FS:[0x18]
269                 mov     EAX,DS:[EAX+0x24]
270         }
271 }
272
273 dyntid_t dyn_pthread_self()
274 {
275    return (dyntid_t) dyn_lwp_self();
276 }
277
278 int DYNINSTthreadInfo(BPatch_newThreadEventRecord *ev)
279 {
280     return 1;
281 }
282
283 /* 
284    We reserve index 0 for the initial thread. This value varies by
285    platform but is always constant for that platform. Wrap that
286    platform-ness here. 
287 */
288 int DYNINST_am_initial_thread(dyntid_t tid) {
289     return (tid == initial_thread_tid);
290 }
291
292 // Check that the address is backed by a file,
293 // get the binary's load address,
294 // get the PE header, assuming there is one,
295 // see if the last section has been tagged with "DYNINST_REWRITE"
296 // get trap-table header from last binary section's end - label - size
297 // sets allocBase to the binary's load address
298 static struct trap_mapping_header *getStaticTrapMap(unsigned long addr, unsigned long *allocBase)
299 {
300    struct trap_mapping_header *header = NULL;
301    char fileName[ERROR_STRING_LENGTH];
302    DWORD actualNameLen = 0;
303    MEMORY_BASIC_INFORMATION memInfo;
304    int numSections = 0;
305    PIMAGE_NT_HEADERS peHdr = NULL;
306    IMAGE_SECTION_HEADER curSecn;
307    int sidx=0;
308    char *str=NULL;
309
310    //check that the address is backed by a file
311    actualNameLen = GetMappedFileName(GetCurrentProcess(), 
312                                      (LPVOID)addr, 
313                                      fileName, 
314                                      ERROR_STRING_LENGTH);
315    if (!actualNameLen) {
316       fileName[0] = '\0';
317       goto done; // no file mapped at trap address
318    }
319    fileName[ERROR_STRING_LENGTH-1] = '\0';
320
321    // get the binary's load address, size
322    if (!VirtualQuery((LPCVOID)addr, &memInfo, sizeof(memInfo)) 
323        || MEM_COMMIT != memInfo.State) 
324    {
325       fprintf(stderr, "ERROR IN RTLIB: getStaticTrapMap %s[%d]\n", __FILE__,__LINE__);
326       goto done; // shouldn't be possible given previous query, but hey
327    }
328    *allocBase = (unsigned long) memInfo.AllocationBase;
329
330    rtdebug_printf("RTLIB: getStaticTrapMap addr=%lx meminfo.BaseAddress=%lx "
331                   "meminfo.AllocationBase = %lx, memInfo.RegionSize = %lx, "
332                   "%s[%d]\n", addr, memInfo.BaseAddress, 
333                   memInfo.AllocationBase, memInfo.RegionSize, 
334                   __FILE__,__LINE__);
335
336    // get the PE header, assuming there is one
337    peHdr = ImageNtHeader( memInfo.AllocationBase );
338    if (!peHdr) {
339       fprintf(stderr, "ERROR IN RTLIB: getStaticTrapMap %s[%d]\n", __FILE__,__LINE__);
340       goto done; // no pe header
341    }
342
343    // see if the last section has been tagged with "DYNINST_REWRITE"
344    numSections = peHdr->FileHeader.NumberOfSections;
345    curSecn = *(PIMAGE_SECTION_HEADER)
346             (((unsigned char*)peHdr) 
347             + sizeof(DWORD) + sizeof(IMAGE_FILE_HEADER) 
348             + peHdr->FileHeader.SizeOfOptionalHeader
349             + sizeof(IMAGE_SECTION_HEADER)*(numSections-1));
350
351    //fprintf(stderr, "RTLIB: PE section header address = %lx\n", curSecn);
352    //fprintf(stderr, "curSecn.chars = %lx %s[%d]\n",curSecn.Characteristics, __FILE__,__LINE__);
353    if ((sizeof(void*) + 16) > curSecn.SizeOfRawData) {
354       fprintf(stderr, "ERROR IN RTLIB: getStaticTrapMap %s[%d]\n", __FILE__,__LINE__);
355       goto done; // last section is uninitialized, doesn't have trap table
356    }
357
358    //fprintf(stderr, "RTLIB %s[%d]\n", __FILE__,__LINE__);
359    //fprintf(stderr, "RTLIB mi.ab =%lx cs.va =%lx cs.srd=%lx %s[%d]\n", memInfo.AllocationBase, curSecn.VirtualAddress, curSecn.SizeOfRawData, __FILE__,__LINE__);
360    str = (char*)((long)memInfo.AllocationBase 
361                  + curSecn.VirtualAddress 
362                  + curSecn.SizeOfRawData 
363                  - 16);
364    if (0 != strncmp("DYNINST_REWRITE", str, 15)) {
365       fprintf(stderr, "ERROR IN RTLIB: getStaticTrapMap found bad string [%s] at %lx %s[%d]\n", 
366               str, str, __FILE__,__LINE__);
367       goto done; // doesn't have DYNINST_REWRITE label
368    }
369
370    // get trap-table header
371    header = (struct trap_mapping_header*) 
372        ( (unsigned long)memInfo.AllocationBase + *((unsigned long*)(str - sizeof(void*))) );
373
374 done: 
375    if (header) {
376        rtdebug_printf( "RTLIB: found trap map header at %lx: [%lx %lx]\n", 
377               (unsigned long) header, header->low_entry, header->high_entry);
378    } else {
379       rtdebug_printf( "ERROR: didn't find trap table\n");
380    }
381    return header;
382 }
383
384 // Find the target IP and substitute. Leave everything else untouched.
385 LONG dyn_trapHandler(PEXCEPTION_POINTERS e)
386 {
387    void *trap_to=0;
388    void *trap_addr = (void*) ((unsigned char*)e->ExceptionRecord->ExceptionAddress);
389    unsigned long zero = 0;
390    unsigned long one = 1;
391    unsigned long loadAddr = 0;
392    struct trap_mapping_header *hdr = NULL;
393    trapMapping_t *mapping = NULL;
394    rtdebug_printf("RTLIB: In dyn_trapHandler for exception type 0x%lx at 0x%lx\n",
395            e->ExceptionRecord->ExceptionCode, trap_addr);
396  
397    assert(DYNINSTstaticMode && "detach on the fly not implemented on Windows");
398
399    if (EXCEPTION_BREAKPOINT != e->ExceptionRecord->ExceptionCode) {
400       fprintf(stderr,"RTLIB: dyn_trapHandler exiting early, exception "
401               "type = 0x%lx triggered at 0x%lx is not breakpoint %s[%d]\n", 
402               e->ExceptionRecord->ExceptionCode, trap_addr, __FILE__,__LINE__);
403       return EXCEPTION_CONTINUE_SEARCH;
404    }
405
406    hdr = getStaticTrapMap((unsigned long) trap_addr, &loadAddr);
407    assert(hdr);
408    mapping = &(hdr->traps[0]);
409
410    rtdebug_printf("RTLIB: calling dyninstTrapTranslate(\n\t0x%lx, \n\t"
411            "0x%lx, \n\t0x%lx, \n\t0x%lx, \n\t0x%lx)\n", 
412            (unsigned long)trap_addr - loadAddr + 1, 
413            hdr->num_entries, zero, mapping, one);
414
415    trap_to = dyninstTrapTranslate((void*)((unsigned long)trap_addr - loadAddr + 1),
416                                   (unsigned long *) &hdr->num_entries,
417                                   &zero, 
418                                   (volatile trapMapping_t **) &mapping,
419                                   &one);
420
421    rtdebug_printf("RTLIB: changing Eip from trap at 0x%lx to 0x%lx\n", 
422            e->ContextRecord->Eip, (long)trap_to + loadAddr);
423    e->ContextRecord->Eip = (long) trap_to + loadAddr;
424    return EXCEPTION_CONTINUE_EXECUTION;
425 }
426
427 PVOID fake_AVEH_handle;
428 /* registers the trap handler by calling AddVectoredExceptionHandler
429  */
430 int DYNINSTinitializeTrapHandler()
431 {
432    fake_AVEH_handle = AddVectoredExceptionHandler
433       (RT_TRUE, (PVECTORED_EXCEPTION_HANDLER)dyn_trapHandler);
434    rtdebug_printf("RTLIB: added vectored trap handler\n");
435    return fake_AVEH_handle != 0;
436 }
437
438 PVOID dyn_AddVectoredExceptionHandler
439 (ULONG isFirst, PVECTORED_EXCEPTION_HANDLER handler)
440 {
441    PVOID handlerHandle;
442    if (isFirst) {
443       RemoveVectoredExceptionHandler(fake_AVEH_handle);
444       handlerHandle = AddVectoredExceptionHandler(isFirst,handler);
445       fake_AVEH_handle = AddVectoredExceptionHandler
446          (isFirst,(PVECTORED_EXCEPTION_HANDLER)dyn_trapHandler);
447    }
448    else {
449       handlerHandle = AddVectoredExceptionHandler(isFirst,handler);
450    }
451    return handlerHandle;
452 }
453
454 extern int fakeTickCount;
455 extern FILE *stOut;
456 DWORD __stdcall DYNINST_FakeTickCount()
457 {
458     DWORD tmp = 0x12345678;
459     if (0 == fakeTickCount) {
460         fakeTickCount = tmp;
461     } else {
462         fakeTickCount = fakeTickCount + 2;
463 //        fakeTickCount = fakeTickCount + (tmp - fakeTickCount)/1000 + 1;
464     }
465     fprintf(stOut,"0x%lx = DYNINST_FakeTickCount()\n",fakeTickCount);
466     return (DWORD) fakeTickCount;
467 }
468
469 BOOL __stdcall DYNINST_FakeBlockInput(BOOL blockit)
470 {
471     BOOL ret = RT_TRUE;
472     fprintf(stOut,"0x%lx = DYNINST_FakeBlockInput(%d)\n",ret,blockit);
473     return ret;
474 }
475
476 DWORD __stdcall DYNINST_FakeSuspendThread(HANDLE hThread)
477 {
478     DWORD suspendCnt = 0;
479     fprintf(stOut,"%d = DYNINST_FakeSuspendThread(%d)\n",suspendCnt,hThread);
480     return suspendCnt;
481 }
482
483 BOOL __stdcall DYNINST_FakeCheckRemoteDebuggerPresent(HANDLE hProcess, PBOOL bpDebuggerPresent)
484 {
485     BOOL ret = RT_FALSE;
486     fprintf(stOut,"%d = DYNINST_FakeCheckRemoteDebuggerPresent(%d,0x%lx)\n",
487             ret, hProcess, bpDebuggerPresent);
488     (*bpDebuggerPresent) = ret;
489     return ret;
490 }
491
492 VOID __stdcall DYNINST_FakeGetSystemTime(LPSYSTEMTIME lpSystemTime)
493 {
494     lpSystemTime->wYear = 2009;
495     lpSystemTime->wMonth = 5;
496     lpSystemTime->wDayOfWeek = 0;
497     lpSystemTime->wDay = 3;
498     lpSystemTime->wHour = 10;
499     lpSystemTime->wMinute = 1;
500     lpSystemTime->wSecond = 33;
501     lpSystemTime->wMilliseconds = 855;
502     fprintf(stOut,"called DYNINST_FakeGetSystemTime()\n");
503     fflush(stOut);
504 }
505
506 void mark_heaps_exec() 
507 {
508         int OK;
509         DWORD old_permissions;
510         OK = VirtualProtect(DYNINSTstaticHeap_16M_anyHeap_1, sizeOfAnyHeap1, 
511                         PAGE_EXECUTE_READWRITE, &old_permissions);
512         if(!OK) {
513                 fprintf(stderr, "ERROR: 16M/any heap not usable in RTlib: %d\n", GetLastError());
514         }
515         OK = VirtualProtect(DYNINSTstaticHeap_512K_lowmemHeap_1, sizeOfLowMemHeap1, 
516                         PAGE_EXECUTE_READWRITE, &old_permissions);
517         if(!OK) {
518                 fprintf(stderr, "ERROR: 512k/lowmem heap not usable in RTlib: %d\n", GetLastError());
519         }
520 }