From 98132526f7524958f1d73c3d3f9f4628fa7c7a5f Mon Sep 17 00:00:00 2001 From: buck Date: Fri, 6 Mar 1998 21:32:11 +0000 Subject: [PATCH] Added several calls to API (waitForStatusChange, BPatch_variableExpr member functions getBaseAddr and readValue, writeValue with an extra length parameter). Fixed several bugs in x86 instrumentation code related to parsing jump tables. Made changes to work with gcc-built programs on NT. --- dyninstAPI/h/BPatch.h | 5 + dyninstAPI/h/BPatch_point.h | 1 + dyninstAPI/h/BPatch_snippet.h | 9 +- dyninstAPI/h/BPatch_thread.h | 18 ++- dyninstAPI/i386-unknown-nt4.0/DEPENDS | 3 +- dyninstAPI/i386-unknown-nt4.0/Makefile | 16 ++- dyninstAPI/make.module.tmpl | 17 +-- dyninstAPI/nmake.module.tmpl | 7 +- dyninstAPI/src/BPatch.C | 180 ++++++++++++++++++++++-------- dyninstAPI/src/BPatch_point.C | 20 ++++ dyninstAPI/src/BPatch_snippet.C | 66 ++++++++++- dyninstAPI/src/BPatch_thread.C | 127 ++++++++++++++++++--- dyninstAPI/src/BPatch_type.h | 2 + dyninstAPI/src/aix.C | 29 ++++- dyninstAPI/src/dummy.C | 20 +--- dyninstAPI/src/inst-x86.C | 106 +++++++++++++++++- dyninstAPI/src/instPoint-x86.h | 5 + dyninstAPI/src/pdwinnt.C | 16 ++- dyninstAPI/src/process.C | 2 +- dyninstAPI/src/process.h | 8 ++ dyninstAPI/src/solaris.C | 31 +++++ dyninstAPI/src/sunos.C | 33 +++++- dyninstAPI/src/templates-nt.C | 10 +- dyninstAPI/src/templates0.C | 6 + dyninstAPI/src/templates1.C | 2 + dyninstAPI/src/unix.C | 10 +- dyninstAPI/tests/src/test1.C | 8 +- dyninstAPI/tests/src/test2.C | 36 +++++- dyninstAPI/tests/src/test_util.C | 6 +- dyninstAPI_RT/i386-unknown-nt4.0/Makefile | 6 +- 30 files changed, 676 insertions(+), 129 deletions(-) diff --git a/dyninstAPI/h/BPatch.h b/dyninstAPI/h/BPatch.h index 30c84a0..bbba50a 100644 --- a/dyninstAPI/h/BPatch.h +++ b/dyninstAPI/h/BPatch.h @@ -59,7 +59,9 @@ typedef void (*BPatchErrorCallback)(BPatchErrorLevel severity, const char **params); class BPatch { + friend class BPatch_thread; friend bool pollForStatusChange(); + friend bool waitForStatusChange(); BPatch_libInfo *info; @@ -69,6 +71,8 @@ class BPatch { BPatch_thread *pidToThread(int pid, bool *exists = NULL); + bool getThreadEvent(bool block); + bool havePendingEvent(); public: static BPatch *bpatch; @@ -104,5 +108,6 @@ public: }; extern bool pollForStatusChange(); +extern bool waitForStatusChange(); #endif /* _BPatch_h_ */ diff --git a/dyninstAPI/h/BPatch_point.h b/dyninstAPI/h/BPatch_point.h index bbbcd97..f96aea2 100644 --- a/dyninstAPI/h/BPatch_point.h +++ b/dyninstAPI/h/BPatch_point.h @@ -59,6 +59,7 @@ class BPatch_point { proc(_proc), point(_point) {}; public: BPatch_function *getCalledFunction(); + bool usesTrap_NP(); }; #endif /* _BPatch_point_h_ */ diff --git a/dyninstAPI/h/BPatch_snippet.h b/dyninstAPI/h/BPatch_snippet.h index 7ea8fc7..f0a808d 100644 --- a/dyninstAPI/h/BPatch_snippet.h +++ b/dyninstAPI/h/BPatch_snippet.h @@ -184,16 +184,21 @@ public: class BPatch_variableExpr : public BPatch_snippet { process *proc; void *address; + int size; public: // The following functions are for internal use by the library only: BPatch_variableExpr(process *in_process, void *in_address, const BPatch_type *type); - - void *getAddress() const { return address; } + BPatch_variableExpr(process *in_process, void *in_address, + int in_size); // Public functions for use by users of the library: void readValue(void *dst); + void readValue(void *dst, int len); void writeValue(const void *src); + void writeValue(const void *src, int len); + + void *getBaseAddr() const { return address; } }; #endif /* _BPatch_snippet_h_ */ diff --git a/dyninstAPI/h/BPatch_thread.h b/dyninstAPI/h/BPatch_thread.h index 9910bb3..44ac7b1 100644 --- a/dyninstAPI/h/BPatch_thread.h +++ b/dyninstAPI/h/BPatch_thread.h @@ -97,7 +97,6 @@ public: void add(instInstance *pointInstance); }; - /* * Represents a thread of execution. */ @@ -111,6 +110,22 @@ class BPatch_thread { bool mutationsActive; bool createdViaAttach; bool detached; + + bool unreportedStop; + bool unreportedTermination; + + void setUnreportedStop(bool new_value) + { unreportedStop = new_value; } + void setUnreportedTermination(bool new_value) + { unreportedTermination = new_value; } + + bool pendingUnreportedStop() + { return unreportedStop; } + bool pendingUnreportedTermination() + { return unreportedTermination; } + + bool statusIsStopped(); + bool statusIsTerminated(); protected: BPatch_thread(char *path, char *argv[], char *envp[] = NULL); BPatch_thread(char *path, int pid); @@ -133,6 +148,7 @@ public: void detach(bool cont); bool dumpCore(const char *file, bool terminate); + bool dumpImage(const char *file); BPatch_variableExpr *malloc(int n); BPatch_variableExpr *malloc(const BPatch_type &type); diff --git a/dyninstAPI/i386-unknown-nt4.0/DEPENDS b/dyninstAPI/i386-unknown-nt4.0/DEPENDS index e9383cd..a502dae 100644 --- a/dyninstAPI/i386-unknown-nt4.0/DEPENDS +++ b/dyninstAPI/i386-unknown-nt4.0/DEPENDS @@ -197,7 +197,8 @@ symtab.obj: ../src/symtab.C ../../dyninstAPI/src/symtab.h \ ../../dyninstAPI/src/arch.h ../../dyninstAPI/src/arch-sparc.h \ ../../dyninstAPI/src/util.h ../../dyninstAPI/src/inst.h \ ../../dyninstAPI/src/ast.h ../../dyninstAPI/src/dyninstP.h \ - ../../util/h/Timer.h ../../paradynd/src/showerror.h + ../../util/h/Timer.h ../../paradynd/src/showerror.h \ + ../../util/h/Object-nt.h util.obj: ../src/util.C ../../util/h/headers.h \ ../../util/h/ntHeaders.h ../../dyninstAPI_RT/h/rtinst.h \ ../../dyninstAPI/src/util.h ../../util/h/String.h \ diff --git a/dyninstAPI/i386-unknown-nt4.0/Makefile b/dyninstAPI/i386-unknown-nt4.0/Makefile index 4f72e53..a7c26ce 100755 --- a/dyninstAPI/i386-unknown-nt4.0/Makefile +++ b/dyninstAPI/i386-unknown-nt4.0/Makefile @@ -1,5 +1,16 @@ # # $Log: Makefile,v $ +# Revision 1.2 1998/03/06 21:32:38 buck +# Added several calls to API (waitForStatusChange, BPatch_variableExpr +# member functions getBaseAddr and readValue, writeValue with an extra +# length parameter). +# Fixed several bugs in x86 instrumentation code related to parsing jump +# tables. +# Made changes to work with gcc-built programs on NT. +# +# Revision 1.1.1.1 1997/08/18 20:10:07 buck +# Updated Maryland repository with the latest changes from Wisconsin. +# # Revision 1.1 1997/08/18 01:34:18 buck # Ported the Dyninst API to Windows NT. # @@ -13,9 +24,6 @@ # # Define any symbols needed to invoke configuration changes in make.config -#USES_LIBERTY = true -#USES_PVM = true - # Include standard make configuration stuff that applies to everything # in the paradyn tree. @@ -34,7 +42,7 @@ OBJS = pdwinnt.obj \ arch-x86.obj -CXXFLAGS = $(CXXFLAGS) -DNO_MDL_PRINT +CXXFLAGS = $(CXXFLAGS) -DNO_MDL_PRINT # Include the module-specific Makefile, which defines everything about # the module that is common across architectures. diff --git a/dyninstAPI/make.module.tmpl b/dyninstAPI/make.module.tmpl index 122a934..690d340 100644 --- a/dyninstAPI/make.module.tmpl +++ b/dyninstAPI/make.module.tmpl @@ -5,9 +5,12 @@ # # -CFLAGS += $(TCLFRIENDLYWARNINGS) -DBPATCH_LIBRARY -UMT_THREAD -DBPATCH_SET_MUTATIONS_ACTIVE -CXXFLAGS += $(TCLFRIENDLYWARNINGS) -DBPATCH_LIBRARY -UMT_THREAD -DBPATCH_SET_MUTATIONS_ACTIVE -TFLAGS += $(TCLFRIENDLYWARNINGS) +DEFINES += -UMT_THREAD \ + -DBPATCH_LIBRARY -DBPATCH_SET_MUTATIONS_ACTIVE + +CFLAGS += $(TCLFRIENDLYWARNINGS) $(DEFINES) +CXXFLAGS += $(TCLFRIENDLYWARNINGS) $(DEFINES) +TFLAGS += $(TCLFRIENDLYWARNINGS) $(DEFINES) TARGET = libdyninstAPI.a @@ -34,7 +37,7 @@ SRCS += ../src/BPatch.C \ ../src/sharedobject.C \ ../src/templates0.C \ ../src/templates05.C \ - ../src/templates1.C \ + ../src/templates1.C ifdef USES_PVM SRCS += ../../paradynd/src/pvm_support.C \ @@ -73,10 +76,10 @@ IFLAGS += -I../$(PLATFORM) -I../src -I../h -I../../paradynd/src all: $(TARGET) templates0.o: ../src/templates0.C - $(CXX) -DBPATCH_LIBRARY $(TFLAGS) -c ../src/templates0.C + $(CXX) $(TFLAGS) -c ../src/templates0.C templates05.o: ../src/templates05.C - $(CXX) -DBPATCH_LIBRARY $(TFLAGS) -c ../src/templates05.C + $(CXX) $(TFLAGS) -c ../src/templates05.C templates1.o: ../src/templates1.C - $(CXX) -DBPATCH_LIBRARY $(TFLAGS) -c ../src/templates1.C + $(CXX) $(TFLAGS) -c ../src/templates1.C diff --git a/dyninstAPI/nmake.module.tmpl b/dyninstAPI/nmake.module.tmpl index 91737bc..367ae10 100644 --- a/dyninstAPI/nmake.module.tmpl +++ b/dyninstAPI/nmake.module.tmpl @@ -3,13 +3,14 @@ # intended to be a useful Makefile in isolation; instead, it should be # included from within an architecture-specific Makefile. # -# $Id: nmake.module.tmpl,v 1.2 1997/11/05 02:32:43 wylie Exp $ +# $Id: nmake.module.tmpl,v 1.3 1998/03/06 21:32:12 buck Exp $ # TARGET = libdyninstAPI.lib -CFLAGS = $(CFLAGS) -DBPATCH_LIBRARY -DBPATCH_SET_MUTATIONS_ACTIVE -CXXFLAGS = $(CXXFLAGS) -DBPATCH_LIBRARY -DBPATCH_SET_MUTATIONS_ACTIVE +DEFINES = -DBPATCH_LIBRARY -DBPATCH_SET_MUTATIONS_ACTIVE +CFLAGS = $(CFLAGS) $(DEFINES) +CXXFLAGS = $(CXXFLAGS) $(DEFINES) IFLAGS = $(IFLAGS) -I../h diff --git a/dyninstAPI/src/BPatch.C b/dyninstAPI/src/BPatch.C index 9280668..5917647 100644 --- a/dyninstAPI/src/BPatch.C +++ b/dyninstAPI/src/BPatch.C @@ -277,54 +277,6 @@ BPatch_Vector *BPatch::getThreads() /* - * pollForStatusChange - * - * Checks for changes in the state of any child process, and returns true if - * it discovers any such changes. Also updates the process object - * representing each process for which a change is detected. - * - * This function is declared as a friend of BPatch_thread so that it can use - * the BPatch_thread::pidToThread call and so that it can set the lastSignal - * member of a BPatch_thread object. - */ -bool pollForStatusChange() -{ - assert(BPatch::bpatch != NULL); - - bool result = false; - int pid, status; - - while ((pid = process::waitProcs(&status)) > 0) { - // There's been a change in a child process - result = true; - assert(BPatch::bpatch != NULL); - bool exists; - BPatch_thread *thread = BPatch::bpatch->pidToThread(pid, &exists); - if (thread == NULL) { - if (exists) { - if (WIFSIGNALED(status) || WIFEXITED(status)) - BPatch::bpatch->unRegisterThread(pid); - } else { - fprintf(stderr, "Warning - wait returned status of an unknown process (%d)\n", pid); - } - } - if (thread != NULL) { - if (WIFSTOPPED(status)) - thread->lastSignal = WSTOPSIG(status); - else if (WIFSIGNALED(status)) - thread->lastSignal = WTERMSIG(status); - else if (WIFEXITED(status)) - thread->lastSignal = 0; /* XXX Make into some constant */ - } -#ifndef i386_unknown_nt4_0 - handleSigChild(pid, status); -#endif - } - return result; -} - - -/* * BPatch::registerProvisionalThread * * Register a new process that is not yet associated with a thread. @@ -420,3 +372,135 @@ BPatch_thread *BPatch::attachProcess(char *path, int pid) return ret; } + + +/* + * getThreadEvent + * + * Checks for changes in any child process, and optionally blocks until such a + * change has occurred. Also updates the process object representing each + * process for which a change is detected. The return value is true if a + * change was detected, otherwise it is false. + * + * block Set this parameter to true to block waiting for a change, + * set to false to poll and return immediately, whether or not a + * change occurred. + */ +bool BPatch::getThreadEvent(bool block) +{ + bool result = false; + int pid, status; + + while ((pid = process::waitProcs(&status, block)) > 0) { + // There's been a change in a child process + result = true; + // Since we found something, we don't want to block anymore + block = false; + + bool exists; + BPatch_thread *thread = pidToThread(pid, &exists); + if (thread == NULL) { + if (exists) { + if (WIFSIGNALED(status) || WIFEXITED(status)) + unRegisterThread(pid); + } else { + fprintf(stderr, "Warning - wait returned status of an unknown process (%d)\n", pid); + } + } + if (thread != NULL) { + if (WIFSTOPPED(status)) { + thread->lastSignal = WSTOPSIG(status); + thread->setUnreportedStop(true); + } else if (WIFSIGNALED(status)) { + thread->lastSignal = WTERMSIG(status); + thread->setUnreportedTermination(true); + } else if (WIFEXITED(status)) { + thread->lastSignal = 0; /* XXX Make into some constant */ + thread->setUnreportedTermination(true); + } + } +#ifndef i386_unknown_nt4_0 + handleSigChild(pid, status); +#endif + } + + return result; +} + + +/* + * havePendingEvent + * + * Returns true if any thread has stopped or terminated and that fact hasn't + * been reported to the user of the library. Otherwise, returns false. + */ +bool BPatch::havePendingEvent() +{ +#ifdef i386_unknown_nt4_0 + // On NT, we need to poll for events as often as possible, so that we can + // handle traps. + if (getThreadEvent(false)) + return true; +#endif + + // For now, we'll do it by iterating over the threads and checking them, + // and we'll change it to something more efficient later on. + dictionary_hash_iter ti(info->threadsByPid); + + int pid; + BPatch_thread *thread; + + while (ti.next(pid, thread)) { + if (thread != NULL && + (thread->pendingUnreportedStop() || + thread->pendingUnreportedTermination())) { + return true; + } + } + + return false; +} + + +/* + * pollForStatusChange + * + * Checks for unreported changes to the status of any child process, and + * returns true if any are detected. Returns false otherwise. + * + * This function is declared as a friend of BPatch_thread so that it can use + * the BPatch_thread::getThreadEvent call to check for status changes. + */ +bool pollForStatusChange() +{ + // First, check if there are any unreported changes that have already been + // detected. + assert(BPatch::bpatch); + if (BPatch::bpatch->havePendingEvent()) + return true; + + // No changes were previously detected, so check for new changes + return BPatch::bpatch->getThreadEvent(false); +} + + +/* + * waitForStatusChange + * + * Blocks waiting for a change to occur in the running status of a child + * process. Returns true upon success, false upon failure. + * + * This function is declared as a friend of BPatch_thread so that it can use + * the BPatch_thread::getThreadEvent call to check for status changes. + */ +bool waitForStatusChange() +{ + // First, check if there are any unreported changes that have already been + // detected. + assert(BPatch::bpatch); + if (BPatch::bpatch->havePendingEvent()) + return true; + + // No changes were previously detected, so wait for a new change + return BPatch::bpatch->getThreadEvent(true); +} diff --git a/dyninstAPI/src/BPatch_point.C b/dyninstAPI/src/BPatch_point.C index 5519ce8..4567fa1 100644 --- a/dyninstAPI/src/BPatch_point.C +++ b/dyninstAPI/src/BPatch_point.C @@ -79,3 +79,23 @@ BPatch_function *BPatch_point::getCalledFunction() else return NULL; } + + +/* + * usesTrap_NP + * + * Returns true if this point is or would be instrumented with a trap, rather + * than a jump to the base tramp, false otherwise. On platforms that do not + * use traps (everything other than x86), it always returns false; + */ +bool BPatch_point::usesTrap_NP() +{ +#if defined(i386_unknown_solaris2_5) || defined(i386_unknown_nt4_0) + assert(point); + assert(proc); + + return point->usesTrap(proc); +#else + return false; +#endif +} diff --git a/dyninstAPI/src/BPatch_snippet.C b/dyninstAPI/src/BPatch_snippet.C index aa2670d..66b0345 100644 --- a/dyninstAPI/src/BPatch_snippet.C +++ b/dyninstAPI/src/BPatch_snippet.C @@ -398,9 +398,12 @@ BPatch_sequence::BPatch_sequence(const BPatch_Vector &items) /* * BPatch_variableExpr::BPatch_variableExpr * - * Construct a snippet representing a variable at the given address. + * Construct a snippet representing a variable of the given type at the given + * address. * + * in_process The process that the variable resides in. * in_address The address of the variable in the inferior's address space. + * type The type of the variable. */ BPatch_variableExpr::BPatch_variableExpr(process *in_process, void *in_address, @@ -413,6 +416,32 @@ BPatch_variableExpr::BPatch_variableExpr(process *in_process, ast->setTypeChecking(BPatch::bpatch->isTypeChecked()); ast->setType(type); + + size = type->getSize(); +} + + +/* + * BPatch_variableExpr::BPatch_variableExpr + * + * Construct a snippet representing an untyped variable of a given size at the + * given address. + * + * in_address The address of the variable in the inferior's address space. + */ +BPatch_variableExpr::BPatch_variableExpr(process *in_process, + void *in_address, + int in_size) : + proc(in_process), address(in_address) +{ + ast = new AstNode(AstNode::DataAddr, address); + + assert(BPatch::bpatch != NULL); + ast->setTypeChecking(BPatch::bpatch->isTypeChecked()); + + ast->setType(BPatch::bpatch->type_Untyped); + + size = in_size; } @@ -426,7 +455,23 @@ BPatch_variableExpr::BPatch_variableExpr(process *in_process, */ void BPatch_variableExpr::readValue(void *dst) { - proc->readDataSpace(address, sizeof(int), dst, true); + proc->readDataSpace(address, size, dst, true); +} + + +/* + * BPatch_variableExpr::readValue + * + * Read the a given number of bytes starting at the base address of a variable + * in the a thread's address space. + * + * dst A pointer to a buffer in which to place the value of the + * variable. It is assumed to be the same size as the variable. + * len Number of bytes to read. + */ +void BPatch_variableExpr::readValue(void *dst, int len) +{ + proc->readDataSpace(address, len, dst, true); } @@ -440,7 +485,22 @@ void BPatch_variableExpr::readValue(void *dst) */ void BPatch_variableExpr::writeValue(const void *src) { - proc->writeDataSpace(address, sizeof(int), src); + proc->writeDataSpace(address, size, src); +} + + +/* + * BPatch_variableExpr::writeValue + * + * Write the a given number of bytes starting at the base address of a + * variable in the a thread's address space. + * + * dst A pointer to a buffer in which to place the value of the + * variable. It is assumed to be the same size as the variable. + */ +void BPatch_variableExpr::writeValue(const void *src, int len) +{ + proc->writeDataSpace(address, len, src); } diff --git a/dyninstAPI/src/BPatch_thread.C b/dyninstAPI/src/BPatch_thread.C index f734edb..bf00984 100644 --- a/dyninstAPI/src/BPatch_thread.C +++ b/dyninstAPI/src/BPatch_thread.C @@ -75,7 +75,8 @@ int BPatch_thread::getPid() */ BPatch_thread::BPatch_thread(char *path, char *argv[], char *envp[]) : lastSignal(-1), mutationsActive(true), createdViaAttach(false), - detached(false), proc(NULL), image(NULL) + detached(false), proc(NULL), image(NULL), + unreportedStop(false), unreportedTermination(false) { vector argv_vec; vector envp_vec; @@ -102,8 +103,8 @@ BPatch_thread::BPatch_thread(char *path, char *argv[], char *envp[]) image = new BPatch_image(proc); - while (!proc->isBootstrappedYet() && !isTerminated()) - pollForStatusChange(); + while (!proc->isBootstrappedYet() && !statusIsTerminated()) + BPatch::bpatch->getThreadEvent(false); } @@ -118,7 +119,8 @@ BPatch_thread::BPatch_thread(char *path, char *argv[], char *envp[]) */ BPatch_thread::BPatch_thread(char *path, int pid) : lastSignal(-1), mutationsActive(true), createdViaAttach(true), - detached(false), proc(NULL), image(NULL) + detached(false), proc(NULL), image(NULL), + unreportedStop(false), unreportedTermination(false) { if (!attachProcess(path, pid, 1, proc)) { // XXX Should do something more sensible @@ -132,8 +134,8 @@ BPatch_thread::BPatch_thread(char *path, int pid) image = new BPatch_image(proc); - while (!proc->isBootstrappedYet() && !isTerminated()) { - pollForStatusChange(); + while (!proc->isBootstrappedYet() && !statusIsTerminated()) { + BPatch::bpatch->getThreadEvent(false); proc->launchRPCifAppropriate(false, false); } } @@ -176,9 +178,19 @@ BPatch_thread::~BPatch_thread() */ bool BPatch_thread::stopExecution() { - pollForStatusChange(); + assert(BPatch::bpatch); + BPatch::bpatch->getThreadEvent(false); return proc->pause(); + + assert(BPatch::bpatch); + + while (!statusIsStopped()) + BPatch::bpatch->getThreadEvent(false); + + setUnreportedStop(false); + + return true; } @@ -189,16 +201,22 @@ bool BPatch_thread::stopExecution() */ bool BPatch_thread::continueExecution() { - pollForStatusChange(); + assert(BPatch::bpatch); + BPatch::bpatch->getThreadEvent(false); + + if (proc->continueProc()) { + setUnreportedStop(false); + return true; + } - return proc->continueProc(); + return false; } /* - * BPatch_thread::continueExecution + * BPatch_thread::terminateExecution * - * Puts the thread into the running state. + * Kill the thread. */ bool BPatch_thread::terminateExecution() { @@ -215,12 +233,33 @@ bool BPatch_thread::terminateExecution() /* * BPatch_thread::isStopped * - * Returns true if the thread is stopped, and false if it is not. + * Returns true if the thread has stopped, and false if it has not. This may + * involve checking for thread events that may have recently changed this + * thread's status. This function also updates the unreportedStop flag if a + * stop is detected, in order to indicate that the stop has been reported to + * the user. */ bool BPatch_thread::isStopped() { - pollForStatusChange(); + // Check for status changes. + assert(BPatch::bpatch); + BPatch::bpatch->getThreadEvent(false); + if (statusIsStopped()) { + setUnreportedStop(false); + return true; + } else + return false; +} + + +/* + * BPatch_thread::statusIsStopped + * + * Returns true if the thread is stopped, and false if it is not. + */ +bool BPatch_thread::statusIsStopped() +{ return proc->status() == stopped; } @@ -242,13 +281,34 @@ int BPatch_thread::stopSignal() /* * BPatch_thread::isTerminated * - * Returns true if the process has terminated, false if it has not. + * Returns true if the thread has terminated, and false if it has not. This + * may involve checking for thread events that may have recently changed this + * thread's status. This function also updates the unreportedTermination flag + * if the program terminated, in order to indicate that the termination has + * been reported to the user. */ bool BPatch_thread::isTerminated() { - if (proc == NULL) return true; - pollForStatusChange(); + // Check for status changes. + assert(BPatch::bpatch); + BPatch::bpatch->getThreadEvent(false); + + if (statusIsTerminated()) { + setUnreportedTermination(false); + return true; + } else + return false; +} + +/* + * BPatch_thread::statusIsTerminated + * + * Returns true if the process has terminated, false if it has not. + */ +bool BPatch_thread::statusIsTerminated() +{ + if (proc == NULL) return true; return proc->status() == exited; } @@ -283,6 +343,7 @@ void BPatch_thread::detach(bool cont) bool BPatch_thread::dumpCore(const char *file, bool terminate) { bool was_stopped; + bool had_unreportedStop = unreportedStop; if (isStopped()) was_stopped = true; else was_stopped = false; @@ -291,7 +352,37 @@ bool BPatch_thread::dumpCore(const char *file, bool terminate) bool ret = proc->dumpCore(file); if (ret && terminate) { terminateExecution(); - } else if (!was_stopped) { + } else if (was_stopped) { + unreportedStop = had_unreportedStop; + } else { + continueExecution(); + } + + return ret; +} + + +/* + * BPatch_thread::dumpImage + * + * Writes the contents of memory into a file. + * Returns true upon success, and false upon failure. + * + * file The name of the file to which the image should be written. + */ +bool BPatch_thread::dumpImage(const char *file) +{ + bool was_stopped; + bool had_unreportedStop = unreportedStop; + if (isStopped()) was_stopped = true; + else was_stopped = false; + + stopExecution(); + + bool ret = proc->dumpImage(file); + if (was_stopped) { + unreportedStop = had_unreportedStop; + } else { continueExecution(); } @@ -364,7 +455,7 @@ void BPatch_thread::free(const BPatch_variableExpr &ptr) { vector pointsToCheck; // We'll leave this empty - inferiorFree(proc, (unsigned)ptr.getAddress(), dataHeap, pointsToCheck); + inferiorFree(proc, (unsigned)ptr.getBaseAddr(), dataHeap, pointsToCheck); } diff --git a/dyninstAPI/src/BPatch_type.h b/dyninstAPI/src/BPatch_type.h index 5461d5a..1a1de35 100644 --- a/dyninstAPI/src/BPatch_type.h +++ b/dyninstAPI/src/BPatch_type.h @@ -55,6 +55,8 @@ public: const char *getName() { return name.string_of(); } bool isCompatible(const BPatch_type &otype); + + int getSize() const { return sizeof(int); }; // XXX Only ints for now }; #ifdef BPATCH_LIBRARY diff --git a/dyninstAPI/src/aix.C b/dyninstAPI/src/aix.C index 9f135c0..cd1771c 100644 --- a/dyninstAPI/src/aix.C +++ b/dyninstAPI/src/aix.C @@ -681,9 +681,18 @@ void OS::osTraceMe(void) // wait for a process to terminate or stop +#ifdef BPATCH_LIBRARY +int process::waitProcs(int *status, bool block) { + int options; + if (block) options = 0; + else options = WNOHANG; + return waitpid(0, status, options); +} +#else int process::waitProcs(int *status) { return waitpid(0, status, WNOHANG); } +#endif // attach to an inferior process. @@ -821,13 +830,17 @@ bool process::API_detach_(const bool cont) { #endif // temporarily unimplemented, PT_DUMPCORE is specific to sunos4.1 -bool process::dumpCore_(const string /*coreFile*/) { +bool process::dumpCore_(const string coreFile) { if (!checkStatus()) return false; ptraceOps++; ptraceOtherOps++; +#ifdef BPATCH_LIBRARY + if (!dumpImage(coreFile)) { +#else if (!dumpImage()) { // if (!OS::osDumpImage(symbols->file(), pid, symbols->codeOffset())) +#endif assert(false); } @@ -927,7 +940,11 @@ bool process::loopUntilStopped() { // Write out the current contents of the text segment to disk. This is useful // for debugging dyninst. // +#ifdef BPATCH_LIBRARY +bool process::dumpImage(string outFile) { +#else bool process::dumpImage() { +#endif // formerly OS::osDumpImage() const string &imageFileName = symbols->file(); // const Address codeOff = symbols->codeOffset(); @@ -943,7 +960,9 @@ bool process::dumpImage() { Address baseAddr; extern int errno; char buffer[4096]; +#ifndef BPATCH_LIBRARY char outFile[256]; +#endif struct filehdr hdr; struct stat statBuf; struct aouthdr aout; @@ -953,7 +972,7 @@ bool process::dumpImage() { ifd = open(imageFileName.string_of(), O_RDONLY, 0); if (ifd < 0) { - sprintf(errorLine, "Unable to open %s\n", outFile); + sprintf(errorLine, "Unable to open %s\n", imageFileName.string_of()); logLine(errorLine); showErrorCallback(41, (const char *) errorLine); perror("open"); @@ -963,17 +982,21 @@ bool process::dumpImage() { rd = fstat(ifd, &statBuf); if (rd != 0) { perror("fstat"); - sprintf(errorLine, "Unable to stat %s\n", outFile); + sprintf(errorLine, "Unable to stat %s\n", imageFileName.string_of()); logLine(errorLine); showErrorCallback(72, (const char *) errorLine); return true; } length = statBuf.st_size; +#ifdef BPATCH_LIBRARY + ofd = open(outFile.string_of(), O_WRONLY|O_CREAT, 0777); +#else sprintf(outFile, "%s.real", imageFileName.string_of()); sprintf(errorLine, "Saving program to %s\n", outFile); logLine(errorLine); ofd = open(outFile, O_WRONLY|O_CREAT, 0777); +#endif if (ofd < 0) { perror("open"); exit(-1); diff --git a/dyninstAPI/src/dummy.C b/dyninstAPI/src/dummy.C index 257f1ba..696281d 100644 --- a/dyninstAPI/src/dummy.C +++ b/dyninstAPI/src/dummy.C @@ -44,19 +44,10 @@ * Miscellaneous functions and globals that are defined in paradynd modules * which aren't being included in the library. * - * $Log: dummy.C,v $ - * Revision 1.1 1997/03/18 19:44:09 buck - * first commit of dyninst library. Also includes: - * moving templates from paradynd to dyninstAPI - * converting showError into a function (in showerror.C) - * many ifdefs for BPATCH_LIBRARY in dyinstAPI/src. - * - * */ -#include "util/h/String.h" -#include "util/h/Vector.h" -#include "util/h/Dictionary.h" +#include +#include int traceSocket = 0; int traceSocket_fd = 0; @@ -72,14 +63,7 @@ void statusLine(char const *) // don't bother with these } -/* float currSamplingRate = BASEBUCKETWIDTH; -float samplingRate = 1.0; */ - void cleanUpAndExit(int status) { exit(status); } - -// no OS init required for library -initOS() { -} diff --git a/dyninstAPI/src/inst-x86.C b/dyninstAPI/src/inst-x86.C index ce6dd75..e5660f5 100644 --- a/dyninstAPI/src/inst-x86.C +++ b/dyninstAPI/src/inst-x86.C @@ -43,6 +43,17 @@ * inst-x86.C - x86 dependent functions and code generator * * $Log: inst-x86.C,v $ + * Revision 1.30 1998/03/06 21:32:59 buck + * Added several calls to API (waitForStatusChange, BPatch_variableExpr + * member functions getBaseAddr and readValue, writeValue with an extra + * length parameter). + * Fixed several bugs in x86 instrumentation code related to parsing jump + * tables. + * Made changes to work with gcc-built programs on NT. + * + * Revision 1.1.1.9 1998/02/04 01:06:37 buck + * Import latest changes from Wisconsin into Maryland repository. + * * Revision 1.29 1997/11/26 21:44:48 mcheyney * *** empty log message *** * @@ -304,6 +315,61 @@ void instPoint::checkInstructions() { } +#ifdef BPATCH_LIBRARY +/* + Returns true if we can use the extra slot for a jump at the entry point + to insert a jump to a base tramp at this point. + */ +bool instPoint::canUseExtraSlot(process *proc) const { + // We get 10 bytes for the entry points, instead of the usual five, + // so that we have space for an extra jump. We can then insert a + // jump to the basetramp in the second slot of the base tramp + // and use a short 2-byte jump from the point to the second jump. + // We adopt the following rule: Only one point in the function + // can use the indirect jump, and this is the first return point + // with a size that is less than five bytes + vectorfReturns = func()->funcExits(proc); + + // first check if this point can use the extra slot in the entry point + bool canUse = false; + for (unsigned u = 0; u < fReturns.size(); u++) { + if (fReturns[u] == this) { + canUse = true; + break; + } else if (fReturns[u]->size() < JUMP_SZ) + break; + } + + return canUse; +} + +bool instPoint::usesTrap(process *proc) +{ + checkInstructions(); + + if (size() < JUMP_REL32_SZ) { + if (canUseExtraSlot(proc)) { + const instPoint *entry = func()->funcEntry(proc); +#ifdef DONT_MAKE_BASETRAMP_FOR_TRAP + if (proc->baseMap.defines(entry) && entry->size() >= 2*JUMP_SZ) { +#else + ((instPoint *)entry)->checkInstructions(); + if (entry->size() >= 2*JUMP_SZ) { +#endif /* DONT_MAKE_BASETRAMP_FOR_TRAP */ + // actual displacement needs to subtract size of instruction (2 bytes) + int displacement = entry->address() + 5 - jumpAddr(); + assert(displacement < 0); + if (size() >= 2 && (displacement-2) > SCHAR_MIN) { + return false; + } + } + } + return true; + } + return false; +} +#endif + /************************************************************** * * machine dependent methods of pdFunction @@ -395,7 +461,7 @@ bool checkJumpTable(image *im, instruction insn, Address addr, return true; } // skip the jump table - for (const unsigned *ptr = (unsigned *)tableBase; + for (const unsigned *ptr = (unsigned *)im->getPtrToInstruction(tableBase); *ptr >= funcBegin && *ptr <= funcEnd; ptr++) { //fprintf(stderr, " jump table entry = %x\n", *(unsigned *)ptr); tableSz += sizeof(int); @@ -526,8 +592,10 @@ if (prettyName() == "gethrvtime" || prettyName() == "_divdi3" // skip the jump table // insert an illegal instruction with the size of the jump table insn = instruction(instr, ILLEGAL, jumpTableSz); + allInstr[numInsns] = insn; + numInsns++; + insnSize += jumpTableSz; } - } else if (insn.isJumpDir()) { // check for jumps out of this function Address target = insn.getTarget(adr); @@ -617,7 +685,8 @@ if (prettyName() == "gethrvtime" || prettyName() == "_divdi3" unsigned maxSize = JUMP_SZ; if (type == EntryPt) maxSize = 2*JUMP_SZ; for (unsigned u1 = index+1; size < maxSize && u1 <= numInsns; u1++) { - if (u+1 < npoints && points[u+1].index > u1 && !allInstr[u1].isCall()) { + if (((u+1 == npoints) || (u+1 < npoints && points[u+1].index > u1)) + && !allInstr[u1].isCall()) { p->addInstrAfterPt(allInstr[u1]); size += allInstr[u1].size(); thisPointEnd = u1; @@ -985,6 +1054,10 @@ unsigned generateBranchToTramp(process *proc, const instPoint *point, unsigned b // the point is not big enough for a jump // First, check if we can use an indirection with the entry point // if that is not possible, we must use a trap +#ifdef BPATCH_LIBRARY + pd_Function *f = point->func(); + if (point->canUseExtraSlot(proc)) { +#else // We get 10 bytes for the entry points, instead of the usual five, // so that we have space for an extra jump. We can then insert a // jump to the basetramp in the second slot of the base tramp @@ -1005,7 +1078,9 @@ unsigned generateBranchToTramp(process *proc, const instPoint *point, unsigned b break; } if (canUse) { +#endif const instPoint *the_entry = f->funcEntry(proc); +#ifdef DONT_MAKE_BASETRAMP_FOR_TRAP if (proc->baseMap.defines(the_entry) && the_entry->size() >= 2*JUMP_SZ) { assert(point->jumpAddr() > the_entry->address()); // actual displacement needs to subtract size of instruction (2 bytes) @@ -1018,6 +1093,31 @@ unsigned generateBranchToTramp(process *proc, const instPoint *point, unsigned b return 2; } } +#else /* DONT_MAKE_BASETRAMP_FOR_TRAP */ + ((instPoint *)the_entry)->checkInstructions(); + if (the_entry->size() >= 2*JUMP_SZ) { + assert(point->jumpAddr() > the_entry->address()); + // actual displacement needs to subtract size of instruction (2 bytes) + int displacement = the_entry->address() + 5 - point->jumpAddr(); + assert(displacement < 0); + if (point->size() >= 2 && (displacement-2) > SCHAR_MIN) { + returnInstance *retInstance; + instPoint *nonConstEntry = (instPoint *)the_entry; + // XXX Is making the noCost parameter always false okay here? + trampTemplate *entryBase = + findAndInstallBaseTramp(proc, nonConstEntry, + retInstance, false); + assert(entryBase); + if (retInstance) { + retInstance->installReturnInstance(proc); + } + generateBranch(proc, the_entry->address()+5, baseAddr); + *insn++ = 0xEB; + *insn++ = (char)(displacement-2); + return 2; + } + } +#endif /* DONT_MAKE_BASETRAMP_FOR_TRAP */ } // must use trap diff --git a/dyninstAPI/src/instPoint-x86.h b/dyninstAPI/src/instPoint-x86.h index 0f936da..132a440 100644 --- a/dyninstAPI/src/instPoint-x86.h +++ b/dyninstAPI/src/instPoint-x86.h @@ -164,6 +164,10 @@ class instPoint { // all functions have been seen -- this might be cleaned up void set_callee(pd_Function * to) { callee_ = to; } +#ifdef BPATCH_LIBRARY + bool usesTrap(process *proc); + bool canUseExtraSlot(process *proc) const; +#endif private: Address addr_; //The address of this instPoint: this is the address @@ -177,6 +181,7 @@ class instPoint { instruction insnAtPoint_; //The instruction at this point vector *insnBeforePt_; //Additional instructions before the point vector *insnAfterPt_; //Additional instructions after the point + }; #endif diff --git a/dyninstAPI/src/pdwinnt.C b/dyninstAPI/src/pdwinnt.C index 64c25c6..58524b8 100644 --- a/dyninstAPI/src/pdwinnt.C +++ b/dyninstAPI/src/pdwinnt.C @@ -275,6 +275,7 @@ Address loadDyninstDll(process *p, char Buffer[LOAD_DYNINST_BUF_SIZE]) { p->readDataSpace((void *)codeBase, LOAD_DYNINST_BUF_SIZE, Buffer, false); p->writeDataSpace((void *)codeBase, LOAD_DYNINST_BUF_SIZE, ibuf); + return codeBase; } @@ -297,7 +298,11 @@ void checkProcStatus() { /* wait for inferior processes to terminate or stop. */ +#ifdef BPATCH_LIBRARY +int process::waitProcs(int *status, bool block) { +#else int process::waitProcs(int *status) { +#endif DEBUG_EVENT debugEv; process *p; #ifdef BPATCH_LIBRARY @@ -308,8 +313,16 @@ int process::waitProcs(int *status) { // happens on the select in controllerMainLoop. But on NT, because // we have to handle traps, we set the timeout on the select as 0, // so that we can check for traps quicly +#ifdef BPATCH_LIBRARY + DWORD milliseconds; + if (block) milliseconds = INFINITE; + else milliseconds = 1; + if (!WaitForDebugEvent(&debugEv, milliseconds)) + return 0; +#else if (!WaitForDebugEvent(&debugEv, 1)) return 0; +#endif //printf("Debug event from process %d, tid %d\n", debugEv.dwProcessId, // debugEv.dwThreadId); @@ -1006,7 +1019,8 @@ void initSymbols(HANDLE procH, const string file, const string dir) { return; } if (!SymLoadModule(procH, NULL, (char *)file.string_of(), NULL, 0, 0)) { - printf("SymLoadModule failed, %x\n", GetLastError()); + printf("SymLoadModule failed for \"%s\", %x\n", + file.string_of(), GetLastError()); return; } } diff --git a/dyninstAPI/src/process.C b/dyninstAPI/src/process.C index c469004..4ab867d 100644 --- a/dyninstAPI/src/process.C +++ b/dyninstAPI/src/process.C @@ -1275,7 +1275,7 @@ process *createProcess(const string File, vector argv, vector en if (!file.prefixed_by("/") && dir.length() > 0) file = dir + "/" + file; -#ifdef BPATCH_LIBRARY +#if defined(BPATCH_LIBRARY) && !defined(BPATCH_REDIRECT_IO) string inputFile; string outputFile; #else diff --git a/dyninstAPI/src/process.h b/dyninstAPI/src/process.h index c40cdf9..4b50d58 100644 --- a/dyninstAPI/src/process.h +++ b/dyninstAPI/src/process.h @@ -298,7 +298,11 @@ class process { Address findInternalAddress(const string &name, bool warn, bool &err) const; +#ifdef BPATCH_LIBRARY + bool dumpImage(string outFile); +#else bool dumpImage(); +#endif bool symbol_info(const string &name, Symbol &ret) { assert(symbols); @@ -711,7 +715,11 @@ class process { int getProcFileDescriptor(){ return proc_fd;} +#ifdef BPATCH_LIBRARY + static int waitProcs(int *status, bool block = false); +#else static int waitProcs(int *status); +#endif const process *getParent() const {return parent;} #if defined(hppa1_1_hp_hpux) diff --git a/dyninstAPI/src/solaris.C b/dyninstAPI/src/solaris.C index 7ad05d3..8a3012a 100644 --- a/dyninstAPI/src/solaris.C +++ b/dyninstAPI/src/solaris.C @@ -63,6 +63,7 @@ #include "instPoint.h" #include +#include #include #include #include @@ -159,7 +160,11 @@ bool process::continueWithForwardSignal(int) { return true; } +#ifdef BPATCH_LIBRARY +bool process::dumpImage(string /* imageFileName */) {return false;} +#else bool process::dumpImage() {return false;} +#endif /* @@ -175,13 +180,21 @@ static inline bool execResult(prstatus_t stat) { /* wait for inferior processes to terminate or stop. */ +#ifdef BPATCH_LIBRARY +int process::waitProcs(int *status, bool block) { +#else int process::waitProcs(int *status) { +#endif extern vector processVec; static struct pollfd fds[OPEN_MAX]; // argument for poll static int selected_fds; // number of selected static int curr; // the current element of fds +#ifdef BPATCH_LIBRARY + do { +#endif + /* Each call to poll may return many selected fds. Since we only report the status of one process per each call to waitProcs, we keep the result of the last poll buffered, and simply process an element from the buffer until all of @@ -198,7 +211,14 @@ int process::waitProcs(int *status) { fds[u].revents = 0; } +#ifdef BPATCH_LIBRARY + int timeout; + if (block) timeout = INFTIM; + else timeout = 0; + selected_fds = poll(fds, processVec.size(), timeout); +#else selected_fds = poll(fds, processVec.size(), 0); +#endif if (selected_fds < 0) { fprintf(stderr, "waitProcs: poll failed: %s\n", sys_errlist[errno]); selected_fds = 0; @@ -216,6 +236,12 @@ int process::waitProcs(int *status) { prstatus_t stat; int ret = 0; +#ifdef BPATCH_LIBRARY + if (fds[curr].revents & POLLHUP) { + ret = waitpid(processVec[curr]->getPid(), status, 0); + assert(ret > 0); + } else +#endif if (ioctl(fds[curr].fd, PIOCSTATUS, &stat) != -1 && ((stat.pr_flags & PR_STOPPED) || (stat.pr_flags & PR_ISTOP))) { switch (stat.pr_why) { @@ -283,7 +309,12 @@ int process::waitProcs(int *status) { } } +#ifdef BPATCH_LIBRARY + } while (block); + return 0; +#else return waitpid(0, status, WNOHANG); +#endif } diff --git a/dyninstAPI/src/sunos.C b/dyninstAPI/src/sunos.C index 0e4beb7..2dc0bad 100644 --- a/dyninstAPI/src/sunos.C +++ b/dyninstAPI/src/sunos.C @@ -41,6 +41,17 @@ /* * $Log: sunos.C,v $ + * Revision 1.35 1998/03/06 21:33:08 buck + * Added several calls to API (waitForStatusChange, BPatch_variableExpr + * member functions getBaseAddr and readValue, writeValue with an extra + * length parameter). + * Fixed several bugs in x86 instrumentation code related to parsing jump + * tables. + * Made changes to work with gcc-built programs on NT. + * + * Revision 1.1.1.6 1997/07/17 18:15:25 buck + * Import latest changes from Wisconsin. + * * Revision 1.34 1997/07/17 16:53:07 buck * Eliminated the need to link dyninst API with -lkvm on SunOS, * and added a check for the failure of the "attach" constructor for @@ -440,9 +451,18 @@ void OS::osTraceMe(void) { P_ptrace(PTRACE_TRACEME, 0, 0, 0, 0); } // wait for a process to terminate or stop +#ifdef BPATCH_LIBRARY +int process::waitProcs(int *status, bool block) { + int options; + if (block) options = 0; + else options = WNOHANG; + return waitpid(0, status, options); +} +#else int process::waitProcs(int *status) { return waitpid(0, status, WNOHANG); } +#endif // attach to an inferior process. bool process::attach() { @@ -806,9 +826,10 @@ bool process::loopUntilStopped() { } #ifdef BPATCH_LIBRARY -bool process::dumpImage() { return false; } +bool process::dumpImage(string outFile) { #else bool process::dumpImage() { +#endif const string &imageFileName = symbols->file(); const Address codeOff = symbols->codeOffset(); @@ -820,7 +841,9 @@ bool process::dumpImage() { int length; struct exec my_exec; char buffer[4096]; +#ifndef BPATCH_LIBRARY char outFile[256]; +#endif extern int errno; struct stat statBuf; @@ -849,6 +872,12 @@ bool process::dumpImage() { return false; } length = statBuf.st_size; +#ifdef BPATCH_LIBRARY + ofd = P_open(outFile.string_of(), O_WRONLY|O_CREAT, 0777); + if (ofd < 0) { + string msg = string("Dump core failed: unable to open file '") + outFile + + string("': ") + string(sys_errlist[errno]); +#else sprintf(outFile, "%s.real", imageFileName.string_of()); sprintf(errorLine, "saving program to %s\n", outFile); logLine(errorLine); @@ -857,6 +886,7 @@ bool process::dumpImage() { if (ofd < 0) { string msg = string("Dump core failed: unable to open file '") + string(outFile) + string("': ") + string(sys_errlist[errno]); +#endif showErrorCallback(47, msg); P_close(ifd); return false; @@ -934,7 +964,6 @@ bool process::dumpImage() { P_close(ifd); return true; } -#endif /* BPATCH_LIBRARY */ #ifdef BPATCH_LIBRARY float OS::compute_rusage_cpu() { return 0; } diff --git a/dyninstAPI/src/templates-nt.C b/dyninstAPI/src/templates-nt.C index 9437eac..cce8ca2 100644 --- a/dyninstAPI/src/templates-nt.C +++ b/dyninstAPI/src/templates-nt.C @@ -40,7 +40,7 @@ */ /* - * $Id: templates-nt.C,v 1.5 1998/03/02 02:22:11 wylie Exp $ + * $Id: templates-nt.C,v 1.6 1998/03/06 21:33:09 buck Exp $ */ /* The VC++ v5.0 compiler (probably correctly) generates warning C4660's @@ -83,5 +83,11 @@ template class dictionary_hash; template class dictionary_hash; template class dictionary_hash; +#ifdef BPATCH_LIBRARY +#include "util/h/String.h" +#include "dyninstAPI/h/BPatch_thread.h" +class BPatch_type; - +template class dictionary_hash; +template class dictionary_hash; +#endif diff --git a/dyninstAPI/src/templates0.C b/dyninstAPI/src/templates0.C index 4081752..e07884b 100644 --- a/dyninstAPI/src/templates0.C +++ b/dyninstAPI/src/templates0.C @@ -80,6 +80,9 @@ #include "dyninstAPI/src/ast.h" #include "dyninstAPI/src/util.h" #include "util/h/Object.h" +#if !defined(BPATCH_LIBRARY) || defined(sparc_sun_sunos4_1_3) || defined(sparc_sun_solaris2_4) +#include "dyninstAPI/src/FunctionExpansionRecord.h" +#endif template class vector; template class vector; @@ -116,3 +119,6 @@ template class vector; template class vector; //XXX template class vector; template class vector; +#if !defined(BPATCH_LIBRARY) || defined(sparc_sun_sunos4_1_3) || defined(sparc_sun_solaris2_4) +template class vector; +#endif diff --git a/dyninstAPI/src/templates1.C b/dyninstAPI/src/templates1.C index 0b5d957..8cc88fc 100644 --- a/dyninstAPI/src/templates1.C +++ b/dyninstAPI/src/templates1.C @@ -162,7 +162,9 @@ template class dictionary_hash; template class dictionary_hash; template class dictionary_hash_iter; +template class vector::entry>; template class dictionary_hash_iter; +template class vector::entry>; #endif template class dictionary_hash *>; diff --git a/dyninstAPI/src/unix.C b/dyninstAPI/src/unix.C index 1f31dfd..358e447 100644 --- a/dyninstAPI/src/unix.C +++ b/dyninstAPI/src/unix.C @@ -228,7 +228,11 @@ bool forkNewProcess(string file, string dir, vector argv, logLine(errorLine); P__exit(-1); } - +#endif +#if !defined(BPATCH_LIBRARY) || defined(BPATCH_REDIRECT_IO) +#if defined(BPATCH_LIBRARY) /* For BPATCH_REDIRECT_IO */ + FILE *childError = stderr; +#endif /* see if I/O needs to be redirected */ if (inputFile.length()) { int fd = P_open(inputFile.string_of(), O_RDONLY, 0); @@ -667,7 +671,11 @@ int handleSigChild(int pid, int status) << WSTOPSIG(status) << ")" << endl << flush; curr->status_ = stopped; +#ifdef BPATCH_LIBRARY + curr->dumpImage("imagefile"); +#else curr->dumpImage(); +#endif curr->continueWithForwardSignal(WSTOPSIG(status)); #endif break; diff --git a/dyninstAPI/tests/src/test1.C b/dyninstAPI/tests/src/test1.C index ba6e0ab..d7c8773 100644 --- a/dyninstAPI/tests/src/test1.C +++ b/dyninstAPI/tests/src/test1.C @@ -950,9 +950,9 @@ void mutatorMAIN(char *pathname, bool useAttach) exit(1); } // see if we can find the address - if (expr3_1->getAddress() <= 0) { + if (expr3_1->getBaseAddr() <= 0) { printf("*Error*: address %d for globalVariable3_1 is not valid\n", - (int) expr3_1->getAddress()); + (int) expr3_1->getBaseAddr()); } BPatch_variableExpr *expr3_2 = appThread->malloc(*appImage->findType("int")); @@ -1071,7 +1071,9 @@ void mutatorMAIN(char *pathname, bool useAttach) mutatorTest15b(appThread, appImage); - while (!appThread->isTerminated()) ; + while (!appThread->isTerminated()) + waitForStatusChange(); + dprintf("Done.\n"); } diff --git a/dyninstAPI/tests/src/test2.C b/dyninstAPI/tests/src/test2.C index 58e71aa..b538951 100644 --- a/dyninstAPI/tests/src/test2.C +++ b/dyninstAPI/tests/src/test2.C @@ -264,6 +264,10 @@ main(int argc, char *argv[]) ret->stopExecution(); +#ifndef sparc_sun_sunos4_1_3 + printf("Skipping test #7 (dump core but do not terminate)\n"); + printf(" BPatch_thread::dumpCore() not implemented on this platform\n"); +#else // dump core, but do not terminate. // this doesn't seem to do anything - jkh 7/12/97 if (access("mycore", F_OK) == 0) { @@ -274,10 +278,6 @@ main(int argc, char *argv[]) } } -#ifndef sparc_sun_sunos4_1_3 - printf("Skipping test #7 (dump core but do not terminate)\n"); - printf(" BPatch_thread::dumpCore() not implemented on this platform\n"); -#else gotError = false; ret->dumpCore("mycore", true); bool coreExists = (access("mycore", F_OK) == 0); @@ -293,6 +293,34 @@ main(int argc, char *argv[]) } #endif +#if !defined(rs6000_ibm_aix4_1) && !defined(sparc_sun_sunos4_1_3) + printf("Skipping test #8 (dump image)\n"); + printf(" BPatch_thread::dumpImage() not implemented on this platform\n"); +#else + // dump image + if (access("myimage", F_OK) == 0) { + printf("File \"myimage\" exists. Deleting it.\n"); + if (unlink("myimage") != 0) { + printf("Couldn't delete the file \"myimage\". Exiting.\n"); + exit(-1); + } + } + + gotError = false; + ret->dumpImage("myimage"); + bool imageExists = (access("myimage", F_OK) == 0); + if (gotError || !imageExists) { + printf("**Failed** test #8 (dump image)\n"); + failed = true; + if (gotError) + printf(" error reported by dumpImage\n"); + if (!imageExists) + printf(" the image file wasn't written\n"); + } else { + printf("Passed test #8 (dump image)\n"); + } +#endif + int pid = ret->getPid(); #ifndef i386_unknown_nt4_0 /* Not yet implemented on NT. */ diff --git a/dyninstAPI/tests/src/test_util.C b/dyninstAPI/tests/src/test_util.C index da672de..b46a911 100644 --- a/dyninstAPI/tests/src/test_util.C +++ b/dyninstAPI/tests/src/test_util.C @@ -13,6 +13,7 @@ #include #endif +#include "BPatch.h" #include "BPatch_Vector.h" #include "BPatch_thread.h" @@ -22,8 +23,9 @@ // void waitUntilStopped(BPatch_thread *appThread, int testnum, char *testname) { - // Wait for process to stop - while (!appThread->isStopped() && !appThread->isTerminated()) ; + while (!appThread->isStopped() && !appThread->isTerminated()) + waitForStatusChange(); + if (!appThread->isStopped()) { printf("**Failed test #%d (%s)\n", testnum, testname); printf(" process did not signal mutator via stop\n"); diff --git a/dyninstAPI_RT/i386-unknown-nt4.0/Makefile b/dyninstAPI_RT/i386-unknown-nt4.0/Makefile index 06b5446..c11f6e7 100644 --- a/dyninstAPI_RT/i386-unknown-nt4.0/Makefile +++ b/dyninstAPI_RT/i386-unknown-nt4.0/Makefile @@ -1,5 +1,5 @@ # -# $Id: Makefile,v 1.3 1998/03/02 02:37:59 wylie Exp $ +# $Id: Makefile,v 1.4 1998/03/06 21:34:08 buck Exp $ # # # Define any symbols needed to invoke configuration changes in make.config @@ -17,7 +17,9 @@ include ../../nmake.config # Now make any necessary architecture specific changes to variables: LD = link -LDFLAGS = -DLL -debug -debugtype:coff +LDFLAGS = -DLL -debug -debugtype:coff -base:0x60000000 + +CFLAGS = -Z7 $(CFLAGS) SRCS = $(SRCS) ../src/RTwinnt.c -- 1.8.3.1