Added features to dyninstAPI library, including the ability to delete
[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 "process.h"
50
51 extern bool dyninstAPI_init();
52 extern int dyninstAPI_handleSigChild(int pid, int status);
53
54
55 BPatch *BPatch::bpatch = NULL;
56
57
58 /*
59  * BPatch::BPatch
60  *
61  * Constructor for BPatch.  Performs one-time initialization needed by the
62  * library.
63  */
64 BPatch::BPatch() : errorHandler(NULL), typeCheckOn(true)
65 {
66     extern bool init();
67     extern double cyclesPerSecond;
68     extern double timing_loop(const unsigned, const unsigned);
69
70     // Save a pointer to the one-and-only bpatch object.
71     if (bpatch == NULL)
72         bpatch = this;
73     /* XXX else
74      *  (indicate an error somehow)
75      */
76
77     // XXX dyninstAPI_init returns success/failure -- should pass on somehow
78     dyninstAPI_init();
79     cyclesPerSecond = timing_loop(1, 100000) * 1000000;
80
81     /*
82      * Create the "error" and "untyped" types.
83      */
84     type_Error   = new BPatch_type("<error>", true);
85     type_Untyped = new BPatch_type("<no type>", true);
86
87     /*
88      * Initialize hash table of standard types.
89      */
90     stdTypes = new BPatch_typeCollection;
91     stdTypes->addType(new BPatch_type("int"));
92     stdTypes->addType(new BPatch_type("char *"));
93 }
94
95
96 /*
97  * BPatch::~BPatch
98  *
99  * Destructor for BPatch.  Free allocated memory.
100  */
101 BPatch::~BPatch()
102 {
103     delete type_Error;
104     delete type_Untyped;
105
106     delete stdTypes;
107 }
108
109
110 /*
111  * BPatch::registerErrorCallback
112  *
113  * Registers a function that is to be called by the library when an error
114  * occurs or when there is status to report.  Returns the address of the
115  * previously registered error callback function.
116  *
117  * function     The function to be called.
118  */
119 BPatchErrorCallback BPatch::registerErrorCallback(BPatchErrorCallback function)
120 {
121     BPatchErrorCallback ret;
122
123     ret = errorHandler;
124     errorHandler = function;
125
126     return ret;
127 }
128
129
130 /*
131  * BPatch::getEnglishErrorString
132  *
133  * Returns the descriptive error string for the passed error number.
134  *
135  * number       The number that identifies the error.
136  */
137 const char *BPatch::getEnglishErrorString(int /* number */)
138 {
139     return "%s";
140 }
141
142
143 /*
144  * BPatch::reportError
145  *
146  * Report an error using the callback mechanism.
147  *
148  * severity     The severity level of the error.
149  * number       Identifies the error.
150  * str          A string to pass as the first element of the list of strings
151  *              given to the callback function.
152  */
153 void BPatch::reportError(BPatchErrorLevel severity, int number, const char *str)
154 {
155     if (errorHandler != NULL) {
156         errorHandler(severity, number, &str);
157     }
158 }
159
160
161 /*
162  * BPatch::formatErrorString
163  *
164  * Takes a format string with an error message (obtained from
165  * getEnglishErrorString) and an array of parameters that were passed to an
166  * error callback function, and creates a string with the parameters
167  * substituted into it.
168  *
169  * dst          The address into which the formatted string should be copied.
170  * size         If the formatted string is equal to or longer than this number
171  *              of characters, then it will be truncated to size-1 characters
172  *              and terminated with a nul ('\0').
173  * fmt          The format string (returned by a function such as
174  *              getEnglishErrorString).
175  * params       The array of parameters that were passed to an error callback
176  *              function.
177  */
178 void BPatch::formatErrorString(char *dst, int size,
179                                const char *fmt, const char **params)
180 {
181     int cur_param = 0;
182
183     while (size > 1 && *fmt) {
184         if (*fmt == '%') {
185             if (fmt[1] == '\0') {
186                 break;
187             } else if (fmt[1] == '%') {
188                 *dst++ = '%';
189                 size--;
190             } else if (fmt[1] == 's') {
191                 char *p = (char *)params[cur_param++];
192                 while (size > 1 && *p) {
193                     *dst++ = *p++;
194                     size--;
195                 }
196             } else {
197                 // Illegal specifier
198                 *dst++ = fmt[0];
199                 *dst++ = fmt[1];
200                 size -= 2;
201             }
202             fmt += 2;
203         } else {
204             *dst++ = *fmt++;
205             size--;
206         }
207     }
208     if (size > 0)
209         *dst = '\0';
210 }
211
212
213 /*
214  * BPatch::pidToThread
215  *
216  * Given a process ID, this function returns a pointer to the associated
217  * BPatch_thread object (or NULL if there is none).
218  */
219 BPatch_thread *BPatch::pidToThread(int pid)
220 {
221     for (int i = 0; i < threadVec.size(); i++)
222         if (threadVec[i]->getPid() == pid) return threadVec[i];
223
224     return NULL;
225 }
226
227
228 /*
229  * BPatch::getThreads
230  *
231  * Returns a vector of all threads that are currently defined.  Includes
232  * threads created directly using the library and those created with UNIX fork
233  * or Windows NT spawn system calls.  The caller is responsible for deleting
234  * the vector when it is no longer needed.
235  */
236 BPatch_Vector<BPatch_thread *> *BPatch::getThreads()
237 {
238     BPatch_Vector<BPatch_thread *> *result = new BPatch_Vector<BPatch_thread *>;
239
240     *result = threadVec;
241
242     return result;
243 }
244
245
246 /*
247  * pollForStatusChange
248  *
249  * Checks for changes in the state of any child process, and returns true if
250  * it discovers any such changes.  Also updates the process object
251  * representing each process for which a change is detected.
252  *
253  * This function is declared as a friend of BPatch_thread so that it can use
254  * the BPatch_thread::pidToThread call and so that it can set the lastSignal
255  * member of a BPatch_thread object.
256  */
257 bool pollForStatusChange()
258 {
259     bool        result = false;
260     int         pid, status;
261
262     while ((pid = process::waitProcs(&status)) > 0) {
263         // There's been a change in a child process
264         result = true;
265         assert(BPatch::bpatch != NULL);
266         BPatch_thread *thread = BPatch::bpatch->pidToThread(pid);
267         assert(thread != NULL);
268         if (thread != NULL) {
269             if (WIFSTOPPED(status))
270                 thread->lastSignal = WSTOPSIG(status);
271             else if (WIFSIGNALED(status))
272                 thread->lastSignal = WTERMSIG(status);
273             else if (WIFEXITED(status))
274                 thread->lastSignal = 0; /* XXX Make into some constant */
275         }
276         dyninstAPI_handleSigChild(pid, status);
277     }
278     return result;
279 }