Eliminated warning when a process was created but not registered as a
[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 #include <sys/wait.h>
46
47 #include "BPatch.h"
48 #include "BPatch_type.h"
49 #include "BPatch_libInfo.h"
50 #include "process.h"
51
52 extern bool dyninstAPI_init();
53 extern int handleSigChild(int pid, int status);
54
55
56 BPatch *BPatch::bpatch = NULL;
57
58
59 /*
60  * BPatch::BPatch
61  *
62  * Constructor for BPatch.  Performs one-time initialization needed by the
63  * library.
64  */
65 BPatch::BPatch() : errorHandler(NULL), typeCheckOn(true)
66 {
67     extern bool init();
68     extern double cyclesPerSecond;
69     extern double timing_loop(const unsigned, const unsigned);
70
71     // Save a pointer to the one-and-only bpatch object.
72     if (bpatch == NULL)
73         bpatch = this;
74     /* XXX else
75      *  (indicate an error somehow)
76      */
77
78     // XXX dyninstAPI_init returns success/failure -- should pass on somehow
79     dyninstAPI_init();
80     cyclesPerSecond = timing_loop(1, 100000) * 1000000;
81
82     /*
83      * Create the library private info object.
84      */
85     info = new BPatch_libInfo;
86
87     /*
88      * Create the "error" and "untyped" types.
89      */
90     type_Error   = new BPatch_type("<error>", true);
91     type_Untyped = new BPatch_type("<no type>", true);
92
93     /*
94      * Initialize hash table of standard types.
95      */
96     stdTypes = new BPatch_typeCollection;
97     stdTypes->addType(new BPatch_type("int"));
98     stdTypes->addType(new BPatch_type("char *"));
99 }
100
101
102 /*
103  * BPatch::~BPatch
104  *
105  * Destructor for BPatch.  Free allocated memory.
106  */
107 BPatch::~BPatch()
108 {
109     delete info;
110
111     delete type_Error;
112     delete type_Untyped;
113
114     delete stdTypes;
115
116     bpatch = NULL;
117 }
118
119
120 /*
121  * BPatch::registerErrorCallback
122  *
123  * Registers a function that is to be called by the library when an error
124  * occurs or when there is status to report.  Returns the address of the
125  * previously registered error callback function.
126  *
127  * function     The function to be called.
128  */
129 BPatchErrorCallback BPatch::registerErrorCallback(BPatchErrorCallback function)
130 {
131     BPatchErrorCallback ret;
132
133     ret = errorHandler;
134     errorHandler = function;
135
136     return ret;
137 }
138
139
140 /*
141  * BPatch::getEnglishErrorString
142  *
143  * Returns the descriptive error string for the passed error number.
144  *
145  * number       The number that identifies the error.
146  */
147 const char *BPatch::getEnglishErrorString(int /* number */)
148 {
149     return "%s";
150 }
151
152
153 /*
154  * BPatch::reportError
155  *
156  * Report an error using the callback mechanism.
157  *
158  * severity     The severity level of the error.
159  * number       Identifies the error.
160  * str          A string to pass as the first element of the list of strings
161  *              given to the callback function.
162  */
163 void BPatch::reportError(BPatchErrorLevel severity, int number, const char *str)
164 {
165     if (errorHandler != NULL) {
166         errorHandler(severity, number, &str);
167     }
168 }
169
170
171 /*
172  * BPatch::formatErrorString
173  *
174  * Takes a format string with an error message (obtained from
175  * getEnglishErrorString) and an array of parameters that were passed to an
176  * error callback function, and creates a string with the parameters
177  * substituted into it.
178  *
179  * dst          The address into which the formatted string should be copied.
180  * size         If the formatted string is equal to or longer than this number
181  *              of characters, then it will be truncated to size-1 characters
182  *              and terminated with a nul ('\0').
183  * fmt          The format string (returned by a function such as
184  *              getEnglishErrorString).
185  * params       The array of parameters that were passed to an error callback
186  *              function.
187  */
188 void BPatch::formatErrorString(char *dst, int size,
189                                const char *fmt, const char **params)
190 {
191     int cur_param = 0;
192
193     while (size > 1 && *fmt) {
194         if (*fmt == '%') {
195             if (fmt[1] == '\0') {
196                 break;
197             } else if (fmt[1] == '%') {
198                 *dst++ = '%';
199                 size--;
200             } else if (fmt[1] == 's') {
201                 char *p = (char *)params[cur_param++];
202                 while (size > 1 && *p) {
203                     *dst++ = *p++;
204                     size--;
205                 }
206             } else {
207                 // Illegal specifier
208                 *dst++ = fmt[0];
209                 *dst++ = fmt[1];
210                 size -= 2;
211             }
212             fmt += 2;
213         } else {
214             *dst++ = *fmt++;
215             size--;
216         }
217     }
218     if (size > 0)
219         *dst = '\0';
220 }
221
222
223 /*
224  * BPatch::pidToThread
225  *
226  * Given a process ID, this function returns a pointer to the associated
227  * BPatch_thread object (or NULL if there is none).  Since a process may be
228  * registered provisionally with a thread object pointer of NULL, the boolean
229  * pointed to by the parameter "exists" is set to true if the pid exists in
230  * the table of processes, and false if it does not.
231  *
232  * pid          The pid to look up.
233  * exists       A pointer to a boolean to fill in with true if the pid exists
234  *              in the table and false if it does not.  NULL may be passed in
235  *              if this information is not required.
236  */
237 BPatch_thread *BPatch::pidToThread(int pid, bool *exists)
238 {
239     if (info->threadsByPid.defines(pid)) {
240         if (exists) *exists = true;
241         return info->threadsByPid[pid];
242     } else {
243         if (exists) *exists = false;
244         return NULL;
245     }
246 }
247
248
249 /*
250  * BPatch::getThreads
251  *
252  * Returns a vector of all threads that are currently defined.  Includes
253  * threads created directly using the library and those created with UNIX fork
254  * or Windows NT spawn system calls.  The caller is responsible for deleting
255  * the vector when it is no longer needed.
256  */
257 BPatch_Vector<BPatch_thread *> *BPatch::getThreads()
258 {
259     BPatch_Vector<BPatch_thread *> *result = new BPatch_Vector<BPatch_thread *>;
260
261     dictionary_hash_iter<int, BPatch_thread *> ti(info->threadsByPid);
262
263     int pid;
264     BPatch_thread *thread;
265
266     while (ti.next(pid, thread))
267         result->push_back(thread);
268
269     return result;
270 }
271
272
273 /*
274  * pollForStatusChange
275  *
276  * Checks for changes in the state of any child process, and returns true if
277  * it discovers any such changes.  Also updates the process object
278  * representing each process for which a change is detected.
279  *
280  * This function is declared as a friend of BPatch_thread so that it can use
281  * the BPatch_thread::pidToThread call and so that it can set the lastSignal
282  * member of a BPatch_thread object.
283  */
284 bool pollForStatusChange()
285 {
286     assert(BPatch::bpatch != NULL);
287
288     bool        result = false;
289     int         pid, status;
290
291     while ((pid = process::waitProcs(&status)) > 0) {
292         // There's been a change in a child process
293         result = true;
294         assert(BPatch::bpatch != NULL);
295         bool exists;
296         BPatch_thread *thread = BPatch::bpatch->pidToThread(pid, &exists);
297         if (thread == NULL) {
298             if (exists) {
299                 if (WIFSIGNALED(status) || WIFEXITED(status))
300                     BPatch::bpatch->unRegisterThread(pid);
301             } else {
302                 fprintf(stderr, "Warning - wait returned status of an unknown process (%d)\n", pid);
303             }
304         }
305         if (thread != NULL) {
306             if (WIFSTOPPED(status))
307                 thread->lastSignal = WSTOPSIG(status);
308             else if (WIFSIGNALED(status))
309                 thread->lastSignal = WTERMSIG(status);
310             else if (WIFEXITED(status))
311                 thread->lastSignal = 0; /* XXX Make into some constant */
312         }
313         handleSigChild(pid, status);
314     }
315     return result;
316 }
317
318
319 /*
320  * BPatch::registerProvisionalThread
321  *
322  * Register a new process that is not yet associated with a thread.
323  * (this function is called only by createProcess).
324  *
325  * pid          The pid of the process to register.
326  */
327 void BPatch::registerProvisionalThread(int pid)
328 {
329     assert(!info->threadsByPid.defines(pid));
330     info->threadsByPid[pid] = NULL;
331 }
332
333
334 /*
335  * BPatch::registerThread
336  *
337  * Register a new BPatch_thread object with the BPatch library (this function
338  * is called only by the constructor for BPatch_thread).
339  *
340  * thread       A pointer to the thread to register.
341  */
342 void BPatch::registerThread(BPatch_thread *thread)
343 {
344     assert(!info->threadsByPid.defines(thread->getPid()) ||
345             info->threadsByPid[thread->getPid()] == NULL);
346     info->threadsByPid[thread->getPid()] = thread;
347 }
348
349
350 /*
351  * BPatch::unRegisterThread
352  *
353  * Remove the BPatch_thread associated with a given pid from the list of
354  * threads being managed by the library.
355  *
356  * pid          The pid of the thread to be removed.
357  */
358 void BPatch::unRegisterThread(int pid)
359 {
360     assert(info->threadsByPid.defines(pid));
361     info->threadsByPid.undef(pid);      
362 }