Fixed demangling of names in Windows (we weren't always stripping off
[dyninst.git] / dyninstAPI / src / pdwinnt.C
1 /*\r
2  * Copyright (c) 1996-2002 Barton P. Miller\r
3  * \r
4  * We provide the Paradyn Parallel Performance Tools (below\r
5  * described as "Paradyn") on an AS IS basis, and do not warrant its\r
6  * validity or performance.  We reserve the right to update, modify,\r
7  * or discontinue this software at any time.  We shall have no\r
8  * obligation to supply such updates or modifications or any other\r
9  * form of support to you.\r
10  * \r
11  * This license is for research uses.  For such uses, there is no\r
12  * charge. We define "research use" to mean you may freely use it\r
13  * inside your organization for whatever purposes you see fit. But you\r
14  * may not re-distribute Paradyn or parts of Paradyn, in any form\r
15  * source or binary (including derivatives), electronic or otherwise,\r
16  * to any other organization or entity without our permission.\r
17  * \r
18  * (for other uses, please contact us at paradyn@cs.wisc.edu)\r
19  * \r
20  * All warranties, including without limitation, any warranty of\r
21  * merchantability or fitness for a particular purpose, are hereby\r
22  * excluded.\r
23  * \r
24  * By your use of Paradyn, you understand and agree that we (or any\r
25  * other person or entity with proprietary rights in Paradyn) are\r
26  * under no obligation to provide either maintenance services,\r
27  * update services, notices of latent defects, or correction of\r
28  * defects for Paradyn.\r
29  * \r
30  * Even if advised of the possibility of such damages, under no\r
31  * circumstances shall we (or any other person or entity with\r
32  * proprietary rights in the software licensed hereunder) be liable\r
33  * to you or any third party for direct, indirect, or consequential\r
34  * damages of any character regardless of type of action, including,\r
35  * without limitation, loss of profits, loss of use, loss of good\r
36  * will, or computer failure or malfunction.  You agree to indemnify\r
37  * us (and any other person or entity with proprietary rights in the\r
38  * software licensed hereunder) for any and all liability it may\r
39  * incur to third parties resulting from your use of Paradyn.\r
40  */\r
41 \r
42 // $Id: pdwinnt.C,v 1.82 2003/03/13 00:47:55 buck Exp $\r
43 \r
44 #include <iomanip.h>\r
45 #include "dyninstAPI/src/symtab.h"\r
46 #include "common/h/headers.h"\r
47 #include "dyninstAPI/src/os.h"\r
48 #include "dyninstAPI/src/dyn_lwp.h"\r
49 #include "dyninstAPI/src/process.h"\r
50 #include "dyninstAPI/src/dyn_thread.h"\r
51 #include "dyninstAPI/src/stats.h"\r
52 #include "common/h/Types.h"\r
53 #include "dyninstAPI/src/showerror.h"\r
54 #include "dyninstAPI/src/instPoint.h"\r
55 #include "dyninstAPI/src/signalhandler.h"\r
56 \r
57 #ifndef BPATCH_LIBRARY\r
58 #include "paradynd/src/main.h"\r
59 #include "paradynd/src/init.h"\r
60 #include "paradynd/src/perfStream.h" //SPLIT ccw 4 jun 2002\r
61 #endif\r
62 \r
63 #ifdef BPATCH_LIBRARY\r
64 /* XXX This is only needed for emulating signals. */\r
65 #include "BPatch_thread.h"\r
66 #include "nt_signal_emul.h"\r
67 #endif\r
68 \r
69 #include "dyninstAPI/src/rpcMgr.h"\r
70 \r
71 // prototypes of functions used in this file\r
72 static string GetLoadedDllImageName( process* p, const DEBUG_EVENT& ev );\r
73 \r
74 \r
75 \r
76 //ccw  27 july 2000 : dummy methods to get the thing to compile before i add\r
77 //the remoteDevice : 29 mar 2001\r
78 #ifdef mips_unknown_ce2_11\r
79 #include <stdio.h> //for wprintf\r
80 \r
81 void kludgeWCHAR(const char *str8, WCHAR *str16){\r
82         int k;\r
83 \r
84         k=0;\r
85         while(str8[k]!='\0'){\r
86                 str16[k] = str8[k];\r
87                 k++;\r
88         }\r
89         str16[k] = '\0';\r
90         str16[k+1]='\0';\r
91 \r
92 }\r
93 \r
94 //int GetThreadContext(HANDLE hThread, w32CONTEXT *lpContext){\r
95 //      return 0;\r
96 //}\r
97 \r
98 //int SetThreadContext(HANDLE hThread, const w32CONTEXT *lpContext){\r
99 //      return 0;\r
100 //}\r
101 #endif\r
102 \r
103 extern bool isValidAddress(process *proc, Address where);\r
104 extern process *findProcess(int);\r
105 \r
106 //HANDLE kludgeProcHandle;\r
107 \r
108 void printSysError(unsigned errNo) {\r
109     char buf[1000];\r
110     FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, errNo, \r
111                   MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),\r
112                   buf, 1000, NULL);\r
113     fprintf(stderr, "*** System error [%d]: %s\n", errNo, buf);\r
114     fflush(stderr);\r
115 }\r
116 \r
117 \r
118 // check if a file handle is for kernel32.dll\r
119 static bool kludge_isKernel32Dll(HANDLE fileHandle, string &kernel32Name) {\r
120     static DWORD IndxHigh, IndxLow;\r
121     static bool firstTime = true;\r
122     BY_HANDLE_FILE_INFORMATION info;\r
123     static string kernel32Name_;\r
124 \r
125     if (firstTime) {\r
126         HANDLE kernel32H;\r
127         firstTime = false;\r
128         char sysRootDir[MAX_PATH+1];\r
129         if (GetSystemDirectory(sysRootDir, MAX_PATH) == 0)\r
130           assert(0);\r
131         kernel32Name_ = string(sysRootDir) + "\\kernel32.dll";\r
132         kernel32H = CreateFile(kernel32Name_.c_str(), GENERIC_READ, \r
133                                FILE_SHARE_READ, NULL, OPEN_EXISTING, NULL, NULL);\r
134         assert(kernel32H);\r
135         if (!GetFileInformationByHandle(kernel32H, &info)) {\r
136             printSysError(GetLastError());\r
137             assert(0);\r
138         }\r
139         IndxHigh = info.nFileIndexHigh;\r
140         IndxLow = info.nFileIndexLow;\r
141         CloseHandle(kernel32H);\r
142     }\r
143 \r
144     if (!GetFileInformationByHandle(fileHandle, &info))\r
145         return false;\r
146 \r
147     if (info.nFileIndexHigh==IndxHigh && info.nFileIndexLow==IndxLow) {\r
148       kernel32Name = kernel32Name_;\r
149       return true;\r
150     }\r
151     return false;\r
152 }\r
153 \r
154 \r
155 void dumpMem(process *p, void * addr, unsigned nbytes) {\r
156     unsigned char *buf = new unsigned char[nbytes];\r
157     memset(buf, 0, nbytes);\r
158     function_base *f;\r
159     assert(buf);\r
160 \r
161     if (f = p->findFuncByAddr((Address)addr))\r
162     {\r
163         printf("Function %s, addr=0x%lx, sz=%d\n", \r
164                 f->prettyName().c_str(),\r
165                 f->getAddress(p),\r
166                 f->size());\r
167     }\r
168     p->readDataSpace((void *)((unsigned)addr-32), nbytes, buf, true);\r
169     printf("## 0x%lx:\n", (unsigned)addr-32);\r
170     for (unsigned u = 0; u < nbytes; u++)\r
171     {\r
172             printf(" %x", buf[u]);\r
173     }\r
174     printf( "\n" );\r
175     p->readDataSpace(addr, nbytes, buf, true);\r
176     printf("## 0x%lx:\n", addr);\r
177     for (unsigned u1 = 0; u1 < nbytes; u1++)\r
178     {\r
179             printf(" %x", buf[u1]);\r
180     }\r
181     printf( "\n" );\r
182 }\r
183 \r
184 \r
185 \r
186 //\r
187 // walkStackFrame\r
188 //\r
189 // Try to walk one more frame in the stack of the indicated process.\r
190 // Assumes that the STACKFRAME argument is either the result\r
191 // from a previous StackWalk call, or has been initialized \r
192 // to the context from a GetThreadContext call.\r
193 //\r
194 inline\r
195 BOOL\r
196 walkStackFrame( HANDLE hProc, HANDLE hThread, STACKFRAME* psf )\r
197 {\r
198         return StackWalk( IMAGE_FILE_MACHINE_I386,\r
199                         hProc,\r
200                         hThread,\r
201                                 psf,\r
202                         NULL,\r
203                                 NULL,\r
204                         SymFunctionTableAccess,\r
205                         SymGetModuleBase,\r
206                                 NULL);\r
207 }\r
208 \r
209 \r
210 //\r
211 // findFunctionFromAddress\r
212 // \r
213 // Finds the function corresponding to the given address.\r
214 // Handles situations where the address is within instrumentation,\r
215 // and situations where the function has been relocated.\r
216 //\r
217 function_base*\r
218 findFunctionFromAddress( process* proc, Address addr )\r
219 {\r
220     function_base* fp = NULL;\r
221 \r
222     instPoint* ip = proc->findInstPointFromAddress(addr);\r
223     if( ip != NULL )\r
224     {\r
225         // the address is within a tramp\r
226         // find the function in which the tramp was installed\r
227         fp = (function_base*)( ip->iPgetFunction() );\r
228     }\r
229     else\r
230     {\r
231         // the address isn't within a tramp\r
232         // check if it is a known function (relocated or otherwise)\r
233         fp = (function_base*)( proc->findFuncByAddr( addr ) );\r
234     }\r
235     return fp;\r
236 }\r
237 \r
238 \r
239 \r
240 #ifdef i386_unknown_nt4_0 //ccw 27 july 2000 : 29 mar 2001\r
241 //\r
242 // process::walkStackFromFrame\r
243 //\r
244 // 8OCT02: this should now pay proper attention to threads,\r
245 //         though a better method than handing in a thread to\r
246 //         kickstart the stackwalk is probably a good idea -- Bernat\r
247 //\r
248 // Note that we have *not* been able to find a mechanism that \r
249 // can perform stack walks reliably for apps compiled with the FPO \r
250 // (frame pointer omission) optimization.  Even if the FPO data is\r
251 // available, the Win32 StackWalk call either skips functions or bottoms\r
252 // out the stack too early.  Unfortunately, this means that we require\r
253 // that the app under study *not* use the FPO optimization.  (Specify /Oy- \r
254 // for the VC++ compiler to turn this optimization off.)\r
255 //\r
256 \r
257 bool process::walkStackFromFrame(Frame currentFrame, pdvector<Frame> &stackWalk)\r
258 {\r
259 #ifndef BPATCH_LIBRARY\r
260     startTimingStackwalk();\r
261 #endif\r
262     \r
263 #ifdef DEBUG_STACKWALK\r
264     cout << "\n<stack>" << endl;\r
265 #endif // DEBUG_STACKWALK\r
266     \r
267     if (status_ == running) {\r
268         cerr << "Error: stackwalk attempted on running process" << endl;\r
269 #ifndef BPATCH_LIBRARY\r
270       stopTimingStackwalk();\r
271 #endif\r
272       return false;\r
273     }\r
274     \r
275     // establish the current execution context\r
276     CONTEXT cont;\r
277     HANDLE hThread = (HANDLE)(currentFrame.getLWP()->get_fd());\r
278     \r
279     cont.ContextFlags = CONTEXT_FULL;\r
280     if (!GetThreadContext(hThread, &cont))\r
281     {\r
282         cerr << "walkStack: GetThreadContext failed:" << GetLastError()\r
283              << endl;\r
284 \r
285 #ifndef BPATCH_LIBRARY\r
286         stopTimingStackwalk();\r
287 #endif\r
288         return false;\r
289     }\r
290 \r
291     STACKFRAME sf;\r
292     ZeroMemory( &sf, sizeof(STACKFRAME) );\r
293     sf.AddrPC.Offset = cont.Eip;\r
294     sf.AddrPC.Mode = AddrModeFlat;\r
295     sf.AddrFrame.Offset = cont.Ebp;\r
296     sf.AddrFrame.Mode = AddrModeFlat;\r
297     sf.AddrStack.Offset = cont.Esp;\r
298     sf.AddrStack.Mode = AddrModeFlat;\r
299     sf.AddrReturn.Mode = AddrModeFlat;\r
300 \r
301     // walk the stack, frame by frame\r
302     // we use the Win32 StackWalk function to automatically\r
303     // handle compiler optimizations, especially FPO optimizations\r
304     bool done = false;\r
305 \r
306     while( !done ) {\r
307         STACKFRAME saved_sf = sf;\r
308         BOOL walked;\r
309         ADDRESS patchedAddrReturn;\r
310         ADDRESS patchedAddrPC;\r
311         instPoint* ip = NULL;\r
312         function_base* fp = NULL;\r
313 \r
314         // set defaults for return address and PC\r
315         patchedAddrReturn = saved_sf.AddrReturn;\r
316         patchedAddrPC = saved_sf.AddrPC;\r
317 \r
318         // try to step through the stack using the current information\r
319         walked = walkStackFrame((HANDLE)procHandle_,  hThread, &sf);\r
320 \r
321         if( !walked && (GetLastError() == ERROR_INVALID_ADDRESS) ) {\r
322 \r
323           // try to patch the return address, in case it is outside\r
324           // of the original text of the process.  It might be outside\r
325           // the original text if the function has been relocated, or\r
326           // if it represents a return from a call instruction that\r
327           // has been relocated to a base tramp.\r
328           // we first try to patch the return address only, because it\r
329           // is most likely that the return address only is out of the\r
330           // original text space.  Once we process the first stack\r
331           // frame, it appears that the StackWalk function transfers \r
332           // the return address from the STACKFRAME struct to the PC,\r
333           // so once we've gotten a valid return address in a \r
334           // STACKFRAME, the PC will be within the original text after\r
335           // the StackWalk\r
336           sf = saved_sf;\r
337           fp = findFunctionFromAddress( this, sf.AddrReturn.Offset );\r
338 \r
339           if( fp != NULL ) {\r
340             // because StackWalk seems to support it, we simply use \r
341             // the address of the function itself rather than\r
342             // trying to do the much more difficult task of finding\r
343             // the original address of the relocated instruction\r
344             patchedAddrReturn.Offset = fp->addr();\r
345             sf.AddrReturn = patchedAddrReturn;\r
346           }\r
347 \r
348           // retry the stack step\r
349           walked = \r
350               walkStackFrame((HANDLE)procHandle_, hThread, &sf);\r
351         }\r
352 \r
353         if( !walked && (GetLastError() == ERROR_INVALID_ADDRESS) ) {\r
354 \r
355           // patching the return address alone didn't work.\r
356           // try patching the return address and the PC\r
357           sf = saved_sf;\r
358           fp = findFunctionFromAddress( this, sf.AddrPC.Offset );\r
359 \r
360           if( fp != NULL ) {\r
361 \r
362             // because StackWalk seems to support it, we simply use \r
363             // the address of the function itself rather than\r
364             // trying to do the much more difficult task of finding\r
365             // the original address of the relocated instruction\r
366             patchedAddrPC.Offset = fp->addr();\r
367             sf.AddrPC = patchedAddrPC;\r
368           }\r
369 \r
370           // use the patched return address we calculated above\r
371           sf.AddrReturn = patchedAddrReturn;\r
372 \r
373           // retry the stack step\r
374           walked = \r
375               walkStackFrame((HANDLE)procHandle_, hThread, &sf);\r
376         }\r
377 \r
378         if( !walked && (GetLastError() == ERROR_INVALID_ADDRESS) )\r
379         {\r
380 \r
381           // patching both addresses didn't work\r
382           //\r
383           // try patching the PC only\r
384           sf = saved_sf;\r
385           sf.AddrPC = patchedAddrPC;\r
386 \r
387           // retry the stack step\r
388           walked = \r
389               walkStackFrame((HANDLE)procHandle_, hThread, &sf);\r
390         }\r
391 \r
392 \r
393         // by now we've tried all of our tricks to handle the stack \r
394         // frame if we haven't succeeded by now, we're not going to be\r
395         // able to handle this frame\r
396         if( walked ) {\r
397           \r
398           Address pc = NULL;\r
399           \r
400           // save the PC for this stack frame\r
401           // make sure we use the original address in case\r
402           // it was outside the original text of the process\r
403           if( saved_sf.AddrReturn.Offset == 0 ) {\r
404             \r
405             // this was the first stack frame, so we had better\r
406             // use the original PC\r
407             pc = saved_sf.AddrPC.Offset;\r
408             \r
409           } else {\r
410             \r
411             // this was not the first stack frame\r
412             // use the original return address\r
413             pc = saved_sf.AddrReturn.Offset;\r
414           }\r
415         \r
416           stackWalk.push_back(Frame(pc, 0, getPid(), \r
417                                     currentFrame.getThread(), \r
418                                     currentFrame.getLWP(), \r
419                                     false));\r
420 \r
421 #ifdef DEBUG_STACKWALK\r
422           cout << "0x" << setw(8) << setfill('0') << hex << pc << ": ";\r
423           \r
424           if( fp != NULL ) {\r
425             cout << fp->prettyName();\r
426           } else {\r
427             cout << "<unknown>";\r
428           }\r
429           \r
430           if( sf.AddrPC.Offset != pc ) {\r
431             cout << " (originally 0x" << setw(8) << setfill('0') \r
432                  << hex << sf.AddrPC.Offset << ")";\r
433           }\r
434           cout << endl;\r
435 #endif\r
436           \r
437         } else {\r
438           // we tried everything we know to recover - we'll have \r
439           // to fail\r
440           done = true;\r
441         }\r
442         \r
443     }\r
444 \r
445     // Terminate stack walk with an empty frame\r
446     stackWalk.push_back(Frame());\r
447 #ifndef BPATCH_LIBRARY\r
448     stopTimingStackwalk();\r
449 #endif\r
450 \r
451     return true;\r
452 }\r
453 #endif\r
454 \r
455 #if defined(mips_unknown_ce2_11) //ccw 6 feb 2001 : 29 mar 2001\r
456 //ccw 6 feb 2001 : windows CE does not have the NT walkStack function\r
457 //so we use this one.\r
458 \r
459 bool process::walkStackFromFrame(Frame currentFrame, pdvector<Frame> &stackWalk)\r
460 {\r
461     if (status_ == running) {\r
462         cerr << "Error: stackwalk attempeded on running process" << endl;\r
463         return false;\r
464     }  \r
465     Address spOld = 0xffffffff;\r
466     \r
467     while (!currentFrame.isLastFrame()) {\r
468         Address spNew = currentFrame.getSP(); // ccw 6 feb 2001 : should get SP?\r
469         \r
470         // successive frame pointers might be the same (e.g. leaf functions)\r
471         if (spOld < spNew) {\r
472             return false;            \r
473         }\r
474         \r
475         spOld = spNew;\r
476         \r
477         Address next_pc = currentFrame.getPC();\r
478         stackWalk.push_back(currentFrame);\r
479         \r
480         //ccw 6 feb 2001 : at this point, i need to use the \r
481         //list of functions parsed from the debug symbols to\r
482         //determine the frame size for each function and find the \r
483         //return value for each (which is the previous fir value)\r
484         currentFrame = currentFrame.getCallerFrame(this); \r
485         \r
486     }    \r
487     stackWalk.push_back(currentFrame);\r
488     return true;    \r
489 }\r
490 #endif\r
491 \r
492 \r
493 /* \r
494    Loading libDyninstRT.dll\r
495 \r
496    We load libDyninstRT.dll dynamically, by inserting code into the\r
497    application to call LoadLibraryA. We don't use the inferior RPC\r
498    mechanism from class process because it already assumes that\r
499    libdyninst is loaded (it uses the inferior heap).\r
500    Instead, we use a simple inferior call mechanism defined below\r
501    to insert the code to call LoadLibraryA("libdyninstRT.dll").\r
502  */\r
503 \r
504 Address loadDyninstDll(process *p, char Buffer[LOAD_DYNINST_BUF_SIZE]) {\r
505     return 0;\r
506 }\r
507 \r
508 // osTraceMe is not needed in Windows NT\r
509 void OS::osTraceMe(void) {}\r
510 \r
511 // Default continue type (modified by handlers)\r
512 DWORD continueType = DBG_CONTINUE; //ccw 25 oct 2000 : 28 mar 2001\r
513 \r
514 // Breakpoint handler\r
515 DWORD handleBreakpoint(process *proc,\r
516                        procSignalInfo_t info) {\r
517     Address addr = (Address) info.u.Exception.ExceptionRecord.ExceptionAddress;\r
518     \r
519     /*\r
520       printf("Debug breakpoint exception, %d, addr = %x\n", \r
521       info.u.Exception.ExceptionRecord.ExceptionFlags,\r
522       info.u.Exception.ExceptionRecord.ExceptionAddress);\r
523     */\r
524 \r
525     if (!proc->reachedBootstrapState(bootstrapped)) {\r
526         \r
527         // If we're attaching, the OS sends a stream of debug events\r
528         // to the mutator informing it of the status of the process.\r
529         // This finishes with a breakpoint that basically says\r
530         // "We're done, have fun". Check for that here.\r
531         if (proc->wasCreatedViaAttach() &&\r
532             !proc->reachedBootstrapState(initialized)) {\r
533             proc->setBootstrapState(initialized);\r
534             return DBG_CONTINUE;\r
535         }\r
536         \r
537         // Wait for the process to hit main before we start\r
538         // doing things to it (creation only)\r
539         if(!proc->reachedBootstrapState(begun)) {\r
540             proc->setBootstrapState(begun);\r
541             proc->insertTrapAtEntryPointOfMain();\r
542             proc->continueProc();\r
543             return DBG_CONTINUE;\r
544         }\r
545     \r
546         // When we hit main, cleanup and set init state\r
547         if (proc->trapAtEntryPointOfMain(addr)) {\r
548             proc->handleTrapAtEntryPointOfMain(); // cleanup\r
549             proc->setBootstrapState(initialized);\r
550             return DBG_CONTINUE;\r
551     }\r
552     \r
553         \r
554         // When dyninst lib load finishes, cleanup\r
555         if (proc->dyninstlib_brk_addr &&\r
556             (proc->dyninstlib_brk_addr == addr)) {\r
557             proc->dyninstlib_brk_addr = 0;\r
558             proc->loadDYNINSTlibCleanup();\r
559             proc->setBootstrapState(loadedRT);\r
560             return DBG_CONTINUE;\r
561         }\r
562     }\r
563 \r
564     // Hitting a base tramp?\r
565     \r
566 #if !defined( mips_unknown_ce2_11 )//ccw 26 july 2000 : 29 mar 2001\r
567     Address trampAddr = 0;\r
568     unsigned u; unsigned k;\r
569     unsigned key = addr;\r
570     for (u = HASH1(key); 1; u = (u + HASH2(key)) % TRAMPTABLESZ) {\r
571         k = proc->trampTable[u].key;\r
572         if (k == 0)\r
573             break;\r
574         else if (k == key) {\r
575             trampAddr = proc->trampTable[u].val;\r
576             break;\r
577         }\r
578     }\r
579     if (trampAddr) {\r
580         // this is a trap from an instrumentation point\r
581         \r
582         // find the current thread\r
583         dyn_thread* currThread = NULL;\r
584         for(unsigned int i = 0; i < proc->threads.size(); i++)\r
585         {\r
586             if ((unsigned)proc->threads[i]->get_tid() == info.dwThreadId)\r
587             {\r
588                 currThread = proc->threads[i];\r
589                 break;\r
590             }\r
591         }\r
592         assert( currThread != NULL );\r
593         \r
594         // Due to a race between the processing of trap debug events\r
595         // and the desire to run an inferior RPC, it is possible that\r
596         // we hit the trap, set ourselves up to run an inferior RPC,\r
597         // and then processed the trap notification.  If this happens,\r
598         // we don't end up running *any* of the inferior RPC code.\r
599         //\r
600         // We can tell that this is what's happened based on the\r
601         // thread's Eip - if it doesn't match the ExceptionAddress, we\r
602         // know that we had tried to reset the Eip to execute an inferior\r
603         // RPC.  In that case, we leave the Eip alone here, which means\r
604         // the inferior RPC code will execute when we continue the \r
605         // thread.\r
606         // We have to remember that we need to execute this \r
607         // instrumentation once the inferior RPC is done, however.\r
608         \r
609         CONTEXT cont;\r
610         cont.ContextFlags = CONTEXT_FULL;\r
611         if( !GetThreadContext( (HANDLE)currThread->get_lwp()->get_fd(), &cont ) )\r
612             assert(0 && "Failed to get thread context");\r
613         if( addr == Address(cont.Eip - 1) )\r
614         {\r
615             // The Eip indicates we've just executed a trap instruction\r
616             // reset the Eip to the address of the base tramp\r
617             cont.Eip = trampAddr;\r
618             if( !SetThreadContext( (HANDLE)currThread->get_lwp()->get_fd(), &cont ) )\r
619                 assert(0 && "Failed to set thread context");\r
620         }\r
621         else {\r
622             // We leave the Eip alone, since we've set it to execute \r
623             // at inferior RPC code.  However, we need to remember that\r
624             // we should execute the base tramp once the inferiorRPC is\r
625             // completed.\r
626             currThread->set_pending_tramp_addr( trampAddr );\r
627         }\r
628         // We're actually in instrumentation, so rerun the \r
629         // process\r
630         proc->continueProc();\r
631         return DBG_CONTINUE;\r
632     } // if trampAddr         \r
633 #endif // mips_unknown_ce2_11\r
634     \r
635     // If it is not from an instrumentation point,\r
636     // it could be from a call to DYNINSTbreakPoint,\r
637     // and so we leave paused\r
638 \r
639     return DBG_CONTINUE;\r
640 }\r
641 \r
642 DWORD handleIllegal(process *proc, procSignalInfo_t info) {\r
643 \r
644     Address addr = (Address) info.u.Exception.ExceptionRecord.ExceptionAddress;\r
645     \r
646     if( proc->handleTrapIfDueToRPC() )\r
647     {\r
648         // handleTrapIfDueToRPC calls continueproc()\r
649         // however, under Windows NT, it doesn't actually \r
650         // continue the thread until the ContinueDbgEvent call is made\r
651         \r
652         // We take advantage of this fact to ensure that any\r
653         // pending instrumentation is executed.  (I.e., instrumentation\r
654         // put off so we could be sure to execute inferior RPC code is\r
655         // now executed.)\r
656         if( !proc->getRpcMgr()->isRunningIRPC() )       {\r
657             // we finished the inferior RPC, so we can now execute\r
658             // any pending instrumentation\r
659             \r
660             // find the current thread\r
661             dyn_thread* currThread = NULL;\r
662             for( unsigned int i = 0; i < proc->threads.size(); i++ ) {\r
663                 if ((unsigned)proc->threads[i]->get_tid() == \r
664                     info.dwThreadId) {\r
665                     currThread = proc->threads[i];\r
666                     break;\r
667                 }\r
668             }\r
669             assert( currThread != NULL );\r
670             \r
671             Address pendingTrampAddr = currThread->get_pending_tramp_addr();\r
672             if( pendingTrampAddr) {\r
673                 // reset the Eip to the pending instrumentation\r
674                 CONTEXT ctxt;\r
675                 ctxt.ContextFlags = CONTEXT_FULL;\r
676                 if( !GetThreadContext( (HANDLE)currThread->get_lwp()->get_fd(), &ctxt ) )\r
677                     assert(0 && "Failed to get thread context");\r
678                 ctxt.Eip = pendingTrampAddr;\r
679                 if( !SetThreadContext( (HANDLE)currThread->get_lwp()->get_fd(), &ctxt ) )\r
680                     assert(0 && "Failed to set thread context");\r
681                 currThread->set_pending_tramp_addr(0);\r
682             }\r
683         }\r
684         // Inferior RPC states whether to leave running or paused\r
685         return DBG_CONTINUE;\r
686     }\r
687     proc->continueProc();\r
688     return DBG_EXCEPTION_NOT_HANDLED;\r
689 }\r
690 \r
691 DWORD handleViolation(process *proc, procSignalInfo_t info) {\r
692     /*\r
693           printf("Access violation exception, %d, addr = %08x\n", \r
694       info.u.Exception.ExceptionRecord.ExceptionFlags,\r
695       info.u.Exception.ExceptionRecord.ExceptionAddress);\r
696     */\r
697     dumpMem(proc, info.u.Exception.ExceptionRecord.ExceptionAddress, 32);\r
698     \r
699     {\r
700         \r
701 #ifndef mips_unknown_ce2_11 //ccw 6 feb 2001 : 29 mar 2001\r
702         // Should walk stacks for other threads as well\r
703         pdvector<pdvector<Frame> > stackWalks;\r
704         proc->walkStacks(stackWalks);\r
705         for (unsigned walk_iter = 0; walk_iter < stackWalks.size(); walk_iter++)\r
706             for( unsigned i = 0; i < stackWalks[walk_iter].size(); i++ )\r
707             {\r
708                 function_base* f = proc->findFuncByAddr( stackWalks[walk_iter][i].getPC() );\r
709                 const char* szFuncName = (f != NULL) ? f->prettyName().c_str() : "<unknown>";\r
710                 fprintf( stderr, "%08x: %s\n", stackWalks[walk_iter][i].getPC(), szFuncName );\r
711             }\r
712 #endif\r
713         \r
714     }\r
715     proc->continueProc();\r
716     return DBG_EXCEPTION_NOT_HANDLED;\r
717 }\r
718 \r
719 \r
720 // Exception dispatcher\r
721 DWORD handleException(process *proc, procSignalWhat_t what, procSignalInfo_t info) {\r
722     DWORD ret = DBG_EXCEPTION_NOT_HANDLED;\r
723 \r
724     switch (what) {\r
725   case EXCEPTION_BREAKPOINT: \r
726       ret = handleBreakpoint(proc, info);\r
727       break;\r
728   case EXCEPTION_ILLEGAL_INSTRUCTION:\r
729       ret = handleIllegal(proc, info);\r
730       break;\r
731   case EXCEPTION_ACCESS_VIOLATION:\r
732       ret = handleViolation(proc, info);\r
733       break;\r
734   default:\r
735       break;\r
736     }\r
737     return ret;\r
738 }\r
739 \r
740 // Thread creation\r
741 DWORD handleThreadCreate(process *proc, procSignalInfo_t info) {\r
742     dyn_lwp *l = proc->createLWP(info.dwThreadId, info.dwThreadId, \r
743                                  info.u.CreateThread.hThread);\r
744     l->openFD();\r
745     dyn_thread *t = new dyn_thread(proc, info.dwThreadId, // thread ID\r
746                                    proc->threads.size()-1, // POS (unused currently)\r
747                                    l); // dyn_lwp object for thread handle\r
748     proc->threads.push_back(t);\r
749     proc->continueProc();\r
750     return DBG_CONTINUE;\r
751 }\r
752 \r
753 // Process creation\r
754 DWORD handleProcessCreate(process *proc, procSignalInfo_t info) {\r
755     if (proc) {\r
756         dyn_lwp *l = proc->getDefaultLWP();\r
757         if (!l) {\r
758             // It's possible we never created the default LWP\r
759             l = proc->createLWP(info.dwThreadId, 0, \r
760                                 info.u.CreateProcessInfo.hThread);\r
761         }\r
762         if (proc->threads.size() == 0) {\r
763             dyn_thread *t = new dyn_thread(proc, info.dwThreadId, // thread ID,\r
764                                            0, // POS (main thread is always 0)\r
765                                            l);\r
766             // define the main thread\r
767             proc->threads.push_back(t);\r
768         }\r
769         else {\r
770             proc->threads[0]->update_tid(info.dwThreadId);\r
771             proc->threads[0]->update_lwp(l);\r
772         }\r
773     }\r
774     \r
775     proc->continueProc();\r
776     return DBG_CONTINUE;\r
777 }\r
778 \r
779 DWORD handleThreadExit(process *proc, procSignalInfo_t info) {\r
780     printf("exit thread, tid = %d\n", info.dwThreadId);\r
781     unsigned nThreads = proc->threads.size();\r
782     // start from one to skip main thread\r
783     for (unsigned u = 1; u < nThreads; u++) {\r
784         if ((unsigned)proc->threads[u]->get_tid() == info.dwThreadId) {\r
785             delete proc->threads[u];\r
786             proc->threads[u] = proc->threads[nThreads-1];\r
787             proc->threads.resize(nThreads-1);\r
788             break;\r
789         }\r
790     }\r
791     proc->continueProc();\r
792     return DBG_CONTINUE;\r
793 }\r
794 \r
795 DWORD handleProcessExit(process *proc, procSignalInfo_t info) {\r
796     if (proc) {\r
797         char errorLine[1024];\r
798         sprintf(errorLine, "Process %d has terminated with code 0x%x\n", \r
799                 proc->getPid(), info.u.ExitProcess.dwExitCode);\r
800           statusLine(errorLine);\r
801           logLine(errorLine);\r
802           handleProcessExit(proc, info.u.ExitProcess.dwExitCode);\r
803     }\r
804     proc->continueProc();\r
805     return DBG_CONTINUE;\r
806 }\r
807 \r
808 DWORD handleDllLoad(process *proc, procSignalInfo_t info) {\r
809     /*\r
810       printf("load dll: hFile=%x, base=%x, debugOff=%x, debugSz=%d lpname=%x, %d\n",\r
811       info.u.LoadDll.hFile, info.u.LoadDll.lpBaseOfDll,\r
812       info.u.LoadDll.dwDebugInfoFileOffset,\r
813       info.u.LoadDll.nDebugInfoSize,\r
814       info.u.LoadDll.lpImageName,\r
815       info.u.LoadDll.fUnicode\r
816       GetFileSize(info.u.LoadDll.hFile,NULL));\r
817     */\r
818     // This is NT's version of handleIfDueToSharedObjectMapping\r
819     \r
820     // Hacky hacky: after the Paradyn RT lib is loaded, skip further\r
821     // parsings. \r
822     \r
823     // obtain the name of the DLL\r
824     string imageName = GetLoadedDllImageName( proc, info );\r
825     \r
826     // try to load symbols for the DLL\r
827     if (!SymLoadModule((HANDLE)proc->getProcessHandle(),\r
828                        info.u.LoadDll.hFile,\r
829                        NULL, NULL, 0, 0)) {\r
830         \r
831         char msgText[1024];\r
832         \r
833         sprintf( msgText, "SymLoadModule failed for %s: 0x%x\n",\r
834                  imageName.c_str(), GetLastError() );\r
835         \r
836         logLine(msgText);\r
837     }\r
838     \r
839     // discover structure of new DLL, and incorporate into our\r
840     // list of known DLLs\r
841     if (imageName.length() > 0) {\r
842         shared_object *so = \r
843 #if defined( mips_unknown_ce2_11 )//ccw 29 mar 2001\r
844         new shared_object(imageName, (unsigned long) info.u.LoadDll.lpBaseOfDll,\r
845                           false, true, true, 0);\r
846 #else\r
847         new shared_object(imageName, 0,false, true, true, 0);\r
848 #endif\r
849         assert(proc->dyn);\r
850         proc->dyn->sharedObjects.push_back(so);\r
851         if (!proc->shared_objects) {\r
852             proc->shared_objects = new pdvector<shared_object *>;\r
853         }\r
854         (*(proc->shared_objects)).push_back(so);\r
855 #ifndef BPATCH_LIBRARY\r
856         tp->resourceBatchMode(true);\r
857 #endif \r
858         proc->addASharedObject(*so,(Address) info.u.LoadDll.lpBaseOfDll); //ccw 20 jun 2002\r
859 #ifndef BPATCH_LIBRARY\r
860         tp->resourceBatchMode(false);\r
861 #endif \r
862         proc->setDynamicLinking();\r
863         \r
864         char dllFilename[_MAX_FNAME];\r
865         _splitpath(imageName.c_str(),\r
866                    NULL, NULL, dllFilename, NULL);\r
867         \r
868         // See if there is a callback registered for this library\r
869         proc->runLibraryCallback(string(dllFilename));\r
870     }\r
871     \r
872     // WinCE used to check for "coredll.dll" here to see if the process\r
873     // was initialized, this should have been fixed by inserting a trap\r
874     // at the entry of main -- bernat, JAN03\r
875     proc->continueProc();\r
876     return DBG_CONTINUE;\r
877 }\r
878 \r
879 // ccw 2 may 2001 win2k fixes\r
880 // when you launch a process to be debugged with win2k (as in createProcess)\r
881 // the system sends you back at least two debug events before starting the\r
882 // process.  a debug event is also sent back for every dll that is loaded\r
883 // prior to starting main(), these include ntdll.dll and kernel32.dll and any\r
884 // other dlls the process needs that are not loaded with an explicit call\r
885 // to LoadLibrary().\r
886 //\r
887 // dyninst catches the first debug event (CREATE_PROCESS) and initializes\r
888 // various process specific data structures.  dyninst catches the second\r
889 // debug event (an EXCEPTION_DEBUG_EVENT) and used this event as a trigger to\r
890 // put in the bit of code that forced the mutatee to load\r
891 // libdyninstAPI_RT.dll.  In win2k, this does not work.  The bit of code is\r
892 // run and the trailing DebugBreak is caught and handled but the Dll will not\r
893 // be loaded.  The EXCEPTION_DEBUG_EVENT must be handled and continued from\r
894 // before LoadLibrary will perform correctly.\r
895 //\r
896 // the fix for this is to handle this EXCEPTION_DEBUG_EVENT, and put a\r
897 // DebugBreak (0xcc) at the beginning of main() in the mutatee.  catching\r
898 // that DebugBreak allows dyninst to write in the bit of code used to load\r
899 // the libdyninstAPI_RT.dll.\r
900 //\r
901 // after this, dyninst previously instrumented the mutatee to force the\r
902 // execution of DYNINSTinit() in the dll.  in order to take out this bit of\r
903 // complexity, the DllMain() function in the dll, which is run upon loading\r
904 // the dll, is used to automatically call DYNINSTinit().\r
905 //\r
906 // DYNINSTinit() takes two parameters, a flag denoting how dyninst attached\r
907 // to this process and the pid of the mutator.  These are passed from the\r
908 // mutator to the mutatee by finding a variable in the dll and writing the\r
909 // correct values into the mutatee's address space.  When a Dll is loaded, a\r
910 // LOAD_DLL debug event is thrown before the execution of DllMain(), so\r
911 // dyninst catches this event, writes the necessary values into the mutatee\r
912 // memory, then lets DllMain() call DYNINSTinit().  the DebugBreak() at the\r
913 // end of DYNINSTinit() is now removed for NT/win2K\r
914 //\r
915 // the bit of code inserted to load the dll fires a DebugBreak() to signal\r
916 // that it is done. dyninst catches this, patches up the code that was used\r
917 // to load the dll, replaces what was overwritten in main() and resets the\r
918 // instruction pointer (EIP) to the beginning of main().\r
919 \r
920 #ifdef mips_unknown_ce2_11\r
921 int secondDLL = 0; //ccw 24 oct 2000 : 28 mar 2001\r
922 #endif\r
923 \r
924 int handleProcessEvent(process *proc,\r
925                        procSignalWhy_t why,\r
926                        procSignalWhat_t what,\r
927                        procSignalInfo_t info) {\r
928     DWORD ret = DBG_EXCEPTION_NOT_HANDLED;\r
929     // Process is paused\r
930     // Make sure pause does something...\r
931     proc->savePreSignalStatus();\r
932     // Due to NT's odd method, we have to call pause_\r
933     // directly (a call to pause returns without doing anything\r
934     // pre-initialization)\r
935     proc->pause_();\r
936     proc->status_ = stopped;\r
937 \r
938     switch(why) {\r
939   case procException:\r
940       ret = handleException(proc, what, info);\r
941       break;\r
942   case procThreadCreate:\r
943       ret = handleThreadCreate(proc, info);\r
944       break;\r
945   case procProcessCreate:\r
946       ret = handleProcessCreate(proc, info);\r
947       break;\r
948   case procThreadExit:\r
949       ret = handleThreadExit(proc, info);\r
950       break;\r
951   case procProcessExit:\r
952       ret = handleProcessExit(proc, info);\r
953       break;\r
954   case procDllLoad:\r
955       ret = handleDllLoad(proc, info);\r
956       break;\r
957   default:\r
958       break;\r
959     }\r
960     // Continue the process after the debug event\r
961     \r
962 #if defined( mips_unknown_ce2_11 )//ccw 28 july 2000 : 29 mar 2001\r
963     if (!BPatch::bpatch->rDevice->RemoteContinueDebugEvent(info.dwProcessId, info.dwThreadId, \r
964                                                            ret))\r
965 #else\r
966     if (!ContinueDebugEvent(info.dwProcessId, info.dwThreadId, ret))\r
967 #endif\r
968     {\r
969         \r
970         DebugBreak();\r
971         printf("ContinueDebugEvent failed\n");\r
972         printSysError(GetLastError());\r
973     }\r
974     return (ret == DBG_CONTINUE);\r
975 }\r
976 \r
977 // Decode only, _NO_ process state changes!\r
978 process *decodeProcessEvent(int pid,\r
979                             procSignalWhy_t &why,\r
980                             procSignalWhat_t &what,\r
981                             procSignalInfo_t &info,\r
982                             bool block) {\r
983     process *proc;\r
984     \r
985     // We wait for 1 millisecond here. On the Unix platforms, the wait\r
986     // happens on the select in controllerMainLoop. But on NT, because\r
987     // we have to handle traps, we set the timeout on the select as 0,\r
988     // so that we can check for traps quickly\r
989 \r
990     DWORD milliseconds;\r
991     if (block) milliseconds = INFINITE;\r
992     else milliseconds = 1;\r
993 \r
994 #if defined(mips_unknown_ce2_11) //ccw 28 july 2000 : 29 mar 2001\r
995     if (!BPatch::bpatch->rDevice->RemoteWaitForDebugEvent(&info, milliseconds))\r
996 #else\r
997     if (!WaitForDebugEvent(&info, milliseconds))\r
998 #endif    \r
999         return NULL;\r
1000    \r
1001     proc = findProcess(info.dwProcessId);\r
1002     if (proc == NULL) {\r
1003         /* \r
1004            this case can happen when we create a process, but then are\r
1005            unable to parse the symbol table, and so don't complete the\r
1006            creation of the process. We just ignore the event here.  \r
1007         */\r
1008         \r
1009 #if defined(mips_unknown_ce2_11) //ccw 28 july 2000 : 29 mar 2001\r
1010         BPatch::bpatch->rDevice->RemoteContinueDebugEvent(info.dwProcessId, info.dwThreadId, \r
1011                                                           DBG_CONTINUE);\r
1012 #else\r
1013                 ContinueDebugEvent(info.dwProcessId, info.dwThreadId, \r
1014                            DBG_CONTINUE);\r
1015         \r
1016 #endif\r
1017         return NULL; \r
1018     }\r
1019     \r
1020     switch (info.dwDebugEventCode) {\r
1021   case EXCEPTION_DEBUG_EVENT:\r
1022       why = procException;\r
1023       what = info.u.Exception.ExceptionRecord.ExceptionCode;\r
1024       break;\r
1025   case CREATE_THREAD_DEBUG_EVENT:\r
1026       why = procThreadCreate;\r
1027       break;\r
1028   case CREATE_PROCESS_DEBUG_EVENT:\r
1029       why = procProcessCreate;\r
1030       break;\r
1031   case EXIT_THREAD_DEBUG_EVENT:\r
1032       why = procThreadExit;\r
1033       break;\r
1034   case EXIT_PROCESS_DEBUG_EVENT:\r
1035       why = procProcessExit;\r
1036       what = info.u.ExitProcess.dwExitCode;\r
1037       break;\r
1038   case LOAD_DLL_DEBUG_EVENT:\r
1039       why = procDllLoad;\r
1040       break;\r
1041   default:\r
1042       procUndefined;\r
1043       break;\r
1044     }\r
1045     \r
1046     return proc;\r
1047     \r
1048 }    \r
1049 \r
1050 // Global interface\r
1051 void decodeAndHandleProcessEvent(bool block) {\r
1052     procSignalWhy_t why;\r
1053     procSignalWhat_t what;\r
1054     procSignalInfo_t info;\r
1055     process *proc;\r
1056     \r
1057     proc = decodeProcessEvent(-1, why, what, info, block);\r
1058     if (!proc) return;\r
1059     handleProcessEvent(proc, why, what, info);\r
1060 }\r
1061 \r
1062 \r
1063 \r
1064 // already setup on this FD.\r
1065 // disconnect from controlling terminal \r
1066 void OS::osDisconnect(void) {\r
1067 #ifdef notdef\r
1068   int ttyfd = open ("/dev/tty", O_RDONLY);\r
1069   ioctl (ttyfd, TIOCNOTTY, NULL); \r
1070   P_close (ttyfd);\r
1071 #endif\r
1072 }\r
1073 \r
1074 dyn_lwp *process::createLWP(unsigned lwp_id, int index, handleT fd) {\r
1075    dyn_lwp *lwp = new dyn_lwp(lwp_id, fd, this);\r
1076    theRpcMgr->newLwpFound(lwp);\r
1077    lwps[index] = lwp;\r
1078    return lwp;\r
1079 }\r
1080 \r
1081 bool process::attach_() {\r
1082   if (createdViaAttach) {\r
1083 #ifdef mips_unknown_ce2_11 //ccw 28 july 2000 : 29 mar 2001\r
1084     if (!BPatch::bpatch->rDevice->RemoteDebugActiveProcess(getPid()))\r
1085 #else\r
1086     if (!DebugActiveProcess(getPid()))\r
1087 #endif\r
1088       {\r
1089         //printf("Error: DebugActiveProcess failed\n");\r
1090         return false;\r
1091       }\r
1092   }\r
1093 \r
1094 #ifdef mips_unknown_ce2_11 //ccw 28 july 2000 : 29 mar 2001\r
1095   procHandle_ = BPatch::bpatch->rDevice->RemoteOpenProcess(PROCESS_ALL_ACCESS, false, getPid());\r
1096 #else\r
1097   procHandle_ = OpenProcess(PROCESS_ALL_ACCESS, false, getPid());\r
1098 #endif\r
1099 \r
1100   \r
1101   if (procHandle_ == NULL) {\r
1102     //printf("Error: OpenProcess failed\n");\r
1103     assert(0);\r
1104   }\r
1105   \r
1106   void initSymbols(HANDLE procH, const string file, const string dir);\r
1107   initSymbols((HANDLE)procHandle_, symbols->file(), "");\r
1108   if (createdViaAttach) {\r
1109     //\r
1110     //void initSymbols(HANDLE procH, const string file, const string dir);\r
1111     //initSymbols((HANDLE)getDefaultLWP()->get_fd(), symbols->file(), "");\r
1112   }\r
1113 \r
1114   return true;\r
1115 }\r
1116 \r
1117 /* continue a process that is stopped */\r
1118 bool process::continueProc_() {\r
1119   for (unsigned u = 0; u < threads.size(); u++) {\r
1120       unsigned count;\r
1121       \r
1122 #ifdef mips_unknown_ce2_11 //ccw 10 feb 2001 : 29 mar 2001\r
1123       count = BPatch::bpatch->rDevice->RemoteResumeThread((HANDLE)threads[u]->get_lwp()->get_fd());\r
1124 #else\r
1125       count = ResumeThread((HANDLE)threads[u]->get_lwp()->get_fd());\r
1126 #endif\r
1127       if (count == 0xFFFFFFFF) {\r
1128           printSysError(GetLastError());\r
1129           return false;\r
1130       }\r
1131   }\r
1132   return true;\r
1133 }\r
1134 \r
1135 \r
1136 #ifdef BPATCH_LIBRARY\r
1137 /*\r
1138    terminate execution of a process\r
1139  */\r
1140 bool process::terminateProc_()\r
1141 {\r
1142     OS::osKill(pid);\r
1143     handleProcessExit(this, -1);\r
1144     return true;\r
1145 }\r
1146 #endif\r
1147 \r
1148 \r
1149 /*\r
1150    pause a process that is running\r
1151 */\r
1152 bool process::pause_() {\r
1153     for (unsigned u = 0; u < threads.size(); u++) {\r
1154         unsigned count ;\r
1155 #ifdef mips_unknown_ce2_11 //ccw 10 feb 2001 : 29 mar 2001\r
1156         count = BPatch::bpatch->rDevice->RemoteSuspendThread((HANDLE)threads[u]->get_lwp()->get_fd());\r
1157 #else\r
1158         count = SuspendThread((HANDLE)threads[u]->get_lwp()->get_fd());\r
1159 #endif\r
1160         if (count == 0xFFFFFFFF) {\r
1161             // printf("pause_: %d\n", threads[u]->get_tid());\r
1162             // printSysError(GetLastError());\r
1163             return false;\r
1164         } \r
1165     }\r
1166     return true;\r
1167 }\r
1168 \r
1169 /*\r
1170    close the file descriptor for the file associated with a process\r
1171 */\r
1172 bool process::detach_() {\r
1173    return false;\r
1174 }\r
1175 \r
1176 \r
1177 #ifdef BPATCH_LIBRARY\r
1178 /*\r
1179    detach from thr process, continuing its execution if the parameter "cont"\r
1180    is true.\r
1181  */\r
1182 bool process::API_detach_(const bool cont)\r
1183 {\r
1184     // XXX Not yet implemented\r
1185     assert(false);\r
1186     return false;\r
1187 }\r
1188 #endif\r
1189 \r
1190 \r
1191 bool process::dumpCore_(const string) {\r
1192     return false;\r
1193 }\r
1194 \r
1195 bool process::writeTextWord_(caddr_t inTraced, int data) {\r
1196     return writeDataSpace_(inTraced, sizeof(int), (caddr_t) &data);\r
1197 }\r
1198 \r
1199 bool process::writeTextSpace_(void *inTraced, u_int amount, const void *inSelf) {\r
1200     return writeDataSpace_(inTraced, amount, inSelf);\r
1201 }\r
1202 \r
1203 bool process::flushInstructionCache_(void *baseAddr, size_t size){ //ccw 25 june 2001\r
1204         return FlushInstructionCache((HANDLE)procHandle_, baseAddr, size);\r
1205 }\r
1206 \r
1207 #ifdef BPATCH_SET_MUTATIONS_ACTIVE\r
1208 bool process::readTextSpace_(void *inTraced, u_int amount, const void *inSelf) {\r
1209   return readDataSpace_(inTraced, amount, (void *)inSelf);\r
1210 }\r
1211 #endif\r
1212 \r
1213 bool process::writeDataSpace_(void *inTraced, u_int amount, const void *inSelf) {\r
1214     DWORD nbytes;\r
1215 \r
1216     //printf("write %d bytes, %x\n", amount, inTraced);\r
1217 #ifdef mips_unknown_ce2_11 //ccw 28 july 2000 : 29 mar 2001\r
1218     bool res = BPatch::bpatch->rDevice->RemoteWriteProcessMemory((HANDLE)procHandle_, (LPVOID)inTraced, \r
1219                                   (LPVOID)inSelf, (DWORD)amount, &nbytes);\r
1220 #else\r
1221     bool res = WriteProcessMemory((HANDLE)procHandle_, (LPVOID)inTraced, \r
1222                                   (LPVOID)inSelf, (DWORD)amount, &nbytes);\r
1223 #endif\r
1224     return res && (nbytes == amount);\r
1225 }\r
1226 \r
1227 \r
1228 bool process::readDataSpace_(const void *inTraced, u_int amount, void *inSelf) {\r
1229     DWORD nbytes;\r
1230 #ifdef mips_unknown_ce2_11 //ccw 28 july 2000 : 29 mar 2001\r
1231     bool res = BPatch::bpatch->rDevice->RemoteReadProcessMemory((HANDLE)procHandle_, (LPVOID)inTraced, \r
1232                                  (LPVOID)inSelf, (DWORD)amount, &nbytes);\r
1233 #else\r
1234     bool res = ReadProcessMemory((HANDLE)procHandle_, (LPVOID)inTraced, \r
1235                                  (LPVOID)inSelf, (DWORD)amount, &nbytes);\r
1236 #endif\r
1237     return res && (nbytes == amount);\r
1238 }\r
1239 \r
1240 \r
1241 bool process::loopUntilStopped() { assert(0); return false; }\r
1242 \r
1243 float OS::compute_rusage_cpu() { return 0.0; }\r
1244 float OS::compute_rusage_sys() { return 0.0; }\r
1245 float OS::compute_rusage_min() { return 0.0; }\r
1246 float OS::compute_rusage_maj() { return 0.0; }\r
1247 float OS::compute_rusage_swap() { return 0.0; }\r
1248 float OS::compute_rusage_io_in() { return 0.0; }\r
1249 float OS::compute_rusage_io_out() { return 0.0; }\r
1250 float OS::compute_rusage_msg_send() { return 0.0; }\r
1251 float OS::compute_rusage_msg_recv() { return 0.0; }\r
1252 float OS::compute_rusage_sigs() { return 0.0; }\r
1253 float OS::compute_rusage_vol_cs() { return 0.0; }\r
1254 float OS::compute_rusage_inv_cs() { return 0.0; }\r
1255 \r
1256 \r
1257 int getNumberOfCPUs() {\r
1258     SYSTEM_INFO info;\r
1259     GetSystemInfo(&info);\r
1260     return info.dwNumberOfProcessors;\r
1261 }  \r
1262 \r
1263 \r
1264 Frame dyn_lwp::getActiveFrame()\r
1265 {\r
1266   w32CONTEXT cont; //ccw 27 july 2000 : 29 mar 2001\r
1267   \r
1268   Address pc = 0, fp = 0, sp = 0;\r
1269   \r
1270   // we must set ContextFlags to indicate the registers we want returned,\r
1271   // in this case, the control registers.\r
1272   // The values for ContextFlags are defined in winnt.h\r
1273   cont.ContextFlags = CONTEXT_CONTROL;\r
1274 #ifdef mips_unknown_ce2_11 //ccw 28 july 2000 : 29 mar 2001\r
1275   if (BPatch::bpatch->rDevice->RemoteGetThreadContext((HANDLE)get_fd(), &cont))\r
1276 #else\r
1277   if (GetThreadContext((HANDLE)get_fd(), &cont))\r
1278 #endif\r
1279     {\r
1280 #ifdef i386_unknown_nt4_0 //ccw 27 july 2000 : 29 mar 2001\r
1281       fp = cont.Ebp;\r
1282       pc = cont.Eip;\r
1283 #elif mips_unknown_ce2_11\r
1284       pc = cont.Fir;\r
1285       sp = cont.IntSp;\r
1286       fp = cont.IntS8;\r
1287 #endif\r
1288       return Frame(pc, fp, sp, proc_->getPid(), NULL, this, true);\r
1289     }\r
1290     printSysError(GetLastError());\r
1291     return Frame();\r
1292 }\r
1293 \r
1294 #if defined(i386_unknown_nt4_0) //ccw 29 mar 2001\r
1295  \r
1296 \r
1297 Frame Frame::getCallerFrame(process *p) const\r
1298 {\r
1299     // For x86, the frame-pointer (EBP) points to the previous \r
1300     // frame-pointer, and the saved return address is in EBP-4.\r
1301 \r
1302     struct {\r
1303         Address fp;\r
1304         Address rtn;\r
1305     } addrs;\r
1306 \r
1307     if (p->readDataSpace((caddr_t)(fp_), sizeof(int)*2,\r
1308                          (caddr_t)&addrs, true))\r
1309     {\r
1310         Frame ret;\r
1311         ret.fp_ = addrs.fp;\r
1312         ret.pc_ = addrs.rtn;\r
1313         return ret;\r
1314     }\r
1315 \r
1316     return Frame(); // zero frame\r
1317 }\r
1318 \r
1319 #elif mips_unknown_ce2_11 //ccw 6 feb 2001\r
1320 \r
1321 Frame Frame::getCallerFrame(process *p) const\r
1322 {\r
1323 //      DebugBreak();//ccw 6 feb 2001\r
1324 \r
1325         Frame ret;\r
1326         Address prevPC;\r
1327 \r
1328         //find which function we are in to determine the frame size\r
1329 \r
1330         // (i.e. $pc in native/basetramp/minitramp code)\r
1331         instPoint     *ip = NULL;\r
1332         trampTemplate *bt = NULL;\r
1333         instInstance  *mt = NULL;\r
1334         pd_Function *callee = findAddressInFuncsAndTramps(p, pc_, ip, bt, mt);\r
1335         // non-NULL "ip" means that $pc is in instrumentation\r
1336         // non-NULL "bt" means that $pc is in basetramp\r
1337         // non-NULL "mt" means that $pc is in minitramp\r
1338         if (ip) assert(bt || mt);\r
1339 \r
1340         ret.sp_ = sp_ - callee->frame_size;\r
1341 \r
1342         Address tmpSp = sp_ + 20;\r
1343         p->readDataSpace((caddr_t)(tmpSp), sizeof(int),\r
1344                          &prevPC, true);\r
1345 \r
1346         ret.pc_ = prevPC;\r
1347           \r
1348 \r
1349         return ret;\r
1350 }\r
1351 #endif\r
1352 \r
1353 struct dyn_saved_regs *dyn_lwp::getRegisters() {\r
1354     struct dyn_saved_regs *regs = new dyn_saved_regs();\r
1355     \r
1356   // we must set ContextFlags to indicate the registers we want returned,\r
1357   // in this case, the control registers.\r
1358   // The values for ContextFlags are defined in winnt.h\r
1359   regs->cont.ContextFlags = w32CONTEXT_FULL;//ccw 27 july 2000 : 29 mar 2001\r
1360 #ifdef mips_unknown_ce2_11 //ccw 28 july 2000 : 29 mar 2001\r
1361   if (!BPatch::bpatch->rDevice->RemoteGetThreadContext((HANDLE)get_fd(), &(regs->cont)))\r
1362 #else\r
1363   handleT handle = get_fd();\r
1364   if (!GetThreadContext((HANDLE)handle, &(regs->cont)))\r
1365 #endif\r
1366   {\r
1367       return NULL;\r
1368   }\r
1369   return regs;\r
1370 }\r
1371 \r
1372 bool dyn_lwp::changePC(Address addr, struct dyn_saved_regs *regs)\r
1373 {\r
1374     \r
1375   w32CONTEXT cont;//ccw 27 july 2000\r
1376   if (!regs) {\r
1377       cont.ContextFlags = w32CONTEXT_FULL;//ccw 27 july 2000 : 29 mar 2001\r
1378       //        DebugBreak();\r
1379 #ifdef mips_unknown_ce2_11 //ccw 28 july 2000 : 29 mar 2001\r
1380       if (!BPatch::bpatch->rDevice->RemoteGetThreadContext((HANDLE)get_fd(), &cont)) \r
1381 #else\r
1382           if (!GetThreadContext((HANDLE)get_fd(), &cont))\r
1383 #endif\r
1384           {\r
1385               printf("GetThreadContext failed\n");\r
1386               return false;\r
1387           }\r
1388   }\r
1389   else {\r
1390       memcpy(&cont, &(regs->cont), sizeof(w32CONTEXT));\r
1391   }\r
1392 #ifdef i386_unknown_nt4_0 //ccw 27 july 2000 : 29 mar 2001 \r
1393   cont.Eip = addr;\r
1394 #elif  mips_unknown_ce2_11 \r
1395   cont.Fir = addr;\r
1396 #endif\r
1397 #ifdef mips_unknown_ce2_11 //ccw 28 july 2000 : 29 mar 2001\r
1398   if (!BPatch::bpatch->rDevice->RemoteSetThreadContext((HANDLE)get_fd(), &cont))\r
1399 #else\r
1400   if (!SetThreadContext((HANDLE)get_fd(), &cont))\r
1401 #endif\r
1402     {\r
1403       printf("SethreadContext failed\n");\r
1404       return false;\r
1405     }\r
1406   return true;\r
1407 }\r
1408 \r
1409 bool dyn_lwp::restoreRegisters(struct dyn_saved_regs *regs) {\r
1410 #ifdef mips_unknown_ce2_11 //ccw 28 july 2000 : 29 mar 2001\r
1411   if (!BPatch::bpatch->rDevice->RemoteSetThreadContext((HANDLE)get_fd(),\r
1412                                                        &(regs->cont)))\r
1413 #else\r
1414   if (!SetThreadContext((HANDLE)get_fd(), \r
1415                         &(regs->cont)))\r
1416 #endif\r
1417     {\r
1418       //printf("SetThreadContext failed\n");\r
1419       return false;\r
1420     }\r
1421   return true;\r
1422 }\r
1423 \r
1424 bool process::isRunning_() const {\r
1425     // TODO\r
1426     printf("process::isRunning_() returning true\n");\r
1427     return true;\r
1428 }\r
1429 \r
1430 \r
1431 string process::tryToFindExecutable(const string& iprogpath, int pid) {\r
1432   return iprogpath;\r
1433 }\r
1434 \r
1435 \r
1436 syscallTrap *process::trapSyscallExitInternal(Address syscall) {\r
1437     // Don't support trapping syscalls here yet, sorry\r
1438     return NULL;\r
1439 }\r
1440 \r
1441 bool process::clearSyscallTrapInternal(syscallTrap *trappedSyscall) {\r
1442     assert(0 && "Unimplemented");\r
1443     return true;\r
1444 }\r
1445 \r
1446 Address dyn_lwp::getCurrentSyscall() {\r
1447     return 0;\r
1448 }\r
1449 \r
1450 bool dyn_lwp::stepPastSyscallTrap() {\r
1451     return false;\r
1452 }\r
1453 \r
1454 int dyn_lwp::hasReachedSyscallTrap() {\r
1455     return 0;\r
1456 }\r
1457 \r
1458 Address dyn_lwp::readRegister(Register reg)\r
1459 {\r
1460    w32CONTEXT *cont = new w32CONTEXT;//ccw 27 july 2000 : 29 mar 2001\r
1461     if (!cont)\r
1462         return NULL;\r
1463     // we must set ContextFlags to indicate the registers we want returned,\r
1464     // in this case, the control registers.\r
1465     // The values for ContextFlags are defined in winnt.h\r
1466     cont->ContextFlags = w32CONTEXT_FULL;//ccw 27 july 2000\r
1467 #ifdef mips_unknown_ce2_11 //ccw 28 july 2000 : 29 mar 2001\r
1468     if (!BPatch::bpatch->rDevice->RemoteGetThreadContext((HANDLE)get_fd(), cont)) {\r
1469 #else\r
1470     if (!GetThreadContext((HANDLE)get_fd(), cont)) {\r
1471 #endif\r
1472         delete cont;\r
1473         return NULL;\r
1474     }\r
1475 #ifdef i386_unknown_nt4_0 //ccw 27 july 2000 : 29 mar 2001\r
1476     return cont->Eax;\r
1477 #elif mips_unknown_ce2_11 \r
1478         return (&cont->IntZero)[reg]; \r
1479         //the registers in the MIPS context returned by\r
1480         //winCE return general registers 0..31 in the struct\r
1481         //starting at IntZero and going to IntRa, each being a DWORD\r
1482 #endif\r
1483 }\r
1484 \r
1485 bool dyn_lwp::executingSystemCall() {\r
1486    // TODO\r
1487    return false;\r
1488 }\r
1489 \r
1490 \r
1491 void initSymbols(HANDLE procH, const string file, const string dir) {\r
1492   string searchPath;\r
1493   char sysRootDir[MAX_PATH+1];\r
1494   if (GetSystemDirectory(sysRootDir, MAX_PATH) == 0)\r
1495      assert(0);\r
1496   string sysSymsDir = string(sysRootDir) + "\\..\\symbols";\r
1497   if (dir.length())\r
1498     searchPath = dir + ";";\r
1499   searchPath = searchPath + sysSymsDir + ";" + sysSymsDir + "\\dll";\r
1500   if (!SymInitialize(procH, (char *)searchPath.c_str(), 0)) {\r
1501     fprintf(stderr,"SymInitialize failed, %x\n", GetLastError()); fflush(stderr);\r
1502     return;\r
1503   }\r
1504   if (!SymLoadModule(procH, NULL, (char *)file.c_str(), NULL, 0, 0)) {\r
1505     printf("SymLoadModule failed for \"%s\", %x\n",\r
1506             file.c_str(), GetLastError());\r
1507     return;\r
1508   }\r
1509 }\r
1510 \r
1511 \r
1512 \r
1513 \r
1514 \r
1515 /*****************************************************************************\r
1516  * forkNewProcess: starts a new process, setting up trace and io links between\r
1517  *                the new process and the daemon\r
1518  * Returns true if succesfull.\r
1519  * \r
1520  * Arguments:\r
1521  *   file: file to execute\r
1522  *   dir: working directory for the new process\r
1523  *   argv: arguments to new process\r
1524  *   envp: environment **** not in use\r
1525  *   inputFile: where to redirect standard input\r
1526  *   outputFile: where to redirect standard output\r
1527  *   traceLink: handle or file descriptor of trace link (read only)\r
1528  //removed all ioLink related code for output redirection\r
1529  *   ioLink: handle or file descriptor of io link (read only)\r
1530  *   pid: process id of new process\r
1531  *   tid: thread id for main thread (needed by WindowsNT)\r
1532  *   procHandle: handle for new process (needed by WindowsNT)\r
1533  *   thrHandle: handle for main thread (needed by WindowsNT)\r
1534  ****************************************************************************/\r
1535 bool forkNewProcess(string &file, string dir, pdvector<string> argv, \r
1536                     pdvector<string>envp, string inputFile, string outputFile,\r
1537                     int &traceLink,  \r
1538                     int &pid, int &tid, \r
1539                     int &procHandle, int &thrHandle, int /* stdin_fd */, \r
1540                     int stdout_fd, int /* stderr_fd */) {\r
1541 #ifdef mips_unknown_ce2_11 //ccw 8 aug 2000 : 29 mar 2001\r
1542         WCHAR appName[256];\r
1543         WCHAR dirName[256];\r
1544         WCHAR commLine[256];\r
1545 #endif\r
1546 \r
1547 #ifndef BPATCH_LIBRARY\r
1548 #ifdef notdef_Pipes     // isn't this all obsolete???\r
1549     HANDLE rTracePipe;\r
1550     HANDLE wTracePipe;\r
1551     // security attributes to make handles inherited\r
1552     SECURITY_ATTRIBUTES sa;\r
1553     sa.nLength = sizeof(SECURITY_ATTRIBUTES);\r
1554     sa.bInheritHandle = true;\r
1555     sa.lpSecurityDescriptor = NULL;\r
1556     \r
1557     // create trace pipe\r
1558     if (!CreatePipe(&rTracePipe, &wTracePipe, &sa, 0)) {\r
1559         string msg = string("Unable to create trace pipe for program '") \r
1560             + File + string("': ") + string(sys_errlist[errno]);\r
1561         showErrorCallback(68, msg);\r
1562         return(NULL);\r
1563     }\r
1564     \r
1565     /* removed for output redirection\r
1566     HANDLE rIoPipe;\r
1567     HANDLE wIoPipe;\r
1568     // create IO pipe\r
1569     // ioPipe is used to redirect the child's stdout & stderr to a pipe which\r
1570     // is in turn read by the parent via the process->ioLink socket.\r
1571     if (!CreatePipe(&rIoPipe, &wIoPipe, &sa, 0)) {\r
1572         string msg = string("Unable to create IO pipe for program '") + File +\r
1573             string("': ") + string(sys_errlist[errno]);\r
1574         showErrorCallback(68, msg);\r
1575         return(NULL);\r
1576     }\r
1577     SetEnvironmentVariable("PARADYN_IO_PIPE",\r
1578                            string((unsigned)wIoPipe).c_str());\r
1579     */\r
1580 \r
1581     printf("tracepipe = %d\n", (unsigned)wTracePipe);\r
1582     // enter trace and IO pipes in child's environment\r
1583     SetEnvironmentVariable("PARADYN_TRACE_PIPE", \r
1584                            string((unsigned)wTracePipe).c_str());\r
1585 #endif\r
1586     //  extern int traceSocket;\r
1587     //  SetEnvironmentVariable("PARADYND_TRACE_SOCKET", string((unsigned)traceSocket).c_str());\r
1588 #endif /* BPATCH_LIBRARY */\r
1589     \r
1590     // create the child process\r
1591     \r
1592     string args;\r
1593     for (unsigned ai=0; ai<argv.size(); ai++) {\r
1594         args += argv[ai];\r
1595         args += " ";\r
1596     }\r
1597 \r
1598     \r
1599     STARTUPINFO stinfo;\r
1600     memset(&stinfo, 0, sizeof(STARTUPINFO));\r
1601     stinfo.cb = sizeof(STARTUPINFO);\r
1602 \r
1603     /*to do: output redirection\r
1604     //stinfo.hStdOutput = (HANDLE)ioLink;\r
1605     stinfo.hStdOutput = (HANDLE)stdout_fd;\r
1606     stinfo.hStdInput = GetStdHandle(STD_INPUT_HANDLE);\r
1607     stinfo.hStdError = GetStdHandle(STD_ERROR_HANDLE);\r
1608     stinfo.dwFlags |= STARTF_USESTDHANDLES;\r
1609     */\r
1610     PROCESS_INFORMATION procInfo;\r
1611 #ifdef mips_unknown_ce2_11 //ccw 28 july 2000 : 29 mar 2001\r
1612         kludgeWCHAR(file.c_str(),appName);\r
1613         kludgeWCHAR(args.c_str(),commLine);\r
1614         if(dir == ""){\r
1615                 dirName[0] = (unsigned short) 0;\r
1616         }else{\r
1617                 kludgeWCHAR(dir.c_str(),dirName);\r
1618         }\r
1619 \r
1620         /* ccw 8 aug 2000  : 29 mar 2001\r
1621          WARNING:  \r
1622                 If compiler optimization are turned on (-Ox) for remoteDevice.C the following\r
1623                 line of code bugs. An extra parameter is passed to the function before \r
1624                 appName and consequently each argument is shifted one to the right, \r
1625                 completely destroying the code.\r
1626                 \r
1627                 DO NOT TURN ON -Ox for remoteDevice.C!\r
1628 \r
1629                 if need be, pdwinnt.C can be compiled with -Ox\r
1630                 less optimization may be safe, it has not yet been tried. if someone is bored\r
1631                 they should try different optimization flags to see if any work correctly here.\r
1632                 Until then the mips/ce version of dyninst will be compiled w/o ANY optimizations!\r
1633         */\r
1634         //DebugBreak();\r
1635     if (BPatch::bpatch->rDevice->RemoteCreateProcess(appName , commLine,\r
1636                       NULL, NULL, false,\r
1637                       (DWORD) DEBUG_PROCESS  /* | CREATE_NEW_CONSOLE /* | CREATE_SUSPENDED */,\r
1638                       NULL, dirName, \r
1639                       &stinfo, &procInfo)) {\r
1640 \r
1641 #else\r
1642     if (CreateProcess(file.c_str(), (char *)args.c_str(), \r
1643                       NULL, NULL, TRUE,\r
1644                       DEBUG_PROCESS /* | CREATE_NEW_CONSOLE /* | CREATE_SUSPENDED */,\r
1645                       NULL, dir == "" ? NULL : dir.c_str(), \r
1646                       &stinfo, &procInfo)) {\r
1647 #endif\r
1648 \r
1649         procHandle = (Word)procInfo.hProcess;\r
1650         thrHandle = (Word)procInfo.hThread;\r
1651         pid = (Word)procInfo.dwProcessId;\r
1652         tid = (Word)procInfo.dwThreadId;\r
1653 #ifdef notdef_Pipes\r
1654         traceLink = (Word)rTracePipe;\r
1655         CloseHandle(wTracePipe);\r
1656         / *removed for output redirection\r
1657         //ioLink = (Word)rIoPipe;\r
1658         CloseHandle(wIoPipe);\r
1659         */\r
1660         //initSymbols((HANDLE)procHandle, file, dir);\r
1661 #else\r
1662         traceLink = -1;\r
1663         /* removed for output redirection\r
1664         ioLink = -1;\r
1665         */\r
1666 #endif\r
1667         return true;\r
1668     }\r
1669    \r
1670 #ifndef BPATCH_LIBRARY\r
1671 #ifdef notdef_Pipes\r
1672     CloseHandle(rTracePipe);\r
1673     CloseHandle(wTracePipe);\r
1674     / *removed for output redirection\r
1675     CloseHandle(rIoPipe);\r
1676     CloseHandle(wIoPipe);\r
1677     */\r
1678 #endif\r
1679 #endif /* BPATCH_LIBRARY */\r
1680 \r
1681     // Output failure message\r
1682     LPVOID lpMsgBuf;\r
1683 \r
1684     if (FormatMessage( \r
1685             FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,\r
1686             NULL,\r
1687             GetLastError(),\r
1688             MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language\r
1689             (LPTSTR) &lpMsgBuf,\r
1690             0,\r
1691             NULL \r
1692         ) > 0) {\r
1693         char *errorLine = (char *)malloc(strlen((char *)lpMsgBuf) +\r
1694                                          file.length() + 64);\r
1695         if (errorLine != NULL) {\r
1696             sprintf(errorLine, "Unable to start %s: %s\n", file.c_str(),\r
1697                     (char *)lpMsgBuf);\r
1698             logLine(errorLine);\r
1699             showErrorCallback(68, (const char *) errorLine);\r
1700 \r
1701             free(errorLine);\r
1702         }\r
1703 \r
1704         // Free the buffer returned by FormatMsg\r
1705         LocalFree(lpMsgBuf);\r
1706     } else {\r
1707         char errorLine[512];\r
1708         sprintf(errorLine, "Unable to start %s: unknown error\n",\r
1709                 file.c_str());\r
1710         logLine(errorLine);\r
1711         showErrorCallback(68, (const char *) errorLine);\r
1712     }\r
1713 \r
1714     return false;\r
1715 }\r
1716 \r
1717 /*\r
1718  * stripAtSuffix\r
1719  *\r
1720  * Strips off of a string any suffix that consists of an @ sign followed by\r
1721  * decimal digits.\r
1722  *\r
1723  * str  The string to strip the suffix from.  The string is altered in place.\r
1724  */\r
1725 static void stripAtSuffix(char *str)\r
1726 {\r
1727     // many symbols have a name like foo@4, we must remove the @4\r
1728     // just searching for an @ is not enough,\r
1729     // as it may occur on other positions. We search for the last one\r
1730     // and check that it is followed only by digits.\r
1731     char *p = strrchr(str, '@');\r
1732     if (p) {\r
1733       char *q = p+1;\r
1734       strtoul(p+1, &q, 10);\r
1735       if (q > p+1 && *q == '\0') {\r
1736         *p = '\0';\r
1737       }\r
1738     }\r
1739 }\r
1740 \r
1741 char *cplus_demangle(char *c, int) { \r
1742     char buf[1000];\r
1743     if (c[0]=='_') {\r
1744         // VC++ 5.0 seems to decorate C symbols differently to C++ symbols\r
1745         // and the UnDecorateSymbolName() function provided by imagehlp.lib\r
1746         // doesn't manage (or want) to undecorate them, so it has to be done\r
1747         // manually, removing a leading underscore from functions & variables\r
1748         // and the trailing "$stuff" from variables (actually "$Sstuff")\r
1749         unsigned i;\r
1750         for (i=1; i<sizeof(buf) && c[i]!='$' && c[i]!='\0'; i++)\r
1751            { buf[i-1]=c[i]; }\r
1752         buf[i-1]='\0';\r
1753         stripAtSuffix(buf);\r
1754         if (buf[0] == '\0') return 0; // avoid null names which seem to annoy Paradyn\r
1755         return strdup(buf);\r
1756       }\r
1757     else if (UnDecorateSymbolName(c, buf, 1000, UNDNAME_NAME_ONLY)) {\r
1758         //printf("Undecorate: %s = %s\n", c, buf);\r
1759         stripAtSuffix(buf);\r
1760         return strdup(buf);\r
1761     }\r
1762     return 0;\r
1763 }\r
1764 \r
1765 bool OS::osKill(int pid) {\r
1766     bool res;\r
1767 #ifdef mips_unknown_ce2_11 //ccw 28 july 2000 : 29 mar 2001\r
1768     HANDLE h = BPatch::bpatch->rDevice->RemoteOpenProcess(PROCESS_ALL_ACCESS, false, pid);\r
1769 #else\r
1770     HANDLE h = OpenProcess(PROCESS_ALL_ACCESS, false, pid);\r
1771 #endif\r
1772     if (h == NULL) {\r
1773         return false;\r
1774     }\r
1775 #ifdef mips_unknown_ce2_11 //ccw 31 aug 2000 : 29 mar 2001\r
1776     res = BPatch::bpatch->rDevice->RemoteTerminateProcess(h,0);\r
1777     BPatch::bpatch->rDevice->RemoteCloseHandle(h);\r
1778 #else\r
1779     res = TerminateProcess(h,0);\r
1780     CloseHandle(h);\r
1781 #endif\r
1782     return res;\r
1783 }\r
1784 \r
1785 #if !defined(BPATCH_LIBRARY)\r
1786 rawTime64 dyn_lwp::getRawCpuTime_hw() {\r
1787   fprintf(stderr, "dyn_lwp::getRawCpuTime_hw: not implemented\n");\r
1788   return 0;\r
1789 }\r
1790 \r
1791 rawTime64\r
1792 FILETIME2rawTime64( FILETIME& ft )\r
1793 {\r
1794     return (((rawTime64)(ft).dwHighDateTime<<32) | \r
1795             ((rawTime64)(ft).dwLowDateTime));\r
1796 }\r
1797 \r
1798 /* return unit: nsecs */\r
1799 rawTime64 dyn_lwp::getRawCpuTime_sw() \r
1800 {\r
1801   FILETIME kernelT, userT, creatT, exitT;\r
1802   rawTime64 now;\r
1803   if(GetThreadTimes( (HANDLE)fd_,\r
1804       &creatT, &exitT, &kernelT,&userT)==0) {\r
1805     return 0;\r
1806   }\r
1807 \r
1808   // GetProcessTimes returns values in 100-ns units\r
1809   now = (FILETIME2rawTime64(userT)+FILETIME2rawTime64(kernelT));\r
1810 \r
1811   // time shouldn't go backwards, but we'd better handle it if it does\r
1812 //  printf(" %I64d %I64d \n", now, previous);\r
1813   if (now < sw_previous_) {\r
1814           //DebugBreak();\r
1815      logLine("********* time going backwards in paradynd **********\n");\r
1816      now = sw_previous_;\r
1817   }\r
1818   else {\r
1819      sw_previous_ = now;\r
1820   }\r
1821 \r
1822   return now;\r
1823 }\r
1824 \r
1825 bool process::catchupSideEffect(Frame &frame, instReqNode *inst)\r
1826 {\r
1827   return true;\r
1828 }\r
1829 \r
1830 #endif\r
1831 \r
1832 #ifdef mips_unknown_ce2_11 //ccw 2 aug 2000 : 29 mar 2001\r
1833 \r
1834 #include "inst-mips.h"\r
1835 //this comes from irix.C\r
1836 bool process::heapIsOk(const pdvector<sym_data>&findUs)\r
1837\r
1838         \r
1839   //ccw 12 oct 2000 NEED TO FIND WinMain here or _WinMain then try to find main or _main\r
1840 //      DebugBreak();\r
1841 \r
1842 \r
1843   if (!(mainFunction = findOneFunction("WinMain")) &&\r
1844           !(mainFunction = findOneFunction("_WinMain"))) {\r
1845                 fprintf(stderr, "process::heapIsOk(): failed to find \"WinMain\"\n");\r
1846 \r
1847                 if (!(mainFunction = findOneFunction("main")) &&\r
1848                 !(mainFunction = findOneFunction("_main"))) {\r
1849 \r
1850                         if (!(mainFunction = findOneFunction("wWinMain")) &&\r
1851                                 !(mainFunction = findOneFunction("_wWinMain"))) {\r
1852 \r
1853                                 fprintf(stderr, "process::heapIsOk(): failed to find \"main\"\n");\r
1854                                 return false;\r
1855                         }\r
1856           }     \r
1857   }\r
1858 \r
1859   for (unsigned i = 0; i < findUs.size(); i++) {\r
1860     const string &name = findUs[i].name;\r
1861     /*\r
1862     Address addr = lookup_fn(this, name);\r
1863     if (!addr && findUs[i].must_find) {\r
1864       fprintf(stderr, "process::heapIsOk(): failed to find \"%s\"\n", name.c_str());\r
1865       return false;\r
1866     }\r
1867     */\r
1868   }\r
1869 \r
1870   return true;\r
1871 }\r
1872 #endif\r
1873 \r
1874 \r
1875 fileDescriptor *getExecFileDescriptor(string filename, int &, bool)\r
1876 {\r
1877   fileDescriptor *desc = new fileDescriptor(filename);\r
1878   return desc;\r
1879 }\r
1880 \r
1881 #ifndef BPATCH_LIBRARY\r
1882 void process::initCpuTimeMgrPlt() {\r
1883   cpuTimeMgr->installLevel(cpuTimeMgr_t::LEVEL_TWO, &process::yesAvail, \r
1884                            timeUnit(fraction(100)), timeBase::bNone(), \r
1885                            &process::getRawCpuTime_sw, "swCpuTimeFPtrInfo");\r
1886 }\r
1887 #endif\r
1888 \r
1889 bool getLWPIDs(pdvector <unsigned> &LWPids)\r
1890 {\r
1891   assert (0 && "Not implemented");\r
1892   return false;\r
1893 }\r
1894 \r
1895 \r
1896 \r
1897 \r
1898 //\r
1899 // This function retrieves the name of a DLL that has been\r
1900 // loaded in an inferior process.  On the desktop flavors\r
1901 // of Windows, the debug event that we get for loaded DLLs\r
1902 // includes the location of a pointer to the DLL's image name.\r
1903 // (Note the indirection.)  On Windows CE, the event contains\r
1904 // the location of the image name string, with no indirection.\r
1905 //\r
1906 // There are several complications to overcome when reading this string:\r
1907 //\r
1908 // 1.  There is no guarantee that the image name is available.\r
1909 //     In this case, the location in the debug event may be NULL,\r
1910 //     or the pointer in the inferior process' address space may be NULL.\r
1911 // 2.  The image name string may be either ASCII or Unicode.  Most of\r
1912 //     the Windows system DLLs have Unicode strings, but many user-built\r
1913 //     DLLs use single-byte strings.  If the string is Unicode, we need\r
1914 //     to copy it to our address space and convert it to a single-byte\r
1915 //     string because the rest of Paradyn/Dyninst has no clue what to\r
1916 //     do with Unicode strings.\r
1917 // 3.  We don't know how long the string is.  We have a loose upper\r
1918 //     bound in that we know it is not more than MAX_PATH characters.\r
1919 //     Unfortunately, the call we use to read from the inferior\r
1920 //     process' address space will return failure if we ask for more\r
1921 //     bytes than it can actually read (so we can't just issue a read\r
1922 //     for MAX_PATH characters).  Given this limitation, we have to\r
1923 //     try a read and check whether the read succeeded *and* whether\r
1924 //     we read the entire image name string.  If not, we have to adjust\r
1925 //     the amount we read and try again.\r
1926 //\r
1927 static\r
1928 string\r
1929 GetLoadedDllImageName( process* p, const DEBUG_EVENT& ev )\r
1930 {\r
1931         string ret;\r
1932 \r
1933 \r
1934         if( ev.u.LoadDll.lpImageName == NULL )\r
1935         {\r
1936                 // there is no image name string for us to read\r
1937                 return ret;\r
1938         }\r
1939 \r
1940         char* msgText = new char[1024]; // buffer for error messages\r
1941 \r
1942 #if defined(mips_unknown_ce2_11)\r
1943 \r
1944         // On Windows CE, the address given in the debug event struct\r
1945         // is the address of the DLL name string.\r
1946         void* pImageName = ev.u.LoadDll.lpImageName;\r
1947 #else // defined(ce)\r
1948         // On non-CE flavors of Windows, the address given in the debug\r
1949         // event struct is the address of a pointer to the DLL name string.\r
1950         void* pImageName = NULL;\r
1951         if( !p->readDataSpace( ev.u.LoadDll.lpImageName, 4, &pImageName, false ) )\r
1952         {\r
1953                 sprintf( msgText, "Failed to read DLL image name pointer: %d\n",\r
1954                         GetLastError() );\r
1955                 logLine( msgText );\r
1956         }\r
1957 #endif // defined(ce)\r
1958 \r
1959         if( pImageName != NULL )\r
1960         {\r
1961                 // we have the pointer to the DLL image name -\r
1962                 // now read the name\r
1963 \r
1964                 // allocate a conservatively-sized buffer\r
1965                 char* buf = new char[(MAX_PATH + 1) * sizeof(WCHAR)];\r
1966                 WCHAR* wbuf = (WCHAR*)buf;\r
1967 \r
1968                 // We don't know how long the image name actually is, but\r
1969                 // we do know that they tend not to be very long.\r
1970                 // Therefore, we use a scheme to try to minimize the number\r
1971                 // of reads needed to get the image name.\r
1972                 // We do reads within ranges, starting with [1,128] bytes,\r
1973                 // then [129,256] bytes, etc. up to MAX_PATH if necessary.\r
1974                 // Within each range, we do reads following a binary search\r
1975                 // algorithm.  For example, for the [1,128] range, we start\r
1976                 // by trying to read 128 bytes.  If that read fails, we\r
1977                 // try to half the number of bytes (i.e., 64).  If that\r
1978                 // read also fails, we continue to halve the read requests \r
1979                 // until we find one that succeeds.\r
1980                 //\r
1981                 // When a read succeeds, we still may not have gotten the\r
1982                 // entire string.  So when reads start succeeding, we have to\r
1983                 // check the data we got for a null-terimated string.  If we didn't\r
1984                 // get the full string, we change the byte count to either\r
1985                 // move into the next higher range (if we were already reading\r
1986                 // the max within the current range) or we set it to a factor\r
1987                 // of 1.5 of the current byte count to try a value between the\r
1988                 // current succeeding read and one that had failed.\r
1989                 unsigned int loRead = 1;                // range boundaries\r
1990                 unsigned int hiRead = 128;\r
1991                 unsigned int cbRead = 128;              // number of bytes to read\r
1992                 unsigned int chunkRead = 64;    // amount to change cbRead if we fail\r
1993                                                                                 // we will not halve this before we read\r
1994                 bool gotString = false;\r
1995                 bool doneReading = false;\r
1996                 while( !doneReading )\r
1997                 {\r
1998                         // try the read with the current byte count\r
1999                         if( p->readDataSpace( pImageName, cbRead, buf, false ) )\r
2000                         {\r
2001                                 // the read succeeded - \r
2002                                 // did we get the full string?\r
2003                                 if( ev.u.LoadDll.fUnicode )\r
2004                                 {\r
2005                                         unsigned int cbReadIdx = cbRead / sizeof(WCHAR);\r
2006                                         wbuf[cbReadIdx] = L'\0';\r
2007                                         WCHAR* nulp = wcschr( wbuf, L'\0' );\r
2008                                         assert( nulp != NULL );                 // because we just NULL-terminated the string\r
2009                                         gotString = (nulp != &(wbuf[cbReadIdx]));\r
2010                                 }\r
2011                                 else\r
2012                                 {\r
2013                                         buf[cbRead] = '\0';\r
2014                                         char* nulp = strchr( buf, '\0' );\r
2015                                         assert( nulp != NULL );                 // because we just NULL-terminated the string\r
2016                                         gotString = (nulp != &(buf[cbRead]));\r
2017                                 }\r
2018 \r
2019                                 if( gotString )\r
2020                                 {\r
2021                                         doneReading = true;\r
2022                                 }\r
2023                                 else\r
2024                                 {\r
2025                                         // we didn't get the full string\r
2026                                         // we need to try a larger read\r
2027                                         if( cbRead == hiRead )\r
2028                                         {\r
2029                                                 // we were at the high end of the current range -\r
2030                                                 // move to the next range\r
2031                                                 loRead = hiRead + 1;\r
2032                                                 hiRead = loRead + 128 - 1;\r
2033                                                 chunkRead = 128;                                // we will halve this before we read again\r
2034                                                 if( loRead > (MAX_PATH * sizeof(WCHAR)) )\r
2035                                                 {\r
2036                                                         // we've tried every range but still failed\r
2037                                                         doneReading = true;\r
2038                                                 }\r
2039                                                 else\r
2040                                                 {\r
2041                                                         cbRead = hiRead;\r
2042                                                 }\r
2043                                         }\r
2044                                         else\r
2045                                         {\r
2046                                                 // we were within the current range -\r
2047                                                 // try something higher but still within the range\r
2048                                                 cbRead = cbRead + chunkRead;\r
2049                                         }\r
2050                                 }\r
2051                         }\r
2052                         else\r
2053                         {\r
2054                                 // the read failed -\r
2055                                 // we need to try a smaller read\r
2056                                 if( cbRead > loRead )\r
2057                                 {\r
2058                                         unsigned int nextRead = cbRead - chunkRead;\r
2059                                         if( nextRead == cbRead )\r
2060                                         {\r
2061                                                 // we can't subdivide any further\r
2062                                                 doneReading = true;\r
2063                                         }\r
2064                                         else\r
2065                                         {\r
2066                                                 cbRead = nextRead;\r
2067                                         }\r
2068                                 }\r
2069                                 else\r
2070                                 {\r
2071                                         // there are no smaller reads to try in this range,\r
2072                                         // and by induction, in any range.\r
2073                                         doneReading = true;\r
2074                                 }\r
2075                         }\r
2076 \r
2077                         // update the amount that we use to change the read request\r
2078                         chunkRead /= 2;\r
2079                 }\r
2080 \r
2081                 if( !gotString )\r
2082                 {\r
2083                         // this is a serious problem because some read \r
2084                         // should've succeeded\r
2085                         sprintf( msgText, "Failed to read DLL image name - no read succeeded\n" );\r
2086                         logLine( msgText );\r
2087                 }\r
2088                 else\r
2089                 {\r
2090                         if( ev.u.LoadDll.fUnicode )\r
2091                         {\r
2092                                 // the DLL path is a Unicode string\r
2093                                 // we have to convert it to single-byte characters\r
2094                                 char* tmpbuf = new char[MAX_PATH];\r
2095 \r
2096                                 WideCharToMultiByte(CP_ACP,             // code page to use (ANSI)\r
2097                                                                         0,                      // flags\r
2098                                                                         wbuf,           // Unicode string\r
2099                                                                         -1,                     // length of Unicode string (-1 => null-terminated)\r
2100                                                                         tmpbuf,         // destination buffer\r
2101                                                                         MAX_PATH,       // size of destionation buffer\r
2102                                                                         NULL,           // default for unmappable chars\r
2103                                                                         NULL);          // var to set when defaulting a char\r
2104 \r
2105                                 // swap buffers so that buf points to the single-byte string\r
2106                                 // when we're out of this code block\r
2107                                 delete[] buf;\r
2108                                 buf = tmpbuf;\r
2109                         }\r
2110                         ret = buf;\r
2111                 }\r
2112 \r
2113                 delete[] buf;\r
2114         }\r
2115         else\r
2116         {\r
2117                 // we were given an image name pointer, but it was NULL\r
2118                 // this happens for some system DLLs, and if we attach to\r
2119                 // the process instead of creating it ourselves.\r
2120                 // However, it is very important for us to know about kernel32.dll,\r
2121                 // so we check for it specially.\r
2122                 //\r
2123                 // This call only changes the string parameter if the indicated file is\r
2124                 // actually kernel32.dll.\r
2125                 kludge_isKernel32Dll( ev.u.LoadDll.hFile, ret );\r
2126         }\r
2127 \r
2128         // cleanup\r
2129         delete[] msgText;\r
2130 \r
2131         return ret;\r
2132 }\r
2133 \r
2134 bool dyn_lwp::openFD_()\r
2135 {\r
2136   // Nothing to do here that I know of, since we are handed the FD\r
2137   // as part of a debug message\r
2138   return true;\r
2139 }\r
2140 \r
2141 void dyn_lwp::closeFD_()\r
2142 {\r
2143   return;\r
2144 }\r
2145 \r
2146 \r
2147 // Insert a breakpoint at the entry of main()\r
2148 \r
2149 void process::insertTrapAtEntryPointOfMain() {\r
2150     // if this was created via attach then\r
2151     // we are not at main() so no reason to\r
2152     // put a breakpoint there, we are already\r
2153     // at a state that will allow loadLibrary() to\r
2154     // succeed. \r
2155     \r
2156     function_base *mainFunc;\r
2157     //DebugBreak();//ccw 14 may 2001  \r
2158     if (!((mainFunc = findOneFunction("main")))){\r
2159         if(!(mainFunc = findOneFunction("_main"))){\r
2160             if(!(mainFunc = findOneFunction("WinMain"))){\r
2161                 if(!(mainFunc = findOneFunction("_WinMain"))){\r
2162                     if(!(mainFunc = findOneFunction("wWinMain"))){\r
2163                         if(!(mainFunc = findOneFunction("_wWinMain"))){\r
2164                             assert(0);\r
2165                         }\r
2166                     }\r
2167                 }\r
2168             }\r
2169         }\r
2170         \r
2171     }\r
2172     main_brk_addr = mainFunc->addr();\r
2173     \r
2174     readDataSpace((void*) (main_brk_addr), BYTES_TO_SAVE, (void*)savedCodeBuffer, false);\r
2175     \r
2176     // A trap instruction. \r
2177     unsigned char trapInsn = 0xcc;\r
2178     \r
2179     // write the modified code sequence back\r
2180     writeDataSpace((void*) (main_brk_addr), sizeof(trapInsn), \r
2181                    (void*)&trapInsn);\r
2182     flushInstructionCache_( (void*)main_brk_addr, sizeof(trapInsn) );\r
2183 }\r
2184 \r
2185 // True if we hit the trap at the entry of main\r
2186 \r
2187 bool process::trapAtEntryPointOfMain(Address trapAddr) {\r
2188     if (!main_brk_addr) return false;\r
2189     if (trapAddr == main_brk_addr) {\r
2190         return true;\r
2191     }\r
2192     return false;\r
2193 }\r
2194 \r
2195 \r
2196 // Clean up after breakpoint in main() is hit\r
2197 void process::handleTrapAtEntryPointOfMain()\r
2198 {\r
2199     // Rewrite saved registers and code buffer\r
2200     assert(main_brk_addr);\r
2201 \r
2202     writeDataSpace((void *)main_brk_addr,\r
2203                    sizeof(unsigned char), (void *)savedCodeBuffer);\r
2204     flushInstructionCache_((void *)main_brk_addr, sizeof(unsigned char));\r
2205 \r
2206     // And bump the PC back\r
2207     getDefaultLWP()->changePC(main_brk_addr, NULL);\r
2208 \r
2209     // Don't trap here accidentally\r
2210     main_brk_addr = 0;\r
2211 }\r
2212 \r
2213 // Load the dyninst library\r
2214 bool process::loadDYNINSTlib()\r
2215 {\r
2216     Address codeBase = getImage()->codeOffset();\r
2217     \r
2218     Address LoadLibBase;\r
2219     Address LoadLibAddr;\r
2220     Symbol sym;\r
2221 \r
2222 \r
2223 #ifdef mips_unknown_ce2_11 //ccw 14 aug 2000 : 29 mar 2001\r
2224 \r
2225         Address hackLoadLibAddr = 0x01f9ac30; //ccw 2 feb 2001 : HACK\r
2226     \r
2227         //ccw 2 feb 2001\r
2228         //this is a terrible hack.  i know that LoadLibrary is 0xac30 bytes from\r
2229         //the base address of coredll.dll from emprical evidence.  i have no\r
2230         //debug symbols for coredll.dll to prove this dynamically though....\r
2231         \r
2232         for(int i=0; i< (p->sharedObjects())->size();i++){\r
2233                 \r
2234                 if((*p->sharedObjects())[i]->getName() == "coredll.dll" ){\r
2235                         hackLoadLibAddr = (*p->sharedObjects())[i]->getBaseAddress() + 0x0000bf1c;\r
2236                         //0x0000ac30; //HACK 24 apr 2001\r
2237                 }\r
2238         }\r
2239 #else\r
2240         if (!getSymbolInfo("_LoadLibraryA@4", sym, LoadLibBase)) {\r
2241         if( !getSymbolInfo( "_LoadLibraryA", sym, LoadLibBase ))\r
2242         {\r
2243                 printf("unable to find function LoadLibrary\n");\r
2244                 assert(0);\r
2245         }\r
2246     }\r
2247     LoadLibAddr = sym.addr() + LoadLibBase;\r
2248     assert(LoadLibAddr);\r
2249 #endif\r
2250     char ibuf[BYTES_TO_SAVE];\r
2251     char *iptr = ibuf;\r
2252         memset(ibuf, '\0', BYTES_TO_SAVE);//ccw 25 aug 2000\r
2253 \r
2254     // Code overview:\r
2255     // Dynininst library name\r
2256     //    Executable code begins here:\r
2257     // Push (address of dyninst lib name)\r
2258     // Call LoadLibrary\r
2259     // Pop (cancel push)\r
2260     // Trap\r
2261 \r
2262     process::dyninstRT_name = getenv("DYNINSTAPI_RT_LIB");\r
2263     \r
2264     if (!process::dyninstRT_name.length())\r
2265         // if environment variable unset, use the default name/strategy\r
2266         process::dyninstRT_name = "libdyninstAPI_RT.dll";\r
2267         \r
2268     // make sure that directory separators are what LoadLibrary expects\r
2269     strcpy(iptr, process::dyninstRT_name.c_str());\r
2270     for (unsigned int i=0; i<strlen(iptr); i++)\r
2271         if (iptr[i]=='/') iptr[i]='\\';\r
2272 \r
2273     // 4: give us plenty of room after the string to start instructions\r
2274     int instructionOffset = strlen(iptr) + 4;\r
2275     // Regenerate the pointer\r
2276     iptr = &(ibuf[instructionOffset]);\r
2277     \r
2278     // At this point, the buffer contains the name of the dyninst\r
2279     // RT lib. We now generate code to load this string into memory\r
2280     // via a call to LoadLibrary\r
2281 \r
2282     // push nameAddr ; 5 bytes\r
2283     *iptr++ = (char)0x68; \r
2284     // Argument for push\r
2285     *(int *)iptr = codeBase; // string at codeBase\r
2286     iptr += sizeof(int);\r
2287 \r
2288     int offsetFromBufferStart = (int)iptr - (int)ibuf;\r
2289     offsetFromBufferStart += 5; // Skip next instruction as well.\r
2290     // call LoadLibrary ; 5 bytes\r
2291     *iptr++ = (char)0xe8;\r
2292    \r
2293     // Jump offset is relative\r
2294     *(int *)iptr = LoadLibAddr - (codeBase + \r
2295                                   offsetFromBufferStart); // End of next instruction\r
2296     iptr += sizeof(int);\r
2297 \r
2298 \r
2299     // add sp, 4 (Pop)\r
2300     *iptr++ = (char)0x83; *iptr++ = (char)0xc4; *iptr++ = (char)0x04;\r
2301 \r
2302     // int3\r
2303     *iptr = (char)0xcc;\r
2304 \r
2305     int offsetToTrap = (int) iptr - (int) ibuf;\r
2306 \r
2307     readDataSpace((void *)codeBase, BYTES_TO_SAVE, savedCodeBuffer, false);\r
2308     writeDataSpace((void *)codeBase, BYTES_TO_SAVE, ibuf);\r
2309     flushInstructionCache_((void *)codeBase, BYTES_TO_SAVE);\r
2310     \r
2311 \r
2312 #ifdef mips_unknown_ce2_11 //ccw 22 aug 2000\r
2313     assert(0 && "Need to update dyninst lib load instructions");\r
2314 #else\r
2315     dyninstlib_brk_addr = codeBase + offsetToTrap;\r
2316 #endif\r
2317 \r
2318 \r
2319     savedRegs = getDefaultLWP()->getRegisters();\r
2320 \r
2321     getDefaultLWP()->changePC(codeBase + instructionOffset, NULL);\r
2322 \r
2323     setBootstrapState(loadingRT);\r
2324 \r
2325     return true;\r
2326 }\r
2327 \r
2328 \r
2329 \r
2330 // Not used on NT. We'd have to rewrite the\r
2331 // prototype to take a PC. Handled inline.\r
2332 // True if trap is from dyninst load finishing\r
2333 bool process::trapDueToDyninstLib()\r
2334 {\r
2335     assert(0);\r
2336     return true;\r
2337 }\r
2338 \r
2339 \r
2340 \r
2341 // Cleanup after dyninst lib loaded\r
2342 bool process::loadDYNINSTlibCleanup()\r
2343 {\r
2344    \r
2345     // First things first: \r
2346     getDefaultLWP()->restoreRegisters(savedRegs);\r
2347     delete savedRegs;\r
2348 \r
2349     writeDataSpace((void *)getImage()->codeOffset(),\r
2350                                       BYTES_TO_SAVE,\r
2351                                       (void *)savedCodeBuffer);\r
2352 \r
2353     flushInstructionCache_((void *)getImage()->codeOffset(), BYTES_TO_SAVE);\r
2354 \r
2355     dyninstlib_brk_addr = 0;\r
2356 \r
2357     return true;\r
2358 }\r
2359 \r
2360 //MIPS code from loadDyninstLib. I'm sticking it here\r
2361 //to assist in debugging NT. Copy it back in when needed\r
2362 \r
2363 #if 0\r
2364 \r
2365         //the following are the instructions to load libdyninstRT_API.dll\r
2366         \r
2367         //ccw 2 oct 2000\r
2368         //the instructions we need to generate are:\r
2369         // lui $a0,hi16(codeBase)  # codeBase contains libBuf\r
2370         // ori $a0,lo16(codeBase)\r
2371         // lui $t0, hi16(hackLoadLibAddr)\r
2372         // ori $t0, lo16(hackLoadLibAddr)\r
2373         // jalr $t0\r
2374         // nop\r
2375         // nop\r
2376         // break\r
2377         // nop\r
2378         // nop\r
2379         // nop\r
2380         // where libBuf is the location of the string containing the name of the dll\r
2381         // in the remote process's memory\r
2382 \r
2383         WCHAR libBuf[] = L"\\libdyninstAPI_RT.dll";\r
2384         BYTE instBuff[4]; //buffer for the instruction to write to memory;\r
2385 \r
2386         //lay the name of the DLL to load into memory, UNICODE!\r
2387         assert(memcpy(iptr, (char*)libBuf, 42));\r
2388         iptr +=42;\r
2389         memset(iptr, '\0', 2);\r
2390         iptr +=2;\r
2391 \r
2392         //LUI //ccw 2 oct 2000\r
2393         instBuff[0]=((char*) &codeBase)[2];\r
2394         instBuff[1]=((char*) &codeBase)[3];\r
2395         instBuff[2]=0x04;\r
2396         instBuff[3]=0x3C;\r
2397         memcpy(iptr, (char*) &instBuff, 4);\r
2398         iptr +=4;\r
2399 \r
2400         //ORI //ccw 2 oct 2000\r
2401         instBuff[0]=((char*) &codeBase)[0];\r
2402         instBuff[1]=((char*) &codeBase)[1];\r
2403         instBuff[2]=0x84;\r
2404         instBuff[3]=0x34;\r
2405         memcpy(iptr, (char*) &instBuff, 4);\r
2406         iptr +=4;\r
2407 \r
2408         //LUI //ccw 2 feb 2001\r
2409         instBuff[0]=((char*) &hackLoadLibAddr)[2];\r
2410         instBuff[1]=((char*) &hackLoadLibAddr)[3];\r
2411         instBuff[2]=0x08;\r
2412         instBuff[3]=0x3C;\r
2413         memcpy(iptr, (char*) &instBuff, 4);\r
2414         iptr +=4;\r
2415 \r
2416         //ORI //ccw 2 feb 2001\r
2417         instBuff[0]=((char*) &hackLoadLibAddr)[0];\r
2418         instBuff[1]=((char*) &hackLoadLibAddr)[1];\r
2419         instBuff[2]=0x08;\r
2420         instBuff[3]=0x35;\r
2421         memcpy(iptr, (char*) &instBuff, 4);\r
2422         iptr +=4;\r
2423 \r
2424         //JALR\r
2425         instBuff[0]=0x09;\r
2426         instBuff[1]=0xf8;\r
2427         instBuff[2]=0x00;\r
2428         instBuff[3]=0x01;\r
2429         memcpy(iptr, (char*) &instBuff, 4);\r
2430         iptr +=4;\r
2431 \r
2432 \r
2433         //NOP\r
2434         instBuff[0]=0x00;\r
2435         instBuff[1]=0x00;\r
2436         instBuff[2]=0x00;\r
2437         instBuff[3]=0x00;\r
2438         memcpy(iptr, (char*) &instBuff, 4);\r
2439         iptr +=4;\r
2440 \r
2441         //NOP\r
2442         instBuff[0]=0x00;\r
2443         instBuff[1]=0x00;\r
2444         instBuff[2]=0x00;\r
2445         instBuff[3]=0x00;\r
2446         memcpy(iptr, (char*) &instBuff, 4);\r
2447         iptr +=4;\r
2448 \r
2449 \r
2450         //DebugBreak();\r
2451         instBuff[0]=0x0D;\r
2452         instBuff[1]=0x00;\r
2453         instBuff[2]=0x00;\r
2454         instBuff[3]=0x00;\r
2455         memcpy(iptr, (char*) &instBuff, 4);\r
2456         iptr +=4;\r
2457 \r
2458 \r
2459         //ccw 25 aug 2000 : throw some NOPs after the debugBreak just in case!\r
2460         //NOP\r
2461         instBuff[0]=0x00;\r
2462         instBuff[1]=0x00;\r
2463         instBuff[2]=0x00;\r
2464         instBuff[3]=0x00;\r
2465         memcpy(iptr, (char*) &instBuff, 4);\r
2466         iptr +=4;\r
2467         \r
2468         memcpy(iptr, (char*) &instBuff, 4);\r
2469         iptr +=4;\r
2470 \r
2471         memcpy(iptr, (char*) &instBuff, 4);\r
2472         iptr +=4;\r
2473 \r
2474 #endif\r