2 * Copyright (c) 1996 Barton P. Miller
4 * We provide the Paradyn Parallel Performance Tools (below
5 * described as Paradyn") on an AS IS basis, and do not warrant its
6 * validity or performance. We reserve the right to update, modify,
7 * or discontinue this software at any time. We shall have no
8 * obligation to supply such updates or modifications or any other
9 * form of support to you.
11 * This license is for research uses. For such uses, there is no
12 * charge. We define "research use" to mean you may freely use it
13 * inside your organization for whatever purposes you see fit. But you
14 * may not re-distribute Paradyn or parts of Paradyn, in any form
15 * source or binary (including derivatives), electronic or otherwise,
16 * to any other organization or entity without our permission.
18 * (for other uses, please contact us at paradyn@cs.wisc.edu)
20 * All warranties, including without limitation, any warranty of
21 * merchantability or fitness for a particular purpose, are hereby
24 * By your use of Paradyn, you understand and agree that we (or any
25 * other person or entity with proprietary rights in Paradyn) are
26 * under no obligation to provide either maintenance services,
27 * update services, notices of latent defects, or correction of
28 * defects for Paradyn.
30 * Even if advised of the possibility of such damages, under no
31 * circumstances shall we (or any other person or entity with
32 * proprietary rights in the software licensed hereunder) be liable
33 * to you or any third party for direct, indirect, or consequential
34 * damages of any character regardless of type of action, including,
35 * without limitation, loss of profits, loss of use, loss of good
36 * will, or computer failure or malfunction. You agree to indemnify
37 * us (and any other person or entity with proprietary rights in the
38 * software licensed hereunder) for any and all liability it may
39 * incur to third parties resulting from your use of Paradyn.
42 #include "dyninstAPI/src/symtab.h"
43 #include "util/h/headers.h"
44 #include "dyninstAPI/src/os.h"
45 #include "dyninstAPI/src/process.h"
46 #include "dyninstAPI/src/pdThread.h"
47 #include "dyninstAPI/src/stats.h"
48 #include "util/h/Types.h"
49 #include "paradynd/src/showerror.h"
51 #ifndef BPATCH_LIBRARY
52 #include "paradynd/src/main.h"
56 /* XXX This is only needed for emulating signals. */
57 #include "BPatch_thread.h"
58 #include "nt_signal_emul.h"
61 extern bool isValidAddress(process *proc, Address where);
62 extern process *findProcess(int);
64 //HANDLE kludgeProcHandle;
66 void printSysError(unsigned errNo) {
68 FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, errNo,
69 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
71 fprintf(stderr, "*** System error [%d]: %s\n", errNo, buf);
76 // check if a file handle is for kernel32.dll
77 static bool kludge_isKernel32Dll(HANDLE fileHandle, string &kernel32Name) {
78 static DWORD IndxHigh, IndxLow;
79 static bool firstTime = true;
80 BY_HANDLE_FILE_INFORMATION info;
81 static string kernel32Name_;
86 char sysRootDir[MAX_PATH+1];
87 if (GetSystemDirectory(sysRootDir, MAX_PATH) == 0)
89 kernel32Name_ = string(sysRootDir) + "\\kernel32.dll";
90 kernel32H = CreateFile(kernel32Name_.string_of(), GENERIC_READ,
91 FILE_SHARE_READ, NULL, OPEN_EXISTING, NULL, NULL);
93 if (!GetFileInformationByHandle(kernel32H, &info)) {
94 printSysError(GetLastError());
97 IndxHigh = info.nFileIndexHigh;
98 IndxLow = info.nFileIndexLow;
99 CloseHandle(kernel32H);
102 if (!GetFileInformationByHandle(fileHandle, &info))
105 if (info.nFileIndexHigh==IndxHigh && info.nFileIndexLow==IndxLow) {
106 kernel32Name = kernel32Name_;
113 void dumpMem(process *p, void * addr, unsigned nbytes) {
114 unsigned char *buf = new unsigned char[nbytes];
115 memset(buf, 0, nbytes);
119 if (f = p->findFunctionIn((Address)addr))
120 printf("Function %s, addr=%x, sz=%d\n",
121 f->prettyName().string_of(),
124 p->readDataSpace((void *)((unsigned)addr-32), nbytes, buf, true);
125 printf("## %x:\n", (unsigned)addr-32);
126 for (unsigned u = 0; u < nbytes; u++)
127 printf(" %x", buf[u]);
128 p->readDataSpace(addr, nbytes, buf, true);
129 printf("## %x:\n", addr);
130 for (unsigned u1 = 0; u1 < nbytes; u1++)
131 printf(" %x", buf[u1]);
137 process::walkStack - get a stack trace using the imagehlp function StackWalk
138 Because the compiler can do optimizations that omit the frame pointer,
139 it may not be possible to get a complete stack trace in some cases.
140 We assume that a trace is complete if we get to the main function (main or WinMain).
141 If we can't get a complete trace, we return an empty vector.
143 vector<Address> process::walkStack(bool noPause) {
145 bool needToCont = noPause ? false : (status() == running);
147 if (!noPause && !pause()) {
148 // pause failed...give up
149 cerr << "walkStack: pause failed" << endl;
153 static STACKFRAME zero;
154 STACKFRAME sf = zero;
157 cont.ContextFlags = CONTEXT_FULL;
158 if (!GetThreadContext((HANDLE)threads[0]->get_handle(), &cont))
159 cerr << "walkStack: GetThreadContext failed\n";
160 //fprintf(stderr, "Context: EIP = %x, ESP = %x, EBP = %x\n",
161 // cont.Eip, cont.Esp, cont.Ebp);
164 sf.AddrPC.Offset = cont.Eip;
165 sf.AddrPC.Mode = AddrModeFlat;
166 sf.AddrFrame.Offset = cont.Ebp;
167 sf.AddrFrame.Mode = AddrModeFlat;
168 sf.AddrStack.Offset = cont.Esp;
169 sf.AddrStack.Mode = AddrModeFlat;
171 sf.AddrReturn.Mode = AddrModeFlat;
174 bool reachedMain = false; // set to true if we reach the main function
176 res = StackWalk(IMAGE_FILE_MACHINE_I386, (HANDLE)getProcFileDescriptor(), NULL,
178 ReadProcessMemory, SymFunctionTableAccess, SymGetModuleBase,
181 if (!res && GetLastError() == 0) {
182 // reached end of stack
184 } else if (!res && GetLastError() != 0) {
185 // error - can't complete stack walk
186 //fprintf(stderr, "error walking stack\n");
187 //printSysError(GetLastError());
191 if (findFunctionIn(sf.AddrPC.Offset)==getMainFunction())
194 pcs += sf.AddrPC.Offset;
197 if (sf.AddrReturn.Offset == 0) {
204 //for (unsigned u = 0; u < pcs.size(); u++) {
205 // function_base *pdf = findFunctionIn(pcs[u]);
206 // fprintf(stderr,"> %x (%s)\n", pcs[u], pdf ? pdf->prettyName().string_of() : "");
211 // error - incomplete trace, return an empty vector
213 //fprintf(stderr, "****** walkStack failed\n"); fflush(stderr);
216 if (!noPause && needToCont) {
217 if (!continueProc()){
218 cerr << "walkStack: continueProc failed" << endl;
227 Loading libDyninstRT.dll
229 We load libDyninstRT.dll dynamically, by inserting code into the
230 application to call LoadLibraryA. We don't use the inferior RPC
231 mechanism from class process because it already assumes that
232 libdyninst is loaded (it uses the inferior heap).
233 Instead, we use a simple inferior call mechanism defined below
234 to insert the code to call LoadLibraryA("libdyninstRT.dll").
237 Address loadDyninstDll(process *p, char Buffer[LOAD_DYNINST_BUF_SIZE]) {
238 Address codeBase = p->getImage()->codeOffset();
243 if (!p->getSymbolInfo("_LoadLibraryA@4", sym, LoadLibBase)) {
244 printf("unable to find function LoadLibrary\n");
247 LoadLibAddr = sym.addr() + LoadLibBase;
250 char ibuf[LOAD_DYNINST_BUF_SIZE];
253 // push nameAddr ; 5 bytes
254 *iptr++ = (char)0x68;
255 *(int *)iptr = codeBase + 14;
258 // call LoadLibrary ; 5 bytes
259 *iptr++ = (char)0xe8;
260 // offset relative to next instruction (address codeBase+10)
261 *(int *)iptr = LoadLibAddr - (codeBase + 10);
265 *iptr++ = (char)0x83; *iptr++ = (char)0xc4; *iptr++ = (char)0x04;
268 *iptr++ = (char)0xcc;
270 #ifdef BPATCH_LIBRARY
271 strcpy(iptr, "libdyninstAPI_RT.dll");
273 strcpy(iptr, "libdyninstRT.dll");
276 p->readDataSpace((void *)codeBase, LOAD_DYNINST_BUF_SIZE, Buffer, false);
277 p->writeDataSpace((void *)codeBase, LOAD_DYNINST_BUF_SIZE, ibuf);
284 // osTraceMe is not needed in Windows NT
285 void OS::osTraceMe(void) {}
288 #ifndef BPATCH_LIBRARY
289 void checkProcStatus() {
291 extern void doDeferredRPCs();
293 process::waitProcs(&wait_status);
299 wait for inferior processes to terminate or stop.
301 #ifdef BPATCH_LIBRARY
302 int process::waitProcs(int *status, bool block) {
304 int process::waitProcs(int *status) {
308 #ifdef BPATCH_LIBRARY
312 // We wait for 1 milisecond here. On the Unix platforms, the wait
313 // happens on the select in controllerMainLoop. But on NT, because
314 // we have to handle traps, we set the timeout on the select as 0,
315 // so that we can check for traps quicly
316 #ifdef BPATCH_LIBRARY
318 if (block) milliseconds = INFINITE;
319 else milliseconds = 1;
320 if (!WaitForDebugEvent(&debugEv, milliseconds))
323 if (!WaitForDebugEvent(&debugEv, 1))
327 //printf("Debug event from process %d, tid %d\n", debugEv.dwProcessId,
328 // debugEv.dwThreadId);
330 p = findProcess(debugEv.dwProcessId);
333 this case can happen when we create a process, but then are
334 unable to parse the symbol table, and so don't complete the
335 creation of the process. We just ignore the event here.
337 ContinueDebugEvent(debugEv.dwProcessId, debugEv.dwThreadId,
342 switch (debugEv.dwDebugEventCode) {
343 case EXCEPTION_DEBUG_EVENT: {
344 DWORD exnCode = debugEv.u.Exception.ExceptionRecord.ExceptionCode;
346 case EXCEPTION_BREAKPOINT: {
347 //printf("Debug breakpoint exception, %d, addr = %x\n",
348 // debugEv.u.Exception.ExceptionRecord.ExceptionFlags,
349 // debugEv.u.Exception.ExceptionRecord.ExceptionAddress);
351 if (!p->reachedFirstBreak) {
353 if (!p->hasLoadedDyninstLib && !p->isLoadingDyninstLib) {
354 Address addr = loadDyninstDll(p, p->savedData);
355 p->savedRegs = p->getRegisters();
357 //p->LoadDyninstTrapAddr = addr + 0xd;
358 p->isLoadingDyninstLib = true;
360 } else if (p->isLoadingDyninstLib) {
361 p->isLoadingDyninstLib = false;
362 p->hasLoadedDyninstLib = true;
363 p->restoreRegisters(p->savedRegs);
365 p->writeDataSpace((void *)p->getImage()->codeOffset(),
366 LOAD_DYNINST_BUF_SIZE,
367 (void *)p->savedData);
370 p->reachedFirstBreak = true;
372 if (!p->createdViaAttach) {
373 int pid = p->getPid();
374 p->status_ = stopped;
376 if (!p->initDyninstLib()) {
378 handleProcessExit(p, -1);
379 #ifdef BPATCH_LIBRARY
380 *status = SIGEM_SIGNALED | SIGTERM;
387 string buffer = string("PID=") + string(pid);
388 buffer += string(", passed trap at start of program");
389 statusLine(buffer.string_of());
391 buffer=string("PID=") + string(pid)
392 + ", installing call to DYNINSTinit()";
393 statusLine(buffer.string_of());
394 p->installBootstrapInst();
396 // now, let main() and then DYNINSTinit() get invoked. As it
397 // completes, DYNINSTinit() does a DYNINSTbreakPoint, at which time
398 // we read bootstrap information "sent back" (in a global vrble),
399 // propagate metric instances, do tp->newProgramCallbackFunc(), etc.
402 //printf("First breakpoint after attach\n");
408 // the process has already been initialized
409 // First lookup in the tramp table, to see if the breakpoint
410 // is from an instrumentation point.
412 // lookup in tramp table
413 unsigned trampAddr = 0;
414 unsigned u; unsigned k;
416 (unsigned)debugEv.u.Exception.ExceptionRecord.ExceptionAddress;
417 for (u = HASH1(key); 1; u = (u + HASH2(key)) % TRAMPTABLESZ) {
418 k = p->trampTable[u].key;
422 trampAddr = p->trampTable[u].val;
427 // this is a trap from an instrumentation point
428 // change the PC to the address of the base tramp
430 for (unsigned i = 0; i < p->threads.size(); i++) {
431 if (p->threads[i]->get_tid()==debugEv.dwThreadId) {
432 HANDLE thrH = (HANDLE)p->threads[i]->get_handle();
434 cont.ContextFlags = CONTEXT_FULL;
435 if (!GetThreadContext(thrH, &cont))
437 cont.Eip = trampAddr;
438 if (!SetThreadContext(thrH, &cont))
446 // If it is not from an instrumentation point,
447 // it could be from a call to DYNINSTbreakPoint
448 // or an inferior procedure call
450 p->status_ = stopped;
452 int result = p->procStopFromDYNINSTinit();
453 assert(result >= 0 && result <= 2);
458 // procStopFromDYNINSTinit called continueProc()
459 // What should we do here?
462 } else if (p->handleTrapIfDueToRPC()) {
466 #ifdef BPATCH_LIBRARY /* Don't ignore unknown bkpt in library; leave stopped. */
467 *status = SIGEM_STOPPED | SIGTRAP;
469 // Unknown breakpoint: we just ignore it
470 printf("Debug breakpoint exception, %d, addr = %x\n",
471 debugEv.u.Exception.ExceptionRecord.ExceptionFlags,
472 debugEv.u.Exception.ExceptionRecord.ExceptionAddress);
473 p->status_ = running;
479 case EXCEPTION_ILLEGAL_INSTRUCTION:
480 //printf("Illegal instruction\n");
482 p->status_ = stopped;
483 if (p->handleTrapIfDueToRPC()) {
484 // handleTrapIfDueToRPC calls continueProc()
487 p->status_ = running;
489 ContinueDebugEvent(debugEv.dwProcessId, debugEv.dwThreadId,
490 DBG_EXCEPTION_NOT_HANDLED);
492 case EXCEPTION_ACCESS_VIOLATION:
493 printf("Access violation exception, %d, addr = %x\n",
494 debugEv.u.Exception.ExceptionRecord.ExceptionFlags,
495 debugEv.u.Exception.ExceptionRecord.ExceptionAddress);
496 dumpMem(p, debugEv.u.Exception.ExceptionRecord.ExceptionAddress, 32);
497 // ContinueDebugEvent(debugEv.dwProcessId, debugEv.dwThreadId,
498 // DBG_EXCEPTION_NOT_HANDLED);
501 //printf("exeption %x, addr %x\n", exnCode,
502 // debugEv.u.Exception.ExceptionRecord.ExceptionAddress);
503 ContinueDebugEvent(debugEv.dwProcessId, debugEv.dwThreadId,
504 DBG_EXCEPTION_NOT_HANDLED);
509 case CREATE_THREAD_DEBUG_EVENT: {
510 //printf("create thread, tid = %d\n", debugEv.dwThreadId);
511 assert(p->threads.size() > 0); // main thread should be already defined
512 pdThread *t = new pdThread(p, debugEv.dwThreadId,
513 debugEv.u.CreateThread.hThread);
517 case CREATE_PROCESS_DEBUG_EVENT: {
518 CREATE_PROCESS_DEBUG_INFO info = debugEv.u.CreateProcessInfo;
519 //printf("CREATE_PROCESS event: %d\n", debugEv.dwProcessId);
520 p = findProcess(debugEv.dwProcessId);
522 //fprintf(stderr,"create process: base = %x\n", info.lpBaseOfImage);
523 if (p->threads.size() == 0) {
524 // define the main thread
525 p->threads += new pdThread(p);
527 p->threads[0]->update_handle(debugEv.dwThreadId,
528 debugEv.u.CreateProcessInfo.hThread);
533 case EXIT_THREAD_DEBUG_EVENT: {
534 //printf("exit thread, tid = %d\n", debugEv.dwThreadId);
535 unsigned nThreads = p->threads.size();
536 // start from one to skip main thread
537 for (unsigned u = 1; u < nThreads; u++) {
538 if (p->threads[u]->get_tid() == debugEv.dwThreadId) {
539 delete p->threads[u];
540 p->threads[u] = p->threads[nThreads-1];
541 p->threads.resize(nThreads-1);
547 case EXIT_PROCESS_DEBUG_EVENT:
548 p = findProcess(debugEv.dwProcessId);
550 //printf("process %d exited\n", p->getPid());
551 handleProcessExit(p, debugEv.u.ExitProcess.dwExitCode);
553 #ifdef BPATCH_LIBRARY
554 *status = SIGEM_EXITED;
559 case LOAD_DLL_DEBUG_EVENT: {
560 //printf("load dll: hFile=%x, base=%x, debugOff=%x, debugSz=%d lpname=%x, %d\n",
561 // debugEv.u.LoadDll.hFile, debugEv.u.LoadDll.lpBaseOfDll,
562 // debugEv.u.LoadDll.dwDebugInfoFileOffset,
563 // debugEv.u.LoadDll.nDebugInfoSize,
564 // debugEv.u.LoadDll.lpImageName,
565 // /*debugEv.u.LoadDll.fUnicode*/
566 // GetFileSize(debugEv.u.LoadDll.hFile,NULL));
568 // We are currently not handling dynamic libraries loaded after the
569 // application starts.
570 if (p->isBootstrappedYet())
573 if (!SymLoadModule((HANDLE)p->getProcFileDescriptor(),
574 debugEv.u.LoadDll.hFile,
576 printf("SymLoadModule failed, %x\n", GetLastError());
579 // set the proc handle for the process that is loading the library
580 // This is need when we use the imagehelp library to get the
581 // symbols for the dll.
582 // kludgeProcHandle = (HANDLE)p->getProcFileDescriptor();
584 void *addr = debugEv.u.LoadDll.lpImageName;
588 addr is a pointer to the image name (in the application address space)
589 There is a problem here, because this pointer can be null and it is
590 null in some cases (in particular, if we attach to a running process
591 it is always null). This means that it can be difficult to find
592 the name of an image.
594 Currently, if we can't find the name, we just ignore the
595 image. However, we need to at least be able to parse
596 kernel32.dll, because this library contains some very
597 important functions, including LoadLibrary, which we
598 need to call to load libdyninstRT.dll. We use the following
599 kludge to find if a library is kernel32.dll: the function
600 klugde_isKernel32Dll open a handle to kernel32.dll. We then
601 find if the handle we get from the LOAD_DLL_DEBUG_EVENT
602 is for the same file.
605 p->readDataSpace_(addr, 4, &ptr);
606 //printf("ptr = %x\n", ptr);
607 char buffer[MAX_PATH];
610 if (debugEv.u.LoadDll.fUnicode) {
611 unsigned short wbuffer[128];
612 p->readDataSpace_((void *)ptr, 128*sizeof(short), wbuffer);
613 WideCharToMultiByte(CP_ACP, 0, wbuffer, 128,
614 buffer, 128, NULL, NULL);
616 p->readDataSpace_((void *)ptr, 128, buffer);
618 //printf("Dll name: %s, base = %x\n", buffer, debugEv.u.LoadDll.lpBaseOfDll);
620 else if (kludge_isKernel32Dll(debugEv.u.LoadDll.hFile, kernel32Path)) {
621 assert(kernel32Path.length() > 0);
622 assert(kernel32Path.length() < sizeof(buffer));
623 strcpy(buffer, kernel32Path.string_of());
627 new shared_object(string(buffer), 0, false, true, true, 0);
629 p->dyn->sharedObjects += so;
630 if (!p->shared_objects) {
631 p->shared_objects = new vector<shared_object *>;
633 *(p->shared_objects) += so;
634 #ifndef BPATCH_LIBRARY
635 tp->resourceBatchMode(true);
637 p->addASharedObject(*so);
638 #ifndef BPATCH_LIBRARY
639 tp->resourceBatchMode(false);
641 p->setDynamicLinking();
645 case UNLOAD_DLL_DEBUG_EVENT:
647 //printf("unload dll\n");
649 case OUTPUT_DEBUG_STRING_EVENT:
650 //printf("output debug string\n");
653 //printf("rip event\n");
657 //printf("unknown debug event\n");
661 if (!ContinueDebugEvent(debugEv.dwProcessId, debugEv.dwThreadId,
663 printf("ContinueDebugEvent failed\n");
664 printSysError(GetLastError());
667 #ifdef BPATCH_LIBRARY
669 return debugEv.dwProcessId;
678 // already setup on this FD.
679 // disconnect from controlling terminal
680 void OS::osDisconnect(void) {
682 int ttyfd = open ("/dev/tty", O_RDONLY);
683 ioctl (ttyfd, TIOCNOTTY, NULL);
689 bool process::attach() {
690 if (createdViaAttach) {
691 if (!DebugActiveProcess(getPid())) {
692 //printf("Error: DebugActiveProcess failed\n");
696 proc_fd = (int)OpenProcess(PROCESS_ALL_ACCESS, false, getPid());
697 if (proc_fd == NULL) {
698 //printf("Error: OpenProcess failed\n");
702 void initSymbols(HANDLE procH, const string file, const string dir);
703 initSymbols((HANDLE)proc_fd, symbols->file(), "");
704 if (createdViaAttach) {
706 //void initSymbols(HANDLE procH, const string file, const string dir);
707 //initSymbols((HANDLE)proc_fd, symbols->file(), "");
712 /* continue a process that is stopped */
713 bool process::continueProc_() {
715 changePC(currentPC_);
718 for (unsigned u = 0; u < threads.size(); u++) {
719 unsigned count = ResumeThread((HANDLE)threads[u]->get_handle());
720 if (count == 0xFFFFFFFF) {
721 printSysError(GetLastError());
729 #ifdef BPATCH_LIBRARY
731 terminate execution of a process
733 bool process::terminateProc_()
736 handleProcessExit(this, -1);
743 pause a process that is running
745 bool process::pause_() {
746 for (unsigned u = 0; u < threads.size(); u++) {
747 unsigned count = SuspendThread((HANDLE)threads[u]->get_handle());
748 if (count == 0xFFFFFFFF) {
749 printf("pause_: %d\n", threads[u]->get_tid());
750 printSysError(GetLastError());
758 close the file descriptor for the file associated with a process
760 bool process::detach_() {
765 #ifdef BPATCH_LIBRARY
767 detach from thr process, continuing its execution if the parameter "cont"
770 bool process::API_detach_(const bool cont)
772 // XXX Not yet implemented
779 bool process::dumpCore_(const string) {
783 bool process::writeTextWord_(caddr_t inTraced, int data) {
784 return writeDataSpace_(inTraced, sizeof(int), (caddr_t) &data);
787 bool process::writeTextSpace_(void *inTraced, int amount, const void *inSelf) {
788 return writeDataSpace_(inTraced, amount, inSelf);
791 #ifdef BPATCH_SET_MUTATIONS_ACTIVE
792 bool process::readTextSpace_(void *inTraced, int amount, const void *inSelf) {
793 return readDataSpace_(inTraced, amount, (void *)inSelf);
797 bool process::writeDataSpace_(void *inTraced, int amount, const void *inSelf) {
800 //printf("write %d bytes, %x\n", amount, inTraced);
802 bool res = WriteProcessMemory((HANDLE)proc_fd, (LPVOID)inTraced,
803 (LPVOID)inSelf, (DWORD)amount, &nbytes);
806 FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(),
807 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
809 printf(">>> %d %s\n", GetLastError(), buf);
810 printf("WriteProcessMem: %d bytes, addr = %x, %d\n",
811 amount, inTraced, res);
813 return res && (nbytes == amount);
817 bool process::readDataSpace_(const void *inTraced, int amount, void *inSelf) {
819 bool res = ReadProcessMemory((HANDLE)proc_fd, (LPVOID)inTraced,
820 (LPVOID)inSelf, (DWORD)amount, &nbytes);
823 FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(),
824 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
826 printf(">>> %d %s\n", GetLastError(), buf);
827 printf("ReadProcessMem: %d bytes, addr = %x, %d\n",
828 amount, inTraced, res);
830 return res && (nbytes == amount);
834 bool process::loopUntilStopped() { assert(0); return false; }
836 float OS::compute_rusage_cpu() { return 0.0; }
837 float OS::compute_rusage_sys() { return 0.0; }
838 float OS::compute_rusage_min() { return 0.0; }
839 float OS::compute_rusage_maj() { return 0.0; }
840 float OS::compute_rusage_swap() { return 0.0; }
841 float OS::compute_rusage_io_in() { return 0.0; }
842 float OS::compute_rusage_io_out() { return 0.0; }
843 float OS::compute_rusage_msg_send() { return 0.0; }
844 float OS::compute_rusage_msg_recv() { return 0.0; }
845 float OS::compute_rusage_sigs() { return 0.0; }
846 float OS::compute_rusage_vol_cs() { return 0.0; }
847 float OS::compute_rusage_inv_cs() { return 0.0; }
850 int getNumberOfCPUs() {
852 GetSystemInfo(&info);
853 return info.dwNumberOfProcessors;
857 bool process::getActiveFrame(int *fp, int *pc) {
860 // we must set ContextFlags to indicate the registers we want returned,
861 // in this case, the control registers.
862 // The values for ContextFlags are defined in winnt.h
863 cont.ContextFlags = CONTEXT_CONTROL;
864 if (GetThreadContext((HANDLE)threads[0]->get_handle(), &cont)) {
869 printSysError(GetLastError());
874 bool process::readDataFromFrame(int currentFP, int *fp, int *rtn, bool ) {
882 // for the x86, the frame-pointer (EBP) points to the previous frame-pointer,
883 // and the saved return address is in EBP-4.
886 if (readDataSpace((caddr_t) (currentFP),
887 sizeof(int)*2, (caddr_t) &addrs, true)) {
888 // this is the previous frame pointer
893 // if pc==0, then we are in the outermost frame and we should stop. We
894 // do this by making fp=0.
896 if ( (addrs.rtn == 0) || !isValidAddress(this,(Address) addrs.rtn) ) {
908 void *process::getRegisters() {
909 CONTEXT *cont = new CONTEXT;
912 // we must set ContextFlags to indicate the registers we want returned,
913 // in this case, the control registers.
914 // The values for ContextFlags are defined in winnt.h
915 cont->ContextFlags = CONTEXT_FULL;
916 if (!GetThreadContext((HANDLE)threads[0]->get_handle(), cont)) {
923 bool process::changePC(unsigned addr, const void *savedRegs) {
924 assert(status_ == stopped);
926 CONTEXT cont = *(CONTEXT *)savedRegs;
928 if (!SetThreadContext((HANDLE)threads[0]->get_handle(), &cont)) {
929 printf("SethreadContext failed\n");
935 bool process::changePC(unsigned addr) {
936 assert(status_ == stopped || status_ == neonatal);
938 cont.ContextFlags = CONTEXT_FULL;
939 if (!GetThreadContext((HANDLE)threads[0]->get_handle(), &cont)) {
940 printf("GetThreadContext failed\n");
944 if (!SetThreadContext((HANDLE)threads[0]->get_handle(), &cont)) {
945 printf("SethreadContext failed\n");
951 bool process::restoreRegisters(void *buffer) {
952 if (!SetThreadContext((HANDLE)threads[0]->get_handle(), (CONTEXT *)buffer)) {
953 //printf("SetThreadContext failed\n");
959 bool process::isRunning_() const {
961 printf("process::isRunning_() returning true\n");
966 string process::tryToFindExecutable(const string& iprogpath, int pid) {
970 bool process::set_breakpoint_for_syscall_completion() {
971 /* Can assume: (1) process is paused and (2) in a system call.
972 We want to set a TRAP for the syscall exit, and do the
973 inferiorRPC at that time. We'll use /proc PIOCSEXIT.
974 Returns true iff breakpoint was successfully set. */
976 // This is never called on Windows NT
981 unsigned process::read_inferiorRPC_result_register(reg) {
982 CONTEXT *cont = new CONTEXT;
985 // we must set ContextFlags to indicate the registers we want returned,
986 // in this case, the control registers.
987 // The values for ContextFlags are defined in winnt.h
988 cont->ContextFlags = CONTEXT_FULL;
989 if (!GetThreadContext((HANDLE)threads[0]->get_handle(), cont)) {
990 //printf("GetThreadContext failed\n");
997 bool process::executingSystemCall() {
1003 bool process::needToAddALeafFrame(Frame , Address &) {
1008 void initSymbols(HANDLE procH, const string file, const string dir) {
1010 char sysRootDir[MAX_PATH+1];
1011 if (GetSystemDirectory(sysRootDir, MAX_PATH) == 0)
1013 string sysSymsDir = string(sysRootDir) + "\\..\\symbols";
1015 searchPath = dir + ";";
1016 searchPath = searchPath + sysSymsDir + ";" + sysSymsDir + "\\dll";
1017 if (!SymInitialize(procH, (char *)searchPath.string_of(), 0)) {
1018 fprintf(stderr,"SymInitialize failed, %x\n", GetLastError()); fflush(stderr);
1021 if (!SymLoadModule(procH, NULL, (char *)file.string_of(), NULL, 0, 0)) {
1022 printf("SymLoadModule failed for \"%s\", %x\n",
1023 file.string_of(), GetLastError());
1032 /*****************************************************************************
1033 * forkNewProcess: starts a new process, setting up trace and io links between
1034 * the new process and the daemon
1035 * Returns true if succesfull.
1038 * file: file to execute
1039 * dir: working directory for the new process
1040 * argv: arguments to new process
1041 * envp: environment **** not in use
1042 * inputFile: where to redirect standard input
1043 * outputFile: where to redirect standard output
1044 * traceLink: handle or file descriptor of trace link (read only)
1045 * ioLink: handle or file descriptor of io link (read only)
1046 * pid: process id of new process
1047 * tid: thread id for main thread (needed by WindowsNT)
1048 * procHandle: handle for new process (needed by WindowsNT)
1049 * thrHandle: handle for main thread (needed by WindowsNT)
1050 ****************************************************************************/
1051 bool forkNewProcess(string file, string dir, vector<string> argv,
1052 vector<string>envp, string inputFile, string outputFile,
1053 int &traceLink, int &ioLink,
1055 int &procHandle, int &thrHandle) {
1056 #ifndef BPATCH_LIBRARY
1062 // security attributes to make handles inherited
1063 SECURITY_ATTRIBUTES sa;
1064 sa.nLength = sizeof(SECURITY_ATTRIBUTES);
1065 sa.bInheritHandle = true;
1066 sa.lpSecurityDescriptor = NULL;
1068 // create trace pipe
1069 if (!CreatePipe(&rTracePipe, &wTracePipe, &sa, 0)) {
1070 string msg = string("Unable to create trace pipe for program '") + File +
1071 string("': ") + string(sys_errlist[errno]);
1072 showErrorCallback(68, msg);
1077 // ioPipe is used to redirect the child's stdout & stderr to a pipe which is in
1078 // turn read by the parent via the process->ioLink socket.
1079 if (!CreatePipe(&rIoPipe, &wIoPipe, &sa, 0)) {
1080 string msg = string("Unable to create IO pipe for program '") + File +
1081 string("': ") + string(sys_errlist[errno]);
1082 showErrorCallback(68, msg);
1085 printf("tracepipe = %d\n", (unsigned)wTracePipe);
1086 // enter trace and IO pipes in child's environment
1087 SetEnvironmentVariable("PARADYN_TRACE_PIPE",
1088 string((unsigned)wTracePipe).string_of());
1089 SetEnvironmentVariable("PARADYN_IO_PIPE",
1090 string((unsigned)wIoPipe).string_of());
1092 // extern int traceSocket;
1093 // SetEnvironmentVariable("PARADYND_TRACE_SOCKET", string((unsigned)traceSocket).string_of());
1094 #endif /* BPATCH_LIBRARY */
1096 // create the child process
1099 for (unsigned ai=0; ai<argv.size(); ai++) {
1105 memset(&stinfo, 0, sizeof(STARTUPINFO));
1106 stinfo.cb = sizeof(STARTUPINFO);
1108 PROCESS_INFORMATION procInfo;
1109 if (CreateProcess(file.string_of(), (char *)args.string_of(),
1111 DEBUG_PROCESS /* | CREATE_SUSPENDED */,
1112 NULL, dir == "" ? NULL : dir.string_of(),
1113 &stinfo, &procInfo)) {
1114 procHandle = (Word)procInfo.hProcess;
1115 thrHandle = (Word)procInfo.hThread;
1116 pid = (Word)procInfo.dwProcessId;
1117 tid = (Word)procInfo.dwThreadId;
1119 traceLink = (Word)rTracePipe;
1120 ioLink = (Word)rIoPipe;
1124 // CloseHandle(wTracePipe);
1125 // CloseHandle(wIoPipe);
1126 //initSymbols((HANDLE)procHandle, file, dir);
1130 #ifndef BPATCH_LIBRARY
1131 CloseHandle(rTracePipe);
1132 CloseHandle(wTracePipe);
1133 CloseHandle(rIoPipe);
1134 CloseHandle(wIoPipe);
1135 #endif /* BPATCH_LIBRARY */
1137 // Output failure message
1141 FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
1144 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
1149 char *errorLine = (char *)malloc(strlen((char *)lpMsgBuf) +
1150 file.length() + 64);
1151 if (errorLine != NULL) {
1152 sprintf(errorLine, "Unable to start %s: %s\n", file.string_of(),
1155 showErrorCallback(68, (const char *) errorLine);
1160 // Free the buffer returned by FormatMsg
1161 LocalFree(lpMsgBuf);
1163 char errorLine[512];
1164 sprintf(errorLine, "Unable to start %s: unknown error\n",
1167 showErrorCallback(68, (const char *) errorLine);
1173 char *cplus_demangle(char *c, int) {
1175 if (UnDecorateSymbolName(c, buf, 1000, UNDNAME_NAME_ONLY)) {
1176 //printf("Undecorate: %s = %s\n", c, buf);
1178 // many symbols have a name like foo@4, we must remove the @4
1179 // just searching for an @ is not enough,
1180 // as it may occur on other positions. We search for the last one
1181 // and check that it is followed only by digits.
1182 char *p = strrchr(buf, '@');
1185 strtoul(p+1, &q, 10);
1186 if (q > p+1 && *q == '\0') {
1195 bool OS::osKill(int pid) {
1197 HANDLE h = OpenProcess(PROCESS_ALL_ACCESS, false, pid);
1201 res = TerminateProcess(h,0);