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.
47 #include "BPatch_thread.h"
50 extern process *createProcess(const string File,
51 vector<string> argv, vector<string> envp, const string dir = "");
52 extern process *attachProcess(const string &progpath, int pid, int afterAttach);
56 * BPatch_thread::getPid
58 * Return the process ID of the thread associated with this object.
60 int BPatch_thread::getPid()
62 return proc->getPid();
67 * BPatch_thread::BPatch_thread
69 * Starts a new process and associates it with the BPatch_thread being
70 * constructed. The new process is placed into a stopped state before
73 * path Pathname of the executable to start.
74 * argv A list of pointers to character strings which are the
75 * arguments for the new process, terminated by a NULL pointer.
76 * envp A list of pointers to character strings which are to be
77 * passed to the new process as its environment, terminated by a
78 * NULL pointer. If envp is NULL, the parent's environment is
79 * copied and passed to the child.
81 BPatch_thread::BPatch_thread(char *path, char *argv[], char *envp[])
82 : lastSignal(-1), mutationsActive(true), createdViaAttach(false),
85 vector<string> argv_vec;
86 vector<string> envp_vec;
88 // Contruct a vector out of the contents of argv
89 for(int i = 0; argv[i] != NULL; i++)
92 // Construct a vector out of the contents of envp
94 for(int i = 0; envp[i] != NULL; i++)
98 proc = createProcess(path, argv_vec, envp_vec, "");
100 // XXX Should do something more sensible.
101 if (proc == NULL) return;
103 // Add this object to the list of threads
104 // XXX Should be conditional on success of creating process
105 assert(BPatch::bpatch != NULL);
106 BPatch::bpatch->registerThread(this);
108 image = new BPatch_image(proc);
110 while (!proc->isBootstrappedYet() && !isTerminated())
111 pollForStatusChange();
116 * BPatch_thread::BPatch_thread
118 * Constructs a new BPatch_thread and associates it with a running process.
119 * Stops execution of the process.
121 * path Pathname of the executable file for the process.
122 * pid Process ID of the target process.
124 BPatch_thread::BPatch_thread(char *path, int pid)
125 : lastSignal(-1), mutationsActive(true), createdViaAttach(true),
128 if (!attachProcess(path, pid, 1, proc)) {
129 // XXX Should do something more sensible
134 // Add this object to the list of threads
135 assert(BPatch::bpatch != NULL);
136 BPatch::bpatch->registerThread(this);
138 image = new BPatch_image(proc);
140 while (!proc->isBootstrappedYet() && !isTerminated()) {
141 pollForStatusChange();
142 proc->launchRPCifAppropriate(false, false);
148 * BPatch_thread::~BPatch_thread
150 * Destructor for BPatch_thread. Detaches from the running thread.
152 BPatch_thread::~BPatch_thread()
155 if (createdViaAttach)
156 proc->API_detach(true);
158 terminateExecution();
161 assert(BPatch::bpatch != NULL);
162 BPatch::bpatch->unRegisterThread(getPid());
164 // XXX I think there are some other things we need to deallocate -- check
172 * BPatch_thread::stopExecution
174 * Puts the thread into the stopped state.
176 bool BPatch_thread::stopExecution()
178 pollForStatusChange();
180 return proc->pause();
185 * BPatch_thread::continueExecution
187 * Puts the thread into the running state.
189 bool BPatch_thread::continueExecution()
191 pollForStatusChange();
193 return proc->continueProc();
198 * BPatch_thread::continueExecution
200 * Puts the thread into the running state.
202 bool BPatch_thread::terminateExecution()
204 if (!proc->terminateProc())
207 // Wait for the process to die
208 while (!isTerminated()) ;
213 * BPatch_thread::isStopped
215 * Returns true if the thread is stopped, and false if it is not.
217 bool BPatch_thread::isStopped()
219 pollForStatusChange();
221 return proc->status() == stopped;
226 * BPatch_thread::stopSignal
228 * Returns the number of the signal which caused the thread to stop.
230 int BPatch_thread::stopSignal()
232 if (proc->status() != neonatal && proc->status() != stopped)
240 * BPatch_thread::isTerminated
242 * Returns true if the process has terminated, false if it has not.
244 bool BPatch_thread::isTerminated()
246 if (proc == NULL) return true;
247 pollForStatusChange();
249 return proc->status() == exited;
254 * BPatch_thread::detach
256 * Detach from the thread represented by this object.
258 * cont True if the thread should be continued as the result of the
259 * detach, false if it should not.
261 void BPatch_thread::detach(bool cont)
263 proc->API_detach(cont);
270 * BPatch_thread::dumpCore
272 * Causes the thread to dump its state to a file, and optionally to terminate.
273 * Returns true upon success, and false upon failure.
275 * file The name of the file to which the state should be written.
276 * terminate Indicates whether or not the thread should be terminated after
277 * dumping core. True indicates that it should, false that is
280 bool BPatch_thread::dumpCore(const char *file, bool terminate)
283 if (isStopped()) was_stopped = true;
284 else was_stopped = false;
288 bool ret = proc->dumpCore(file);
289 if (ret && terminate) {
290 terminateExecution();
291 } else if (!was_stopped) {
300 * BPatch_thread::malloc
302 * Allocate memory in the thread's address space.
304 * n The number of bytes to allocate.
307 * A pointer to a BPatch_variableExpr representing the memory.
309 * XXX Should return NULL on failure, but the function which it calls,
310 * inferiorMalloc, calls exit rather than returning an error, so this
311 * is not currently possible.
313 BPatch_variableExpr *BPatch_thread::malloc(int n)
315 // XXX What to do about the type?
316 assert(BPatch::bpatch != NULL);
317 return new BPatch_variableExpr(
318 (void *)inferiorMalloc(proc, n, dataHeap),
319 BPatch::bpatch->type_Untyped);
324 * BPatch_thread::malloc
326 * Allocate memory in the thread's address space for a variable of the given
329 * type The type of variable for which to allocate space.
332 * A pointer to a BPatch_variableExpr representing the memory.
334 * XXX Should return NULL on failure, but the function which it calls,
335 * inferiorMalloc, calls exit rather than returning an error, so this
336 * is not currently possible.
338 BPatch_variableExpr *BPatch_thread::malloc(const BPatch_type &type)
341 * XXX For now, the only type that will work is "int."
343 void *mem = (void *)inferiorMalloc(proc, sizeof(int), dataHeap);
345 /* XXX At least for now, the memory is initially filled with zeroes. */
347 proc->writeDataSpace((char *)mem, sizeof(int), (char *)&zero);
349 return new BPatch_variableExpr(mem, &type);
354 * BPatch_thread::free
356 * Free memory that was allocated with BPatch_thread::malloc.
358 * ptr A BPatch_variableExpr representing the memory to free.
360 void BPatch_thread::free(const BPatch_variableExpr &ptr)
362 vector<unsigVecType> pointsToCheck; // We'll leave this empty
364 inferiorFree(proc, (unsigned)ptr.getAddress(), dataHeap, pointsToCheck);
369 * BPatch_thread::insertSnippet
371 * Insert a code snippet at a given instrumentation point. Upon succes,
372 * returns a handle to the created instance of the snippet, which can be used
373 * to delete it. Otherwise returns NULL.
375 * expr The snippet to insert.
376 * point The point at which to insert it.
378 BPatchSnippetHandle *BPatch_thread::insertSnippet(const BPatch_snippet &expr,
379 const BPatch_point &point,
380 BPatch_callWhen when,
381 BPatch_snippetOrder order)
383 BPatch_Vector<BPatch_point *> point_vec;
385 point_vec.push_back((BPatch_point *)&point);
387 return insertSnippet(expr, point_vec, when, order);
392 * BPatch_thread::insertSnippet
394 * Insert a code snippet at each of a list of instrumentation points. Upon
395 * success, Returns a handle to the created instances of the snippet, which
396 * can be used to delete them (as a unit). Otherwise returns NULL.
398 * expr The snippet to insert.
399 * points The list of points at which to insert it.
401 BPatchSnippetHandle *BPatch_thread::insertSnippet(
402 const BPatch_snippet &expr,
403 const BPatch_Vector<BPatch_point *> &points,
404 BPatch_callWhen when,
405 BPatch_snippetOrder order)
407 // Can't insert code when mutations are not active.
408 if (!mutationsActive)
415 case BPatch_callBefore:
418 case BPatch_callAfter:
419 _when = callPostInsn;
426 case BPatch_firstSnippet:
427 _order = orderFirstAtPoint;
429 case BPatch_lastSnippet:
430 _order = orderLastAtPoint;
436 assert(BPatch::bpatch != NULL); // We'll use this later
438 BPatchSnippetHandle *handle = new BPatchSnippetHandle(proc);
440 for (int i = 0; i < points.size(); i++) {
441 instPoint *point = (instPoint *)points[i]->point; // Cast away const
443 // XXX Really only need to type check once per function the snippet is
444 // being inserted into, not necessarily once per point.
445 if (expr.ast->checkType() == BPatch::bpatch->type_Error) {
446 // XXX Type check error - should call callback
451 // XXX We just pass false for the "noCost" parameter here - do we want
452 // to make that an option?
453 instInstance *instance;
457 ((BPatch_snippet)expr).ast, /* XXX no const */
461 handle->add(instance);
472 * BPatch_thread::deleteSnippet
474 * Deletes an instance of a snippet.
476 * handle The handle returned by insertSnippet when the instance to
477 * deleted was created.
479 bool BPatch_thread::deleteSnippet(BPatchSnippetHandle *handle)
481 if (handle->proc == proc) {
484 } else { // Handle isn't to a snippet instance in this process
491 * BPatch_thread::setMutationsActive
493 * Enable or disable the execution of all snippets for the thread.
495 * activate If set to true, execution of snippets is enabled. If false,
496 * execution is disabled.
498 void BPatch_thread::setMutationsActive(bool activate)
500 // If not activating or deactivating, just return.
501 if ((activate && mutationsActive) || (!activate && !mutationsActive))
505 // The old implementation
506 dictionary_hash_iter<const instPoint*, trampTemplate *> bmi(proc->baseMap);
508 const instPoint *point;
509 trampTemplate *tramp;
511 while (bmi.next(point, tramp)) {
514 if (tramp->retInstance != NULL) {
516 tramp->retInstance->installReturnInstance(proc);
518 tramp->retInstance->unInstallReturnInstance(proc);
524 proc->reinstallMutations();
526 proc->uninstallMutations();
528 mutationsActive = activate;
533 * BPatch_thread::replaceFunctionCall
535 * Replace a function call with a call to a different function. Returns true
536 * upon success, false upon failure.
538 * point The call site that is to be changed.
539 * newFunc The function that the call site will now call.
541 bool BPatch_thread::replaceFunctionCall(BPatch_point &point,
542 BPatch_function &newFunc)
544 // Can't make changes to code when mutations are not active.
545 if (!mutationsActive)
548 assert(point.point && newFunc.func);
550 return proc->replaceFunctionCall(point.point, newFunc.func);
555 * BPatch_thread::removeFunctionCall
557 * Replace a function call with a NOOP. Returns true upon success, false upon
560 * point The call site that is to be NOOPed out.
562 bool BPatch_thread::removeFunctionCall(BPatch_point &point)
564 // Can't make changes to code when mutations are not active.
565 if (!mutationsActive)
570 return proc->replaceFunctionCall(point.point, NULL);
574 /***************************************************************************
575 * BPatch_snippetHandle
576 ***************************************************************************/
579 * BPatchSnippetHandle::add
581 * Add an instance of a snippet to the list of instances held by the
582 * BPatchSnippetHandle.
584 * instance The instance to add.
586 void BPatchSnippetHandle::add(instInstance *pointInstance)
588 assert(pointInstance->proc == proc);
589 instance.push_back(pointInstance);
594 * BPatchSnippetHandle::~BPatchSnippetHandle
596 * Destructor for BPatchSnippetHandle. Delete the snippet instance(s)
597 * associated with the BPatchSnippetHandle.
599 BPatchSnippetHandle::~BPatchSnippetHandle()
601 for (int i = 0; i < instance.size(); i++)
602 deleteInst(instance[i], getAllTrampsAtPoint(instance[i]));