Added BPatch_thread::oneTimeCode, BPatch_thread::loadLibrary, and other
[dyninst.git] / dyninstAPI / src / BPatch.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 <stdio.h>
43 #include <assert.h>
44 #include <signal.h>
45
46 #include "BPatch.h"
47 #include "BPatch_type.h"
48 #include "BPatch_libInfo.h"
49 #include "process.h"
50
51 #ifdef i386_unknown_nt4_0
52 #include "nt_signal_emul.h"
53 #endif
54
55 extern bool dyninstAPI_init();
56 extern int handleSigChild(int pid, int status);
57
58
59 BPatch *BPatch::bpatch = NULL;
60
61
62 /*
63  * BPatch::BPatch
64  *
65  * Constructor for BPatch.  Performs one-time initialization needed by the
66  * library.
67  */
68 BPatch::BPatch() : errorHandler(NULL), typeCheckOn(true)
69 {
70     extern bool init();
71     extern double cyclesPerSecond;
72     extern double timing_loop(const unsigned, const unsigned);
73
74     // Save a pointer to the one-and-only bpatch object.
75     if (bpatch == NULL)
76         bpatch = this;
77     /* XXX else
78      *  (indicate an error somehow)
79      */
80
81     // XXX dyninstAPI_init returns success/failure -- should pass on somehow
82     dyninstAPI_init();
83     cyclesPerSecond = timing_loop(1, 100000) * 1000000;
84
85     /*
86      * Create the library private info object.
87      */
88     info = new BPatch_libInfo;
89
90     /*
91      * Create the "error" and "untyped" types.
92      */
93     type_Error   = new BPatch_type("<error>", true);
94     type_Untyped = new BPatch_type("<no type>", true);
95
96     /*
97      * Initialize hash table of standard types.
98      */
99     stdTypes = new BPatch_typeCollection;
100     stdTypes->addType(new BPatch_type("int"));
101     stdTypes->addType(new BPatch_type("char *"));
102 }
103
104
105 /*
106  * BPatch::~BPatch
107  *
108  * Destructor for BPatch.  Free allocated memory.
109  */
110 BPatch::~BPatch()
111 {
112     delete info;
113
114     delete type_Error;
115     delete type_Untyped;
116
117     delete stdTypes;
118
119     bpatch = NULL;
120 }
121
122
123 /*
124  * BPatch::registerErrorCallback
125  *
126  * Registers a function that is to be called by the library when an error
127  * occurs or when there is status to report.  Returns the address of the
128  * previously registered error callback function.
129  *
130  * function     The function to be called.
131  */
132 BPatchErrorCallback BPatch::registerErrorCallback(BPatchErrorCallback function)
133 {
134     BPatchErrorCallback ret;
135
136     ret = errorHandler;
137     errorHandler = function;
138
139     return ret;
140 }
141
142
143 /*
144  * BPatch::getEnglishErrorString
145  *
146  * Returns the descriptive error string for the passed error number.
147  *
148  * number       The number that identifies the error.
149  */
150 const char *BPatch::getEnglishErrorString(int /* number */)
151 {
152     return "%s";
153 }
154
155
156 /*
157  * BPatch::reportError
158  *
159  * Report an error using the callback mechanism.
160  *
161  * severity     The severity level of the error.
162  * number       Identifies the error.
163  * str          A string to pass as the first element of the list of strings
164  *              given to the callback function.
165  */
166 void BPatch::reportError(BPatchErrorLevel severity, int number, const char *str)
167 {
168     if (severity != BPatchInfo)
169         lastError = number;
170
171     if (errorHandler != NULL) {
172         errorHandler(severity, number, &str);
173     }
174 }
175
176
177 /*
178  * BPatch::formatErrorString
179  *
180  * Takes a format string with an error message (obtained from
181  * getEnglishErrorString) and an array of parameters that were passed to an
182  * error callback function, and creates a string with the parameters
183  * substituted into it.
184  *
185  * dst          The address into which the formatted string should be copied.
186  * size         If the formatted string is equal to or longer than this number
187  *              of characters, then it will be truncated to size-1 characters
188  *              and terminated with a nul ('\0').
189  * fmt          The format string (returned by a function such as
190  *              getEnglishErrorString).
191  * params       The array of parameters that were passed to an error callback
192  *              function.
193  */
194 void BPatch::formatErrorString(char *dst, int size,
195                                const char *fmt, const char **params)
196 {
197     int cur_param = 0;
198
199     while (size > 1 && *fmt) {
200         if (*fmt == '%') {
201             if (fmt[1] == '\0') {
202                 break;
203             } else if (fmt[1] == '%') {
204                 *dst++ = '%';
205                 size--;
206             } else if (fmt[1] == 's') {
207                 char *p = (char *)params[cur_param++];
208                 while (size > 1 && *p) {
209                     *dst++ = *p++;
210                     size--;
211                 }
212             } else {
213                 // Illegal specifier
214                 *dst++ = fmt[0];
215                 *dst++ = fmt[1];
216                 size -= 2;
217             }
218             fmt += 2;
219         } else {
220             *dst++ = *fmt++;
221             size--;
222         }
223     }
224     if (size > 0)
225         *dst = '\0';
226 }
227
228
229 /*
230  * BPatch::getThreadByPid
231  *
232  * Given a process ID, this function returns a pointer to the associated
233  * BPatch_thread object (or NULL if there is none).  Since a process may be
234  * registered provisionally with a thread object pointer of NULL, the boolean
235  * pointed to by the parameter "exists" is set to true if the pid exists in
236  * the table of processes, and false if it does not.
237  *
238  * pid          The pid to look up.
239  * exists       A pointer to a boolean to fill in with true if the pid exists
240  *              in the table and false if it does not.  NULL may be passed in
241  *              if this information is not required.
242  */
243 BPatch_thread *BPatch::getThreadByPid(int pid, bool *exists)
244 {
245     if (info->threadsByPid.defines(pid)) {
246         if (exists) *exists = true;
247         return info->threadsByPid[pid];
248     } else {
249         if (exists) *exists = false;
250         return NULL;
251     }
252 }
253
254
255 /*
256  * BPatch::getThreads
257  *
258  * Returns a vector of all threads that are currently defined.  Includes
259  * threads created directly using the library and those created with UNIX fork
260  * or Windows NT spawn system calls.  The caller is responsible for deleting
261  * the vector when it is no longer needed.
262  */
263 BPatch_Vector<BPatch_thread *> *BPatch::getThreads()
264 {
265     BPatch_Vector<BPatch_thread *> *result = new BPatch_Vector<BPatch_thread *>;
266
267     dictionary_hash_iter<int, BPatch_thread *> ti(info->threadsByPid);
268
269     int pid;
270     BPatch_thread *thread;
271
272     while (ti.next(pid, thread))
273         result->push_back(thread);
274
275     return result;
276 }
277
278
279 /*
280  * BPatch::registerProvisionalThread
281  *
282  * Register a new process that is not yet associated with a thread.
283  * (this function is called only by createProcess).
284  *
285  * pid          The pid of the process to register.
286  */
287 void BPatch::registerProvisionalThread(int pid)
288 {
289     assert(!info->threadsByPid.defines(pid));
290     info->threadsByPid[pid] = NULL;
291 }
292
293
294 /*
295  * BPatch::registerThread
296  *
297  * Register a new BPatch_thread object with the BPatch library (this function
298  * is called only by the constructor for BPatch_thread).
299  *
300  * thread       A pointer to the thread to register.
301  */
302 void BPatch::registerThread(BPatch_thread *thread)
303 {
304     assert(!info->threadsByPid.defines(thread->getPid()) ||
305             info->threadsByPid[thread->getPid()] == NULL);
306     info->threadsByPid[thread->getPid()] = thread;
307 }
308
309
310 /*
311  * BPatch::unRegisterThread
312  *
313  * Remove the BPatch_thread associated with a given pid from the list of
314  * threads being managed by the library.
315  *
316  * pid          The pid of the thread to be removed.
317  */
318 void BPatch::unRegisterThread(int pid)
319 {
320     assert(info->threadsByPid.defines(pid));
321     info->threadsByPid.undef(pid);      
322 }
323
324
325 /*
326  * BPatch::createProcess
327  *
328  * Create a process and return a BPatch_thread representing it.
329  * Returns NULL upon failure.
330  *
331  * path         The pathname of the executable for the new process.
332  * argv         A list of the arguments for the new process, terminated by a
333  *              NULL.
334  * envp         A list of values that make up the environment for the new
335  *              process, terminated by a NULL.  If envp is NULL, the new
336  *              new process will inherit the environemnt of the parent.
337  */
338 BPatch_thread *BPatch::createProcess(char *path, char *argv[], char *envp[])
339 {
340     clearError();
341
342     BPatch_thread *ret = new BPatch_thread(path, argv, envp);
343
344     if (getLastError()) {
345         delete ret;
346         return NULL;
347     }
348
349     return ret;
350 }
351
352
353 /*
354  * BPatch::attachProcess
355  *
356  * Attach to a running pprocess and return a BPatch_thread representing it.
357  * Returns NULL upon failure.
358  *
359  * path         The pathname of the executable for the process.
360  * pid          The id of the process to attach to.
361  */
362 BPatch_thread *BPatch::attachProcess(char *path, int pid)
363 {
364     clearError();
365
366     BPatch_thread *ret = new BPatch_thread(path, pid);
367
368     if (getLastError()) {
369         delete ret;
370         return NULL;
371     }
372
373     return ret;
374 }
375
376
377 /*
378  * getThreadEvent
379  *
380  * Checks for changes in any child process, and optionally blocks until such a
381  * change has occurred.  Also updates the process object representing each
382  * process for which a change is detected.  The return value is true if a
383  * change was detected, otherwise it is false.
384  *
385  * block        Set this parameter to true to block waiting for a change,
386  *              set to false to poll and return immediately, whether or not a
387  *              change occurred.
388  */
389 bool BPatch::getThreadEvent(bool block)
390 {
391     bool        result = false;
392     int         pid, status;
393
394     while ((pid = process::waitProcs(&status, block)) > 0) {
395         // There's been a change in a child process
396         result = true;
397         // Since we found something, we don't want to block anymore
398         block = false;
399
400         bool exists;
401         BPatch_thread *thread = getThreadByPid(pid, &exists);
402         if (thread == NULL) {
403             if (exists) {
404                 if (WIFSIGNALED(status) || WIFEXITED(status))
405                     unRegisterThread(pid);
406             } else {
407                 fprintf(stderr, "Warning - wait returned status of an unknown process (%d)\n", pid);
408             }
409         }
410         if (thread != NULL) {
411             if (WIFSTOPPED(status)) {
412                 thread->lastSignal = WSTOPSIG(status);
413                 thread->setUnreportedStop(true);
414             } else if (WIFSIGNALED(status)) {
415                 thread->lastSignal = WTERMSIG(status);
416                 thread->setUnreportedTermination(true);
417             } else if (WIFEXITED(status)) {
418                 thread->lastSignal = 0; /* XXX Make into some constant */
419                 thread->setUnreportedTermination(true);
420             }
421         }
422 #ifndef i386_unknown_nt4_0
423         handleSigChild(pid, status);
424 #endif
425     }
426
427     return result;
428 }
429
430
431 /*
432  * havePendingEvent
433  *
434  * Returns true if any thread has stopped or terminated and that fact hasn't
435  * been reported to the user of the library.  Otherwise, returns false.
436  */
437 bool BPatch::havePendingEvent()
438 {
439 #ifdef i386_unknown_nt4_0
440     // On NT, we need to poll for events as often as possible, so that we can
441     // handle traps.
442     if (getThreadEvent(false))
443         return true;
444 #endif
445
446     // For now, we'll do it by iterating over the threads and checking them,
447     // and we'll change it to something more efficient later on.
448     dictionary_hash_iter<int, BPatch_thread *> ti(info->threadsByPid);
449
450     int pid;
451     BPatch_thread *thread;
452
453     while (ti.next(pid, thread)) {
454         if (thread != NULL &&
455             (thread->pendingUnreportedStop() ||
456              thread->pendingUnreportedTermination())) {
457             return true;
458         }
459     }
460
461     return false;
462 }
463
464
465 /*
466  * pollForStatusChange
467  *
468  * Checks for unreported changes to the status of any child process, and
469  * returns true if any are detected.  Returns false otherwise.
470  *
471  * This function is declared as a friend of BPatch_thread so that it can use
472  * the BPatch_thread::getThreadEvent call to check for status changes.
473  */
474 bool pollForStatusChange()
475 {
476     // First, check if there are any unreported changes that have already been
477     // detected.
478     assert(BPatch::bpatch);
479     if (BPatch::bpatch->havePendingEvent())
480         return true;
481   
482     // No changes were previously detected, so check for new changes
483     return BPatch::bpatch->getThreadEvent(false);
484 }
485
486
487 /*
488  * waitForStatusChange
489  *
490  * Blocks waiting for a change to occur in the running status of a child
491  * process.  Returns true upon success, false upon failure.
492  *
493  * This function is declared as a friend of BPatch_thread so that it can use
494  * the BPatch_thread::getThreadEvent call to check for status changes.
495  */
496 bool waitForStatusChange()
497 {
498     // First, check if there are any unreported changes that have already been
499     // detected.
500     assert(BPatch::bpatch);
501     if (BPatch::bpatch->havePendingEvent())
502         return true;
503
504     // No changes were previously detected, so wait for a new change
505     return BPatch::bpatch->getThreadEvent(true);
506 }