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_type.h"
48 #include "BPatch_libInfo.h"
51 #ifdef i386_unknown_nt4_0
52 #include "nt_signal_emul.h"
55 extern bool dyninstAPI_init();
56 extern int handleSigChild(int pid, int status);
59 BPatch *BPatch::bpatch = NULL;
65 * Constructor for BPatch. Performs one-time initialization needed by the
68 BPatch::BPatch() : errorHandler(NULL), typeCheckOn(true)
71 extern double cyclesPerSecond;
72 extern double timing_loop(const unsigned, const unsigned);
74 // Save a pointer to the one-and-only bpatch object.
78 * (indicate an error somehow)
81 // XXX dyninstAPI_init returns success/failure -- should pass on somehow
83 cyclesPerSecond = timing_loop(1, 100000) * 1000000;
86 * Create the library private info object.
88 info = new BPatch_libInfo;
91 * Create the "error" and "untyped" types.
93 type_Error = new BPatch_type("<error>", true);
94 type_Untyped = new BPatch_type("<no type>", true);
97 * Initialize hash table of standard types.
99 stdTypes = new BPatch_typeCollection;
100 stdTypes->addType(new BPatch_type("int"));
101 stdTypes->addType(new BPatch_type("char *"));
108 * Destructor for BPatch. Free allocated memory.
124 * BPatch::registerErrorCallback
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.
130 * function The function to be called.
132 BPatchErrorCallback BPatch::registerErrorCallback(BPatchErrorCallback function)
134 BPatchErrorCallback ret;
137 errorHandler = function;
144 * BPatch::getEnglishErrorString
146 * Returns the descriptive error string for the passed error number.
148 * number The number that identifies the error.
150 const char *BPatch::getEnglishErrorString(int /* number */)
157 * BPatch::reportError
159 * Report an error using the callback mechanism.
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.
166 void BPatch::reportError(BPatchErrorLevel severity, int number, const char *str)
168 if (severity != BPatchInfo)
171 if (errorHandler != NULL) {
172 errorHandler(severity, number, &str);
178 * BPatch::formatErrorString
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.
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
194 void BPatch::formatErrorString(char *dst, int size,
195 const char *fmt, const char **params)
199 while (size > 1 && *fmt) {
201 if (fmt[1] == '\0') {
203 } else if (fmt[1] == '%') {
206 } else if (fmt[1] == 's') {
207 char *p = (char *)params[cur_param++];
208 while (size > 1 && *p) {
230 * BPatch::pidToThread
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.
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.
243 BPatch_thread *BPatch::pidToThread(int pid, bool *exists)
245 if (info->threadsByPid.defines(pid)) {
246 if (exists) *exists = true;
247 return info->threadsByPid[pid];
249 if (exists) *exists = false;
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.
263 BPatch_Vector<BPatch_thread *> *BPatch::getThreads()
265 BPatch_Vector<BPatch_thread *> *result = new BPatch_Vector<BPatch_thread *>;
267 dictionary_hash_iter<int, BPatch_thread *> ti(info->threadsByPid);
270 BPatch_thread *thread;
272 while (ti.next(pid, thread))
273 result->push_back(thread);
280 * BPatch::registerProvisionalThread
282 * Register a new process that is not yet associated with a thread.
283 * (this function is called only by createProcess).
285 * pid The pid of the process to register.
287 void BPatch::registerProvisionalThread(int pid)
289 assert(!info->threadsByPid.defines(pid));
290 info->threadsByPid[pid] = NULL;
295 * BPatch::registerThread
297 * Register a new BPatch_thread object with the BPatch library (this function
298 * is called only by the constructor for BPatch_thread).
300 * thread A pointer to the thread to register.
302 void BPatch::registerThread(BPatch_thread *thread)
304 assert(!info->threadsByPid.defines(thread->getPid()) ||
305 info->threadsByPid[thread->getPid()] == NULL);
306 info->threadsByPid[thread->getPid()] = thread;
311 * BPatch::unRegisterThread
313 * Remove the BPatch_thread associated with a given pid from the list of
314 * threads being managed by the library.
316 * pid The pid of the thread to be removed.
318 void BPatch::unRegisterThread(int pid)
320 assert(info->threadsByPid.defines(pid));
321 info->threadsByPid.undef(pid);
326 * BPatch::createProcess
328 * Create a process and return a BPatch_thread representing it.
329 * Returns NULL upon failure.
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
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.
338 BPatch_thread *BPatch::createProcess(char *path, char *argv[], char *envp[])
342 BPatch_thread *ret = new BPatch_thread(path, argv, envp);
344 if (getLastError()) {
354 * BPatch::attachProcess
356 * Attach to a running pprocess and return a BPatch_thread representing it.
357 * Returns NULL upon failure.
359 * path The pathname of the executable for the process.
360 * pid The id of the process to attach to.
362 BPatch_thread *BPatch::attachProcess(char *path, int pid)
366 BPatch_thread *ret = new BPatch_thread(path, pid);
368 if (getLastError()) {
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.
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
389 bool BPatch::getThreadEvent(bool block)
394 while ((pid = process::waitProcs(&status, block)) > 0) {
395 // There's been a change in a child process
397 // Since we found something, we don't want to block anymore
401 BPatch_thread *thread = pidToThread(pid, &exists);
402 if (thread == NULL) {
404 if (WIFSIGNALED(status) || WIFEXITED(status))
405 unRegisterThread(pid);
407 fprintf(stderr, "Warning - wait returned status of an unknown process (%d)\n", pid);
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);
422 #ifndef i386_unknown_nt4_0
423 handleSigChild(pid, status);
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.
437 bool BPatch::havePendingEvent()
439 #ifdef i386_unknown_nt4_0
440 // On NT, we need to poll for events as often as possible, so that we can
442 if (getThreadEvent(false))
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);
451 BPatch_thread *thread;
453 while (ti.next(pid, thread)) {
454 if (thread != NULL &&
455 (thread->pendingUnreportedStop() ||
456 thread->pendingUnreportedTermination())) {
466 * pollForStatusChange
468 * Checks for unreported changes to the status of any child process, and
469 * returns true if any are detected. Returns false otherwise.
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.
474 bool pollForStatusChange()
476 // First, check if there are any unreported changes that have already been
478 assert(BPatch::bpatch);
479 if (BPatch::bpatch->havePendingEvent())
482 // No changes were previously detected, so check for new changes
483 return BPatch::bpatch->getThreadEvent(false);
488 * waitForStatusChange
490 * Blocks waiting for a change to occur in the running status of a child
491 * process. Returns true upon success, false upon failure.
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.
496 bool waitForStatusChange()
498 // First, check if there are any unreported changes that have already been
500 assert(BPatch::bpatch);
501 if (BPatch::bpatch->havePendingEvent())
504 // No changes were previously detected, so wait for a new change
505 return BPatch::bpatch->getThreadEvent(true);