Added features to dyninstAPI library, including the ability to delete
[dyninst.git] / dyninstAPI / src / BPatch_thread.C
1 /*
2  * Copyright (c) 1996 Barton P. Miller
3  * 
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.
10  * 
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.
17  * 
18  * (for other uses, please contact us at paradyn@cs.wisc.edu)
19  * 
20  * All warranties, including without limitation, any warranty of
21  * merchantability or fitness for a particular purpose, are hereby
22  * excluded.
23  * 
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.
29  * 
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.
40  */
41
42 #include "process.h"
43 #include "inst.h"
44 #include "instP.h"
45
46 #include "BPatch.h"
47 #include "BPatch_thread.h"
48
49 extern process *dyninstAPI_createProcess(const string File,
50         vector<string> argv, vector<string> envp, const string dir = "");
51 extern process *dyninstAPI_attachProcess(const string &progpath, int pid,
52         int afterAttach);
53
54
55 /*
56  * BPatch_thread::getPid
57  *
58  * Return the process ID of the thread associated with this object.
59  */
60 int BPatch_thread::getPid()
61 {
62     return proc->getPid();
63 }
64
65
66 /*
67  * BPatch_thread::BPatch_thread
68  *
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
71  * executing any code.
72  *
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.
80  */
81 BPatch_thread::BPatch_thread(char *path, char *argv[], char *envp[])
82     : lastSignal(-1)
83 {
84     vector<string> argv_vec;
85     vector<string> envp_vec;
86
87     // Contruct a vector out of the contents of argv
88     for(int i = 0; argv[i] != NULL; i++)
89         argv_vec += argv[i];
90
91     // Construct a vector out of the contents of envp
92     if (envp != NULL) {
93         for(int i = 0; envp[i] != NULL; i++)
94             envp_vec += envp[i];
95     }
96
97     proc = dyninstAPI_createProcess(path, argv_vec, envp_vec, "");
98
99     // XXX Should do something more sensible.
100     if (proc == NULL) return;
101
102     // Add this object to the list of threads
103     // XXX Should be conditional on success of creating process
104     assert(BPatch::bpatch != NULL);
105     BPatch::bpatch->registerThread(this);
106
107     image = new BPatch_image(proc);
108 }
109
110
111 /*
112  * BPatch_thread::BPatch_thread
113  *
114  * Constructs a new BPatch_thread and associates it with a running process.
115  * Stops execution of the process.
116  *
117  * path         Pathname of the executable file for the process.
118  * pid          Process ID of the target process.
119  */
120 BPatch_thread::BPatch_thread(char *path, int pid)
121     : lastSignal(-1)
122 {
123     proc = dyninstAPI_attachProcess(path, pid, 1);
124
125     // XXX Should do something more sensible
126     if (proc == NULL) return;
127
128     // Add this object to the list of threads
129     assert(BPatch::bpatch != NULL);
130     BPatch::bpatch->registerThread(this);
131
132     image = new BPatch_image(proc);
133 }
134
135
136 /*
137  * BPatch_thread::~BPatch_thread
138  *
139  * Destructor for BPatch_thread.  Detaches from the running thread.
140  */
141 BPatch_thread::~BPatch_thread()
142 {
143     // Detach from the thread
144     proc->detach(FALSE);
145
146     // XXX Should also deallocate memory and remove process ID from
147     //     the map of process IDs to thread objects.
148 }
149
150
151 /*
152  * BPatch_thread::stopExecution
153  *
154  * Puts the thread into the stopped state.
155  */
156 bool BPatch_thread::stopExecution()
157 {
158     pollForStatusChange();
159
160     return proc->pause();
161 }
162
163
164 /*
165  * BPatch_thread::continueExecution
166  *
167  * Puts the thread into the running state.
168  */
169 bool BPatch_thread::continueExecution()
170 {
171     pollForStatusChange();
172
173     return proc->continueProc();
174 }
175
176
177 /*
178  * BPatch_thread::continueExecution
179  *
180  * Puts the thread into the running state.
181  */
182 bool BPatch_thread::terminateExecution()
183 {
184     return P_kill(getPid(), SIGKILL);
185 }
186
187
188 /*
189  * BPatch_thread::isStopped
190  *
191  * Returns true if the thread is stopped, and false if it is not.
192  */
193 bool BPatch_thread::isStopped()
194 {
195     pollForStatusChange();
196
197     return proc->status() == neonatal || proc->status() == stopped;
198 }
199
200
201 /*
202  * BPatch_thread::stopSignal
203  *
204  * Returns the number of the signal which caused the thread to stop.
205  */
206 int BPatch_thread::stopSignal()
207 {
208     if (proc->status() != neonatal && proc->status() != stopped)
209         return -1;
210     else
211         return lastSignal;
212 }
213
214
215 /*
216  * BPatch_thread::isTerminated
217  *
218  * Returns true if the process has terminated, false if it has not.
219  */
220 bool BPatch_thread::isTerminated()
221 {
222     if (proc == NULL) return true;
223
224     pollForStatusChange();
225
226     return proc->status() == exited;
227 }
228
229
230 /*
231  * BPatch_thread::detach
232  *
233  * Detach from the thread represented by this object.
234  *
235  * cont         True if the thread should be continued as the result of the
236  *              detach, false if it should not.
237  */
238 void BPatch_thread::detach(bool cont)
239 {
240     proc->detach(cont);
241 }
242
243
244 /*
245  * BPatch_thread::dumpCore
246  *
247  * Causes the thread to dump its state to a file, and optionally to terminate.
248  * Returns true upon success, and false upon failure.
249  *
250  * file         The name of the file to which the state should be written.
251  * terminate    Indicates whether or not the thread should be terminated after
252  *              dumping core.  True indicates that it should, false that is
253  *              should not.
254  */
255 bool BPatch_thread::dumpCore(const char *file, bool terminate)
256 {
257     bool was_stopped;
258     if (isStopped()) was_stopped = true;
259     else was_stopped = false;
260
261     stopExecution();
262
263     bool ret = proc->dumpCore(file);
264     if (ret && terminate) {
265         terminateExecution();
266     } else if (!was_stopped) {
267         continueExecution();
268     }
269
270     return ret;
271 }
272
273
274 /*
275  * BPatch_thread::malloc
276  *
277  * Allocate memory in the thread's address space.
278  *
279  * n    The number of bytes to allocate.
280  *
281  * Returns:
282  *      A pointer to a BPatch_variableExpr representing the memory.
283  *
284  * XXX Should return NULL on failure, but the function which it calls,
285  *     inferiorMalloc, calls exit rather than returning an error, so this
286  *     is not currently possible.
287  */
288 BPatch_variableExpr *BPatch_thread::malloc(int n)
289 {
290     // XXX What to do about the type?
291     assert(BPatch::bpatch != NULL);
292     return new BPatch_variableExpr(
293             (void *)inferiorMalloc(proc, n, dataHeap),
294             BPatch::bpatch->type_Untyped);
295 }
296
297
298 /*
299  * BPatch_thread::malloc
300  *
301  * Allocate memory in the thread's address space for a variable of the given
302  * type.
303  *
304  * type         The type of variable for which to allocate space.
305  *
306  * Returns:
307  *      A pointer to a BPatch_variableExpr representing the memory.
308  *
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.
312  */
313 BPatch_variableExpr *BPatch_thread::malloc(const BPatch_type &type)
314 {
315     /*
316      * XXX For now, the only type that will work is "int."
317      */
318     void *mem = (void *)inferiorMalloc(proc, sizeof(int), dataHeap);
319
320     /* XXX At least for now, the memory is initially filled with zeroes. */
321     int zero = 0;
322     proc->writeDataSpace((char *)mem, sizeof(int), (char *)&zero);
323
324     return new BPatch_variableExpr(mem, &type);
325 }
326
327
328 /*
329  * BPatch_thread::free
330  *
331  * Free memory that was allocated with BPatch_thread::malloc.
332  *
333  * ptr          A BPatch_variableExpr representing the memory to free.
334  */
335 void BPatch_thread::free(const BPatch_variableExpr &ptr)
336 {
337     vector<unsigVecType> pointsToCheck; // We'll leave this empty
338
339     inferiorFree(proc, (unsigned)ptr.getAddress(), dataHeap, pointsToCheck);
340 }
341
342
343 /*
344  * BPatch_thread::insertSnippet
345  *
346  * Insert a code snippet at a given instrumentation point.  Upon succes,
347  * returns a handle to the created instance of the snippet, which can be used
348  * to delete it.  Otherwise returns NULL.
349  *
350  * expr         The snippet to insert.
351  * point        The point at which to insert it.
352  */
353 BPatchSnippetHandle *BPatch_thread::insertSnippet(const BPatch_snippet &expr,
354                                                   const BPatch_point &point,
355                                                   BPatch_callWhen when,
356                                                   BPatch_snippetOrder order)
357 {
358     BPatch_Vector<BPatch_point *> point_vec;
359
360     point_vec.push_back((BPatch_point *)&point);
361
362     return insertSnippet(expr, point_vec, when, order);
363 }
364
365
366 /*
367  * BPatch_thread::insertSnippet
368  *
369  * Insert a code snippet at each of a list of instrumentation points.  Upon
370  * success, Returns a handle to the created instances of the snippet, which
371  * can be used to delete them (as a unit).  Otherwise returns NULL.
372  *
373  * expr         The snippet to insert.
374  * points       The list of points at which to insert it.
375  */
376 BPatchSnippetHandle *BPatch_thread::insertSnippet(
377                                     const BPatch_snippet &expr,
378                                     const BPatch_Vector<BPatch_point *> &points,
379                                     BPatch_callWhen when,
380                                     BPatch_snippetOrder order)
381 {
382     callWhen    _when;
383     callOrder   _order;
384
385     switch (when) {
386       case BPatch_callBefore:
387         _when = callPreInsn;
388         break;
389       case BPatch_callAfter:
390         _when = callPostInsn;
391         break;
392       default:
393         return NULL;
394     };
395
396     switch (order) {
397       case BPatch_firstSnippet:
398         _order = orderFirstAtPoint;
399         break;
400       case BPatch_lastSnippet:
401         _order = orderLastAtPoint;
402         break;
403       default:
404         return NULL;
405     }
406
407     assert(BPatch::bpatch != NULL);     // We'll use this later
408
409     BPatchSnippetHandle *handle = new BPatchSnippetHandle(proc);
410
411     for (int i = 0; i < points.size(); i++) {
412         instPoint *point = points[i]->point;
413
414         // XXX Really only need to type check once per function the snippet is
415         // being inserted into, not necessarily once per point.
416         if (expr.ast->checkType() == BPatch::bpatch->type_Error) {
417             // XXX Type check error - should call callback
418             delete handle;
419             return NULL;
420         }
421
422         // XXX We just pass false for the "noCost" parameter here - do we want
423         // to make that an option?
424         instInstance *instance; 
425         if ((instance =
426                 addInstFunc(proc,
427                             point,
428                             ((BPatch_snippet)expr).ast,  /* XXX no const */
429                             _when,
430                             _order,
431                             false)) != NULL) {
432             handle->add(instance);
433         } else {
434             delete handle;
435             return NULL;
436         }
437     }
438     return handle;
439 }
440
441
442 /*
443  * BPatch_thread::deleteSnippet
444  * 
445  * Deletes an instance of a snippet.
446  *
447  * handle       The handle returned by insertSnippet when the instance to
448  *              deleted was created.
449  */
450 bool BPatch_thread::deleteSnippet(BPatchSnippetHandle *handle)
451 {
452     if (handle->proc == proc) {
453         delete handle;
454         return true;
455     } else { // Handle isn't to a snippet instance in this process
456         return false;
457     }
458 }
459
460
461 /*
462  * BPatchSnippetHandle::add
463  *
464  * Add an instance of a snippet to the list of instances held by the
465  * BPatchSnippetHandle.
466  *
467  * instance     The instance to add.
468  */
469 void BPatchSnippetHandle::add(instInstance *pointInstance)
470 {
471     assert(pointInstance->proc == proc);
472     instance.push_back(pointInstance);
473 }
474
475
476 /*
477  * BPatchSnippetHandle::~BPatchSnippetHandle
478  *
479  * Destructor for BPatchSnippetHandle.  Delete the snippet instance(s)
480  * associated with the BPatchSnippetHandle.
481  */
482 BPatchSnippetHandle::~BPatchSnippetHandle()
483 {
484     for (int i = 0; i < instance.size(); i++)
485         deleteInst(instance[i], getAllTrampsAtPoint(instance[i]));
486 }