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 // $Id: BPatch_thread.C,v 1.62 2002/09/19 01:21:37 buck Exp $
44 #ifdef sparc_sun_solaris2_4
56 #include "BPatch_thread.h"
57 #include "LineInformation.h"
60 * class OneTimeCodeInfo
62 * This is used by the oneTimeCode (inferiorRPC) mechanism to keep per-RPC
65 class OneTimeCodeInfo {
71 OneTimeCodeInfo(bool _synchronous, void *_userData) :
72 synchronous(_synchronous), completed(false), userData(_userData) { };
74 bool isSynchronous() { return synchronous; }
76 bool isCompleted() const { return completed; }
77 void setCompleted(bool _completed) { completed = _completed; }
79 void *getUserData() { return userData; }
81 void setReturnValue(void *_returnValue) { returnValue = _returnValue; }
82 void *getReturnValue() { return returnValue; }
87 * BPatch_thread::getPid
89 * Return the process ID of the thread associated with this object.
91 int BPatch_thread::getPid()
93 return proc->getPid();
97 static void insertVForkInst(BPatch_thread *thread)
100 BPatch_image *appImage = thread->getImage();
101 if (!appImage) return;
103 #if !defined(i386_unknown_nt4_0) && !defined(mips_unknown_ce2_11) //ccw 20 july 2000 : 28 mar 2001
104 BPatch_function *vforkFunc = appImage->findFunction("DYNINSTvfork");
106 BPatch_Vector<BPatch_point *> *points =
107 appImage->findProcedurePoint("vfork", BPatch_exit);
109 if (vforkFunc && points) {
110 BPatch_Vector<BPatch_snippet *> args;
111 BPatch_constExpr pidExpr(thread->getPid());
112 args.push_back(&pidExpr);
114 BPatch_snippet *ret = new BPatch_funcCallExpr(*vforkFunc, args);
116 printf("error creating function\n");
120 thread->insertSnippet(*ret, *points);
126 * BPatch_thread::BPatch_thread
128 * Starts a new process and associates it with the BPatch_thread being
129 * constructed. The new process is placed into a stopped state before
130 * executing any code.
132 * path Pathname of the executable to start.
133 * argv A list of pointers to character strings which are the
134 * arguments for the new process, terminated by a NULL pointer.
135 * envp A list of pointers to character strings which are to be
136 * passed to the new process as its environment, terminated by a
137 * NULL pointer. If envp is NULL, the parent's environment is
138 * copied and passed to the child.
140 BPatch_thread::BPatch_thread(char *path, char *argv[], char *envp[],
141 int stdin_fd, int stdout_fd, int stderr_fd)
142 : proc(NULL), image(NULL), lastSignal(-1), exitCode(-1), mutationsActive(true),
143 createdViaAttach(false), detached(false),
144 unreportedStop(false), unreportedTermination(false)
146 vector<string> argv_vec;
147 vector<string> envp_vec;
149 // Contruct a vector out of the contents of argv
150 for(int i = 0; argv[i] != NULL; i++)
151 argv_vec.push_back(argv[i]);
153 // Construct a vector out of the contents of envp
155 for(int i = 0; envp[i] != NULL; i++)
156 envp_vec.push_back(envp[i]);
159 string directoryName = "";
161 #if !defined(i386_unknown_nt4_0) && !defined(mips_unknown_ce2_11) // i.e. for all unixes
163 // this fixes a problem on linux and alpha platforms where pathless filenames
164 // are searched for either in a standard, predefined path, or in $PATH by execvp.
165 // thus paths that should resolve to "./" are missed.
166 // Note that the previous use of getcwd() here for the alpha platform was dangerous
167 // since this is an API and we don't know where the user's code will leave the
169 const char *dotslash = "./";
170 if (NULL == strchr(path, '/'))
171 directoryName = dotslash;
174 //#if defined(alpha_dec_osf4_0)
176 //(void*) getcwd(buf, sizeof(buf));
177 //directoryName = buf;
180 proc = createProcess(path, argv_vec, envp_vec, directoryName, stdin_fd,
181 stdout_fd, stderr_fd);
183 // XXX Should do something more sensible.
184 if (proc == NULL) return;
188 // Add this object to the list of threads
189 // XXX Should be conditional on success of creating process
190 assert(BPatch::bpatch != NULL);
191 BPatch::bpatch->registerThread(this);
193 image = new BPatch_image(proc);
195 while (!proc->isBootstrappedYet() && !statusIsTerminated())
196 BPatch::bpatch->getThreadEvent(false);
198 if (BPatch::bpatch->postForkCallback) {
199 insertVForkInst(this);
205 * BPatch_thread::BPatch_thread
207 * Constructs a new BPatch_thread and associates it with a running process.
208 * Stops execution of the process.
210 * path Pathname of the executable file for the process.
211 * pid Process ID of the target process.
213 BPatch_thread::BPatch_thread(char *path, int pid)
214 : proc(NULL), image(NULL), lastSignal(-1), exitCode(-1), mutationsActive(true),
215 createdViaAttach(true), detached(false),
216 unreportedStop(false), unreportedTermination(false)
219 /* For some reason, on Irix, evaluating the return value of
220 attachProcess directly (i.e. no "ret" variable) causes the
221 expression to be incorrectly evaluated as false. This appears
222 to be a compiler bug ("g++ -mabi=64 -O3"). */
223 bool ret = attachProcess(path, pid, 1, proc);
225 // XXX Should do something more sensible
232 // Add this object to the list of threads
233 assert(BPatch::bpatch != NULL);
234 BPatch::bpatch->registerThread(this);
236 image = new BPatch_image(proc);
238 while (!proc->isBootstrappedYet() && !statusIsTerminated()) {
239 BPatch::bpatch->getThreadEventOnly(false);
240 proc->launchRPCifAppropriate(false, false);
243 #if defined(alpha_dec_osf4_0)
244 // need to perform this after dyninst Heap is present and happy
245 proc->getDyn()->setMappingHooks(proc);
248 insertVForkInst(this);
252 * BPatch_thread::BPatch_thread
254 * Constructs a new BPatch_thread and associates it with a forked process.
256 * parentPid Pathname of the executable file for the process.
257 * childPid Process ID of the target process.
259 BPatch_thread::BPatch_thread(int /*pid*/, process *nProc)
260 : proc(nProc), image(NULL), lastSignal(-1), exitCode(-1), mutationsActive(true),
261 createdViaAttach(true), detached(false),
262 unreportedStop(false), unreportedTermination(false)
266 // Add this object to the list of threads
267 assert(BPatch::bpatch != NULL);
268 BPatch::bpatch->registerThread(this);
270 image = new BPatch_image(proc);
275 * BPatch_thread::~BPatch_thread
277 * Destructor for BPatch_thread. Detaches from the running thread.
279 BPatch_thread::~BPatch_thread()
281 if (image) delete image;
283 // XXX Make sure that anything else that needs to be deallocated
284 // gets taken care of.
288 #if !defined(i386_unknown_nt4_0) && !(defined mips_unknown_ce2_11) //ccw 20 july 2000 : 28 mar 2001
289 if (createdViaAttach && !statusIsTerminated())
290 proc->API_detach(true);
293 terminateExecution();
296 assert(BPatch::bpatch != NULL);
297 BPatch::bpatch->unRegisterThread(getPid());
299 // Remove the process from our list of processes
301 for (i = 0; i < processVec.size(); i++) {
302 if (processVec[i] == proc) {
306 assert(i < processVec.size());
307 while (i < processVec.size()-1) {
308 processVec[i] = processVec[i+1];
311 processVec.resize(processVec.size()-1);
313 // XXX I think there are some other things we need to deallocate -- check
316 // XXX We'd like to delete the process object here, but if we do that then
317 // we get problems (specifically, the library gets confused in some way so
318 // that it won't be able to run another mutatee process). Anyway, the
319 // process class has no destructor right now, so whether we delete proc or
320 // not we're leaking megabytes of memory. So, for now, we just leave it
327 * BPatch_thread::stopExecution
329 * Puts the thread into the stopped state.
331 bool BPatch_thread::stopExecution()
333 assert(BPatch::bpatch);
334 BPatch::bpatch->getThreadEvent(false);
336 #ifdef DETACH_ON_THE_FLY
337 return proc->reattachAndPause();
339 return proc->pause();
343 assert(BPatch::bpatch);
345 while (!statusIsStopped())
346 BPatch::bpatch->getThreadEvent(false);
348 setUnreportedStop(false);
355 * BPatch_thread::continueExecution
357 * Puts the thread into the running state.
359 bool BPatch_thread::continueExecution()
361 assert(BPatch::bpatch);
362 BPatch::bpatch->getThreadEvent(false);
364 #ifdef DETACH_ON_THE_FLY
365 if (proc->detachAndContinue()) {
367 if (proc->continueProc()) {
369 setUnreportedStop(false);
378 * BPatch_thread::terminateExecution
382 bool BPatch_thread::terminateExecution()
384 if (!proc || !proc->terminateProc())
387 // Wait for the process to die
388 while (!isTerminated()) ;
395 * BPatch_thread::isStopped
397 * Returns true if the thread has stopped, and false if it has not. This may
398 * involve checking for thread events that may have recently changed this
399 * thread's status. This function also updates the unreportedStop flag if a
400 * stop is detected, in order to indicate that the stop has been reported to
403 bool BPatch_thread::isStopped()
405 // Check for status changes.
406 assert(BPatch::bpatch);
407 BPatch::bpatch->getThreadEvent(false);
408 if (statusIsStopped()) {
409 setUnreportedStop(false);
417 * BPatch_thread::statusIsStopped
419 * Returns true if the thread is stopped, and false if it is not.
421 bool BPatch_thread::statusIsStopped()
423 return proc->status() == stopped;
428 * BPatch_thread::stopSignal
430 * Returns the number of the signal which caused the thread to stop.
432 int BPatch_thread::stopSignal()
434 if (proc->status() != neonatal && proc->status() != stopped)
442 * BPatch_thread::terminationStatus
444 * Returns the exit status code of the terminated thread.
446 int BPatch_thread::terminationStatus()
448 if (proc->status() != exited)
456 * BPatch_thread::isTerminated
458 * Returns true if the thread has terminated, and false if it has not. This
459 * may involve checking for thread events that may have recently changed this
460 * thread's status. This function also updates the unreportedTermination flag
461 * if the program terminated, in order to indicate that the termination has
462 * been reported to the user.
464 bool BPatch_thread::isTerminated()
466 // Check for status changes.
467 assert(BPatch::bpatch);
468 BPatch::bpatch->getThreadEvent(false);
470 if (statusIsTerminated()) {
471 proc->terminateProc();
472 setUnreportedTermination(false);
480 * BPatch_thread::statusIsTerminated
482 * Returns true if the process has terminated, false if it has not.
484 bool BPatch_thread::statusIsTerminated()
486 if (proc == NULL) return true;
487 return proc->status() == exited;
492 * BPatch_thread::detach
494 * Detach from the thread represented by this object.
496 * cont True if the thread should be continued as the result of the
497 * detach, false if it should not.
499 void BPatch_thread::detach(bool cont)
501 #ifdef DETACH_ON_THE_FLY
502 proc->reattachAndPause();
504 proc->API_detach(cont);
511 * BPatch_thread::dumpCore
513 * Causes the thread to dump its state to a file, and optionally to terminate.
514 * Returns true upon success, and false upon failure.
516 * file The name of the file to which the state should be written.
517 * terminate Indicates whether or not the thread should be terminated after
518 * dumping core. True indicates that it should, false that is
521 bool BPatch_thread::dumpCore(const char *file, bool terminate)
524 bool had_unreportedStop = unreportedStop;
525 if (isStopped()) was_stopped = true;
526 else was_stopped = false;
530 bool ret = proc->dumpCore(file);
531 if (ret && terminate) {
532 terminateExecution();
533 } else if (was_stopped) {
534 unreportedStop = had_unreportedStop;
543 * BPatch_thread::dumpPatchedImage
545 * Writes the mutated file back to disk,
546 * in ELF format. (Solaris only)
550 char* BPatch_thread::dumpPatchedImage(const char* file){ //ccw 28 oct 2001
552 #if !defined(sparc_sun_solaris2_4) && !defined(i386_unknown_linux2_0)
556 bool had_unreportedStop = unreportedStop;
557 if (isStopped()) was_stopped = true;
558 else was_stopped = false;
562 char* ret = proc->dumpPatchedImage(file);
564 unreportedStop = had_unreportedStop;
575 * BPatch_thread::dumpImage
577 * Writes the contents of memory into a file.
578 * Returns true upon success, and false upon failure.
580 * file The name of the file to which the image should be written.
582 bool BPatch_thread::dumpImage(const char *file)
584 #if defined(i386_unknown_nt4_0) || defined(mips_unknown_ce2_11) //ccw 20 july 2000 : 28 mar 2001
588 bool had_unreportedStop = unreportedStop;
589 if (isStopped()) was_stopped = true;
590 else was_stopped = false;
594 bool ret = proc->dumpImage(file);
596 unreportedStop = had_unreportedStop;
607 * BPatch_thread::malloc
609 * Allocate memory in the thread's address space.
611 * n The number of bytes to allocate.
614 * A pointer to a BPatch_variableExpr representing the memory.
617 BPatch_variableExpr *BPatch_thread::malloc(int n)
619 assert(BPatch::bpatch != NULL);
621 void *ptr = (void *) proc->inferiorMalloc(n, dataHeap);
626 BPatch_variableExpr *ret;
627 ret = new BPatch_variableExpr(proc, ptr, BPatch::bpatch->type_Untyped);
633 * BPatch_thread::malloc
635 * Allocate memory in the thread's address space for a variable of the given
638 * type The type of variable for which to allocate space.
641 * A pointer to a BPatch_variableExpr representing the memory.
643 * XXX Should return NULL on failure, but the function which it calls,
644 * inferiorMalloc, calls exit rather than returning an error, so this
645 * is not currently possible.
647 BPatch_variableExpr *BPatch_thread::malloc(const BPatch_type &type)
649 void *mem = (void *)proc->inferiorMalloc(type.getSize(), dataHeap);
651 if (!mem) return NULL;
653 return new BPatch_variableExpr(proc, mem, &type);
658 * BPatch_thread::free
660 * Free memory that was allocated with BPatch_thread::malloc.
662 * ptr A BPatch_variableExpr representing the memory to free.
664 void BPatch_thread::free(const BPatch_variableExpr &ptr)
666 proc->inferiorFree((Address)ptr.getBaseAddr());
671 * BPatch_thread::getInheritedVariable
673 * Allows one to retrieve a variable which exists in a child process which
674 * was inherited from and originally created in the parent process.
675 * Function is invoked on the child BPatch_thread (created from a fork in
678 * parentVar A BPatch_variableExpr created in the parent thread
680 * Returns: The corresponding BPatch_variableExpr from the child thread
681 * or NULL if the variable argument hasn't been malloced
682 * in a parent process.
684 BPatch_variableExpr *BPatch_thread::getInheritedVariable(
685 const BPatch_variableExpr &parentVar)
687 if(! isInferiorAllocated(proc, (Address)parentVar.getBaseAddr())) {
688 // isn't defined in this process so must not have been defined in a
692 return new BPatch_variableExpr(proc, parentVar.getBaseAddr(),
693 parentVar.getType());
698 * BPatch_thread::getInheritedSnippet
700 * Allows one to retrieve a snippet which exists in a child process which
701 * was inherited from and originally created in the parent process.
702 * Function is invoked on the child BPatch_thread (created from a fork in
705 * parentVar A BPatch_variableExpr created in the parent thread
707 * Returns: The corresponding BPatch_variableExpr from the child thread
708 * or NULL if the variable argument hasn't been malloced
709 * in a parent process.
711 BPatchSnippetHandle *BPatch_thread::getInheritedSnippet(
712 BPatchSnippetHandle &parentSnippet)
714 // a BPatchSnippetHandle has an miniTrampHandle for each point that
715 // the instrumentation is inserted at
716 BPatch_Vector<miniTrampHandle *> parent_mtHandles;
717 parentSnippet.getMiniTrampHandles(&parent_mtHandles);
719 BPatchSnippetHandle *childSnippet = new BPatchSnippetHandle(proc);
720 for(unsigned i=0; i<parent_mtHandles.size(); i++) {
721 miniTrampHandle *childMT = new miniTrampHandle;
722 if(! getInheritedMiniTramp(parent_mtHandles[i], childMT, proc)) {
723 // error, couldn't find a snippet
726 childSnippet->add(childMT);
733 * BPatch_thread::insertSnippet
735 * Insert a code snippet at a given instrumentation point. Upon succes,
736 * returns a handle to the created instance of the snippet, which can be used
737 * to delete it. Otherwise returns NULL.
739 * expr The snippet to insert.
740 * point The point at which to insert it.
742 BPatchSnippetHandle *BPatch_thread::insertSnippet(const BPatch_snippet &expr,
744 BPatch_snippetOrder order)
746 BPatch_callWhen when;
748 // which one depends on the type of the point
749 // need to cast away const since getPointType isn't const
750 if (((BPatch_point)point).getPointType() == BPatch_exit) {
751 when = BPatch_callAfter;
753 when = BPatch_callBefore;
756 return insertSnippet(expr, point, when, order);
760 * BPatch_thread::insertSnippet
762 * Insert a code snippet at a given instrumentation point. Upon succes,
763 * returns a handle to the created instance of the snippet, which can be used
764 * to delete it. Otherwise returns NULL.
766 * expr The snippet to insert.
767 * point The point at which to insert it.
769 BPatchSnippetHandle *BPatch_thread::insertSnippet(const BPatch_snippet &expr,
771 BPatch_callWhen when,
772 BPatch_snippetOrder order)
774 // Can't insert code when mutations are not active.
775 if (!mutationsActive)
778 // code is null (possibly an empy sequence or earlier error)
779 if (!expr.ast) return NULL;
785 case BPatch_callBefore:
788 case BPatch_callAfter:
789 _when = callPostInsn;
796 case BPatch_firstSnippet:
797 _order = orderFirstAtPoint;
799 case BPatch_lastSnippet:
800 _order = orderLastAtPoint;
806 assert(BPatch::bpatch != NULL); // We'll use this later
809 // Check for valid combinations of BPatch_procedureLocation & call*
810 // Right now we don't allow
811 // BPatch_callBefore + BPatch_exit
812 // BPatch_callAfter + BPatch_entry
814 // These combinations are intended to be used to mark the point that
815 // is the last, first valid point where the local variables are
816 // valid. This is deifferent than the first/last instruction of
817 // a subroutine which is what the other combinations of BPatch_entry
818 // and BPatch_exit refer to.
820 // jkh 3/1/00 (based on agreement reached at dyninst Jan'00 meeting)
822 if ((when == BPatch_callBefore) &&
823 (point.getPointType() == BPatch_exit)) {
824 BPatch_reportError(BPatchSerious, 113,
825 "BPatch_callBefore at BPatch_exit not supported yet");
827 } else if ((when == BPatch_callAfter) &&
828 (point.getPointType() == BPatch_entry)) {
829 BPatch_reportError(BPatchSerious, 113,
830 "BPatch_callAfter at BPatch_entry not supported yet");
834 if ((point.getPointType() == BPatch_exit)) {
836 // The semantics of pre/post insn at exit are setup for the new
837 // defintion of using this to control before/after stack creation,
838 // but the lower levels of dyninst don't know about this yet.
842 // XXX Really only need to type check once per function the snippet is
843 // being inserted into, not necessarily once per point.
844 if (BPatch::bpatch->isTypeChecked()) {
846 if (expr.ast->checkType() == BPatch::bpatch->type_Error) {
847 // XXX Type check error - should call callback
852 BPatchSnippetHandle *handle = new BPatchSnippetHandle(proc);
854 AstNode *ast = (AstNode *)expr.ast; /* XXX no const */
856 // XXX We just pass false for the "noCost" parameter here - do we want
857 // to make that an option?
858 miniTrampHandle *mtHandle = new miniTrampHandle;
859 instPoint *&ip = (instPoint*&) point.point;
861 if(point.proc != proc) {
862 cerr << "insertSnippet: the given instPoint isn't from the same process "
863 << "as the invoked BPatch_thread\n";
867 loadMiniTramp_result res = addInstFunc(mtHandle, proc, ip, ast, _when,
869 // Do we want the base tramp (if any) created allowing
871 #if defined(mips_sgi_irix6_4)
872 // On MIPS, we can't have recursive guards on arbitrary
874 point.getPointType() == BPatch_instruction ? true :
876 BPatch::bpatch->isTrampRecursive()
879 if(res == success_res) {
880 handle->add(mtHandle);
890 * BPatch_thread::insertSnippet
892 * Insert a code snippet at each of a list of instrumentation points. Upon
893 * success, Returns a handle to the created instances of the snippet, which
894 * can be used to delete them (as a unit). Otherwise returns NULL.
896 * expr The snippet to insert.
897 * points The list of points at which to insert it.
899 BPatchSnippetHandle *BPatch_thread::insertSnippet(
900 const BPatch_snippet &expr,
901 const BPatch_Vector<BPatch_point *> &points,
902 BPatch_callWhen when,
903 BPatch_snippetOrder order)
905 BPatchSnippetHandle *handle = new BPatchSnippetHandle(proc);
907 for (unsigned int i = 0; i < points.size(); i++) {
908 BPatch_point *point = points[i];
910 BPatchSnippetHandle *ret = insertSnippet(expr, *point, when, order);
912 for (unsigned int j=0; j < ret->mtHandles.size(); j++) {
913 handle->add(ret->mtHandles[j]);
927 * BPatch_thread::insertSnippet
929 * Insert a code snippet at each of a list of instrumentation points. Upon
930 * success, Returns a handle to the created instances of the snippet, which
931 * can be used to delete them (as a unit). Otherwise returns NULL.
933 * expr The snippet to insert.
934 * points The list of points at which to insert it.
936 BPatchSnippetHandle *BPatch_thread::insertSnippet(
937 const BPatch_snippet &expr,
938 const BPatch_Vector<BPatch_point *> &points,
939 BPatch_snippetOrder order)
941 BPatchSnippetHandle *handle = new BPatchSnippetHandle(proc);
943 for (unsigned int i = 0; i < points.size(); i++) {
944 BPatch_point *point = points[i]; // Cast away const
946 BPatch_callWhen when;
948 // which one depends on the type of the point
949 // need to cast away const since getPointType isn't const
950 if (point->getPointType() == BPatch_exit) {
951 when = BPatch_callAfter;
953 when = BPatch_callBefore;
956 BPatchSnippetHandle *ret = insertSnippet(expr, *point, when, order);
958 for (unsigned int j=0; j < ret->mtHandles.size(); j++) {
959 handle->add(ret->mtHandles[j]);
972 * BPatch_thread::deleteSnippet
974 * Deletes an instance of a snippet.
976 * handle The handle returned by insertSnippet when the instance to
977 * deleted was created.
979 bool BPatch_thread::deleteSnippet(BPatchSnippetHandle *handle)
981 if (handle->proc == proc) {
982 for (unsigned int i=0; i < handle->mtHandles.size(); i++) {
983 deleteInst(proc, *(handle->mtHandles[i]));
987 } else { // Handle isn't to a snippet instance in this process
994 * BPatch_thread::setMutationsActive
996 * Enable or disable the execution of all snippets for the thread.
998 * activate If set to true, execution of snippets is enabled. If false,
999 * execution is disabled.
1001 void BPatch_thread::setMutationsActive(bool activate)
1003 // If not activating or deactivating, just return.
1004 if ((activate && mutationsActive) || (!activate && !mutationsActive))
1008 // The old implementation
1009 dictionary_hash_iter<const instPoint*, trampTemplate *> bmi(proc->baseMap);
1011 const instPoint *point;
1012 trampTemplate *tramp;
1014 while (bmi.next(point, tramp)) {
1017 if (tramp->retInstance != NULL) {
1019 tramp->retInstance->installReturnInstance(proc);
1021 tramp->retInstance->unInstallReturnInstance(proc);
1027 proc->reinstallMutations();
1029 proc->uninstallMutations();
1031 mutationsActive = activate;
1036 * BPatch_thread::replaceFunctionCall
1038 * Replace a function call with a call to a different function. Returns true
1039 * upon success, false upon failure.
1041 * point The call site that is to be changed.
1042 * newFunc The function that the call site will now call.
1044 bool BPatch_thread::replaceFunctionCall(BPatch_point &point,
1045 BPatch_function &newFunc)
1047 // Can't make changes to code when mutations are not active.
1048 if (!mutationsActive)
1051 assert(point.point && newFunc.func);
1053 return proc->replaceFunctionCall(point.point, newFunc.func);
1058 * BPatch_thread::removeFunctionCall
1060 * Replace a function call with a NOOP. Returns true upon success, false upon
1063 * point The call site that is to be NOOPed out.
1065 bool BPatch_thread::removeFunctionCall(BPatch_point &point)
1067 // Can't make changes to code when mutations are not active.
1068 if (!mutationsActive)
1071 assert(point.point);
1073 return proc->replaceFunctionCall(point.point, NULL);
1078 * BPatch_thread::replaceFunction
1080 * Replace all calls to function OLDFUNC with calls to NEWFUNC.
1081 * Returns true upon success, false upon failure.
1083 * oldFunc The function to replace
1084 * newFunc The replacement function
1086 bool BPatch_thread::replaceFunction(BPatch_function &oldFunc,
1087 BPatch_function &newFunc)
1089 #if defined(sparc_sun_solaris2_4) || defined(alpha_dec_osf4_0) || defined(i386_unknown_linux2_0) || defined(ia64_unknown_linux2_4) /* Temporary duplication - TLM */
1090 // Can't make changes to code when mutations are not active.
1091 if (!mutationsActive)
1094 assert(oldFunc.func && newFunc.func);
1096 // Self replacement is a nop
1097 if (oldFunc.func == newFunc.func)
1103 bool old_recursion_flag = BPatch::bpatch->isTrampRecursive();
1104 BPatch::bpatch->setTrampRecursive( true );
1106 // We replace functions by instrumenting the entry of OLDFUNC with
1107 // a non-linking jump to NEWFUNC. Calls to OLDFUNC do actually
1108 // transfer to OLDFUNC, but then our jump shunts them to NEWFUNC.
1109 // The non-linking jump ensures that when NEWFUNC returns, it
1110 // returns directly to the caller of OLDFUNC.
1111 BPatch_Vector<BPatch_point *> *pts = oldFunc.findPoint(BPatch_entry);
1112 if (! pts || ! pts->size())
1114 BPatch_funcJumpExpr fje(newFunc);
1115 BPatchSnippetHandle * result = insertSnippet(fje, *pts, BPatch_callBefore);
1120 BPatch::bpatch->setTrampRecursive( old_recursion_flag );
1122 return (NULL != result);
1124 BPatch_reportError(BPatchSerious, 109,
1125 "replaceFunction is not implemented on this platform");
1132 * BPatch_thread::oneTimeCodeCallbackDispatch
1134 * This function is registered with the lower-level code as the callback for
1135 * inferior RPC completion. It determines what thread the RPC was executed on
1136 * and then calls the API's higher-level callback routine for that thread.
1138 * theProc The process in which the RPC completed.
1139 * userData This is a value that can be set when we invoke an inferior RPC
1140 * and which will be returned to us in this callback.
1141 * returnValue The value returned by the RPC.
1143 void BPatch_thread::oneTimeCodeCallbackDispatch(process *theProc,
1147 assert(BPatch::bpatch != NULL);
1149 OneTimeCodeInfo *info = (OneTimeCodeInfo *)userData;
1151 BPatch_thread *theThread =
1152 BPatch::bpatch->getThreadByPid(theProc->getPid());
1154 assert(theThread != NULL);
1155 assert(info && !info->isCompleted());
1157 info->setReturnValue(returnValue);
1158 info->setCompleted(true);
1160 if (!info->isSynchronous()) {
1161 if (BPatch::bpatch->oneTimeCodeCallback)
1162 BPatch::bpatch->oneTimeCodeCallback(theThread, info->getUserData(), returnValue);
1167 #ifdef IBM_BPATCH_COMPAT
1168 if (BPatch::bpatch->RPCdoneCallback) {
1169 printf("invoking IBM thread callback function\n");
1170 BPatch::bpatch->RPCdoneCallback(theThread, userData, returnValue);
1177 * BPatch_thread::oneTimeCodeInternal
1179 * Causes a snippet expression to be evaluated once in the mutatee at the next
1180 * available opportunity. Optionally, Dyninst will call a callback function
1181 * when the snippet has executed in the mutatee, and can wait until the
1182 * snippet has executed to return.
1184 * expr The snippet to evaluate.
1185 * userData This value is given to the callback function along with the
1186 * return value for the snippet. Can be used by the caller to
1187 * store per-oneTimeCode information.
1188 * synchronous True means wait until the snippet has executed, false means
1189 * return immediately.
1191 void *BPatch_thread::oneTimeCodeInternal(const BPatch_snippet &expr,
1195 bool needToResume = false;
1197 if (synchronous && !statusIsStopped()) {
1199 if (!statusIsStopped()) {
1202 needToResume = true;
1205 OneTimeCodeInfo *info = new OneTimeCodeInfo(synchronous, userData);
1207 proc->postRPCtoDo(expr.ast,
1208 false, // XXX = calculate cost - is this what we want?
1209 BPatch_thread::oneTimeCodeCallbackDispatch, // Callback
1210 (void *)info, // User data
1211 -1, // This isn't a metric definition - we shouldn't
1212 NULL, // No particular thread (yet),
1213 0, // Same -- no kernel thread
1218 proc->launchRPCifAppropriate(false, false);
1219 BPatch::bpatch->getThreadEvent(false);
1220 } while (!info->isCompleted() && !statusIsTerminated());
1222 void *ret = info->getReturnValue();
1226 continueExecution();
1230 proc->launchRPCifAppropriate(proc->status() == running, false);
1238 * BPatch_thread::loadLibrary
1240 * Load a dynamically linked library into the address space of the mutatee.
1242 * libname The name of the library to load.
1244 bool BPatch_thread::loadLibrary(char *libname, bool reload)
1246 #if defined(sparc_sun_solaris2_4) || defined(i386_unknown_solaris2_5) || \
1247 defined(i386_unknown_linux2_0) || defined(mips_sgi_irix6_4) || \
1248 defined(alpha_dec_osf4_0) || defined(rs6000_ibm_aix4_1) ||\
1249 defined(ia64_unknown_linux2_4) /* Temporary duplication - TLM */
1250 if (!statusIsStopped()) {
1253 BPatch_Vector<BPatch_snippet *> args;
1255 BPatch_constExpr nameArg(libname);
1256 // BPatch_constExpr modeArg(RTLD_NOW | RTLD_GLOBAL);
1258 args.push_back(&nameArg);
1259 // args.push_back(&modeArg);
1261 BPatch_function *dlopen_func = image->findFunction("DYNINSTloadLibrary");
1262 if (dlopen_func == NULL) return false;
1264 BPatch_funcCallExpr call_dlopen(*dlopen_func, args);
1266 if (!oneTimeCodeInternal(call_dlopen, NULL, true)) {
1268 // find the (global var) error string in the RT Lib and send it to the
1269 // error reporting mechanism
1270 BPatch_variableExpr *dlerror_str_var = image->findVariable("gLoadLibraryErrorString");
1271 assert(NULL != dlerror_str_var);
1273 char dlerror_str[256];
1274 dlerror_str_var->readValue((void *)dlerror_str, 256);
1275 BPatch_reportError(BPatchSerious, 124, dlerror_str);
1279 #ifdef BPATCH_LIBRARY //ccw 14 may 2002
1280 #if defined(sparc_sun_solaris2_4) || defined(i386_unknown_linux2_0)
1281 if(proc->collectSaveWorldData && reload){
1282 proc->saveWorldloadLibrary(libname);
1292 /** method that retrieves the line number and file name for a given
1293 * address. In failure it returns false. user is responsible to
1294 * to supply the buffer to write the file name and has to give the
1295 * size of the buffer available. The name of the file will be null
1296 * terminated by the program.
1298 bool BPatch_thread::getLineAndFile(unsigned long addr,unsigned short& lineNo,
1299 char* fileName,int size)
1301 if(!fileName || (size <= 0)){
1305 LineInformation* lineInformation = NULL;
1306 BPatch_Vector<BPatch_module*>* appModules = image->getModules();
1307 for(unsigned int i=0;i<appModules->size();i++){
1308 lineInformation = (*appModules)[i]->lineInformation;
1309 if(!lineInformation)
1311 for(int j=0;j<lineInformation->sourceFileCount;j++){
1312 string* fileN = lineInformation->sourceFileList[j];
1313 FileLineInformation* fInfo =
1314 lineInformation->lineInformationList[j];
1315 if(fInfo->getLineFromAddr(*fileN,lineNo,addr,true,false)){
1316 if(fileN->length() < (unsigned)size)
1317 size = fileN->length();
1318 strncpy(fileName,fileN->c_str(),size);
1319 fileName[size] = '\0';
1327 this function sets a flag in process that
1328 forces the collection of data for saveworld. //ccw 23 jan 2002
1330 void BPatch_thread::startSaveWorld(){
1331 proc->collectSaveWorldData=true;
1334 /***************************************************************************
1335 * BPatch_snippetHandle
1336 ***************************************************************************/
1339 * BPatchSnippetHandle::add
1341 * Add an instance of a snippet to the list of instances held by the
1342 * BPatchSnippetHandle.
1344 * instance The instance to add.
1346 void BPatchSnippetHandle::add(miniTrampHandle *pointInstance)
1348 mtHandles.push_back(pointInstance);
1353 * BPatchSnippetHandle::~BPatchSnippetHandle
1355 * Destructor for BPatchSnippetHandle. Delete the snippet instance(s)
1356 * associated with the BPatchSnippetHandle.
1358 BPatchSnippetHandle::~BPatchSnippetHandle()
1360 // don't delete inst instances since they are might have been copied
1363 #ifdef IBM_BPATCH_COMPAT
1364 bool BPatch_thread::addSharedObject(const char *name, const unsigned long loadaddr)
1366 // in IBM's code, this is a wrapper for _BPatch_thread->addSharedObject (linux)
1367 // which is in turn a wrapper for creating a new ibmBpatchElf32Reader(name, addr)
1369 fprintf(stderr, "%s[%d]: inside addSharedObject(%s, %lu), which is not properly implemented\n"
1370 "using loadLibrary(char* = %s)\n",
1371 __FILE__, __LINE__, name, loadaddr, name);
1373 return loadLibrary((char *)name);