2 * Copyright (c) 1996-2004 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.
44 #include "BPatch_asyncEventHandler.h"
47 #if defined (os_windows)
51 #include <sys/types.h>
52 //#if defined (os_osf)
53 //typedef unsigned long socklen_t;
54 //#ifndef _XOPEN_SOURCE
55 //#define _XOPEN_SOURCE 500
57 //#undef _XOPEN_SOURCE
58 //#define _XOPEN_SOURCE 500
60 //#ifndef _XOPEN_SOURCE_EXTENDED
61 //#define _XOPEN_SOURCE_EXTENDED 1
63 //#define _SOCKADDR_LEN
64 #include <sys/types.h>
65 #include <sys/socket.h>
69 #include "BPatch_eventLock.h"
73 //extern MUTEX_TYPE global_mutex; // see BPatch_eventLock.h
74 //extern bool mutex_created = false;
76 ThreadLibrary::ThreadLibrary(BPatch_thread *thr, const char *libName) :
79 DYNINSTasyncThreadCreate(NULL),
80 DYNINSTasyncThreadDestroy(NULL),
81 DYNINSTasyncThreadStart(NULL),
82 DYNINSTasyncThreadStop(NULL)
84 const char *tmp_libname = libName;
86 BPatch_image *appImage = thr->getImage();
87 threadModule = appImage->findModule(libName);
89 // exact match not found, try substrings (so we can specify libpthread
90 // when we want a match on either libpthread.so, or libpthread.so.0, .a, etc)
92 BPatch_Vector<BPatch_module *> *mods = appImage->getModules();
93 for (unsigned int i = 0; i < mods->size(); ++i) {
94 (*mods)[i]->getName(buf, 512);
95 if (strstr(buf, libName)) {
98 threadModule->getName(oldname, 512);
99 fprintf(stderr, "%s[%d]: WARN: multiple matches found for %s\n",
100 __FILE__, __LINE__, libName);
101 fprintf(stderr, "%s[%d]: replacing module %s with %s\n",
102 __FILE__, __LINE__, oldname, buf);
104 threadModule = (*mods)[i];
109 //fprintf(stderr, "%s[%d]: Thread module %s not found, assuming single threaded\n",
110 // __FILE__, __LINE__, libName);
114 fprintf(stderr, "Available modules:\n");
115 BPatch_Vector<BPatch_module *> *mods = appImage->getModules();
116 for (unsigned int i = 0; i < mods->size(); ++i) {
117 (*mods)[i]->getName(buf, 512);
118 fprintf(stderr, "\t%s\n", buf);
121 tmp_libname = "<unavailable thread module>";
124 libname = new char [strlen(tmp_libname)+1];
125 strcpy(libname, tmp_libname);
127 // find the dyninst RT Library
128 char *rtname = getenv("DYNINSTAPI_RT_LIB");
131 #if defined(os_windows)
132 char *short_rtname = strrchr(rtname, '\\') + 1; /*ignore slash*/
134 char *short_rtname = strrchr(rtname, '/') + 1; /*ignore slash*/
137 dyninst_rt = appImage->findModuleInt(short_rtname ? short_rtname : rtname);
139 bpfatal("%s[%d]: Cannot find dyninst rt lib: %s\n", __FILE__, __LINE__,
144 // find the thread reporting functions in the RT lib
145 BPatch_Vector<BPatch_function *> funcs;
149 funcName = "DYNINSTasyncThreadCreate";
150 dyninst_rt->findFunction(funcName, funcs);
152 bperr("%s[%d]: cannot find %s\n", __FILE__, __LINE__, funcName);
155 if (funcs.size() > 1)
156 bperr("%s[%d]: WARN: weird: found %d %s\n", __FILE__, __LINE__,
157 funcs.size(), funcName);
158 DYNINSTasyncThreadCreate = funcs[0];
163 funcName = "DYNINSTasyncThreadDestroy";
164 dyninst_rt->findFunction(funcName, funcs);
166 bperr("%s[%d]: cannot find %s\n", __FILE__, __LINE__, funcName);
169 if (funcs.size() > 1)
170 bperr("%s[%d]: WARN: weird: found %d %s\n", __FILE__, __LINE__,
171 funcs.size(), funcName);
172 DYNINSTasyncThreadDestroy = funcs[0];
177 funcName = "DYNINSTasyncThreadStart";
178 dyninst_rt->findFunction(funcName, funcs);
180 bperr("%s[%d]: cannot find %s\n", __FILE__, __LINE__, funcName);
183 if (funcs.size() > 1)
184 bperr("%s[%d]: WARN: weird: found %d %s\n", __FILE__, __LINE__,
185 funcs.size(), funcName);
186 DYNINSTasyncThreadStart = funcs[0];
191 funcName = "DYNINSTasyncThreadStop";
192 dyninst_rt->findFunction(funcName, funcs);
194 bperr("%s[%d]: cannot find %s\n", __FILE__, __LINE__, funcName);
197 if (funcs.size() > 1)
198 bperr("%s[%d]: WARN: weird: found %d %s\n", __FILE__, __LINE__,
199 funcs.size(), funcName);
200 DYNINSTasyncThreadStop = funcs[0];
206 ThreadLibrary::~ThreadLibrary()
211 bool ThreadLibrary::hasCapability(BPatch_asyncEventType t)
213 if (!threadModule) return false;
215 BPatch_Vector<BPatch_function *> *funcs = funcsForType(t);
216 if (!funcs) return false;
218 return (funcs->size() > 0);
221 bool ThreadLibrary::addThreadEventFunction(BPatch_asyncEventType t, const char *name)
224 fprintf(stderr, "%s[%d]: cannot add thread event %s to nonexistant threads lib\n",
225 __FILE__, __LINE__, asyncEventType2Str(t));
229 BPatch_Vector<BPatch_function *> *funcs = funcsForType(t);
233 BPatch_Vector<BPatch_function *> hits;
234 if (!threadModule->findFunction(name, hits, false,false, true) || !hits.size()) {
235 fprintf(stderr, "%s[%d]: no matches for %s found in module %s\n",
236 __FILE__, __LINE__, name, libname);
239 // as usual, warn if we got more than one hit.
240 if (hits.size() > 1) {
241 fprintf(stderr, "%s[%d]: %d matches for %s found in module %s\n",
242 __FILE__, __LINE__, hits.size(), name, libname);
245 // add function(s) to event-specific vector
246 for (unsigned int i = 0; i < hits.size(); ++i) {
247 funcs->push_back(hits[i]);
250 //fprintf(stderr, "%s[%d]: installed capability %s for Thread Lib %s\n",
251 // __FILE__, __LINE__, asyncEventType2Str(t), libname);
255 unsigned int ThreadLibrary::numberOfFuncsForEvent(BPatch_asyncEventType t)
257 BPatch_Vector<BPatch_function *> *funcs = funcsForType(t);
258 if (!funcs) return 0;
259 return funcs->size();
262 BPatch_function *ThreadLibrary::funcForEvent(BPatch_asyncEventType t, int index)
264 BPatch_Vector<BPatch_function *> *funcs = funcsForType(t);
265 if (!funcs) return NULL;
266 if (index > (int)(funcs->size() - 1)) return NULL;
267 return (*funcs)[index];
270 BPatch_function *ThreadLibrary::getDYNINSTreportFunc(BPatch_asyncEventType t)
273 case BPatch_threadCreateEvent: return DYNINSTasyncThreadCreate;
274 case BPatch_threadDestroyEvent: return DYNINSTasyncThreadDestroy;
275 case BPatch_threadStartEvent: return DYNINSTasyncThreadStart;
276 case BPatch_threadStopEvent: return DYNINSTasyncThreadStop;
279 fprintf(stderr, "%s[%d]: invalid type requested: %s\n",
280 __FILE__, __LINE__, asyncEventType2Str(t));
283 BPatch_Vector<BPatch_function *> *ThreadLibrary::funcsForType(BPatch_asyncEventType t)
286 case BPatch_threadCreateEvent: return &threadCreateFuncs;
287 case BPatch_threadDestroyEvent: return &threadDestroyFuncs;
288 case BPatch_threadStartEvent: return &threadStartFuncs;
289 case BPatch_threadStopEvent: return &threadStopFuncs;
292 fprintf(stderr, "%s[%d]: invalid type requested: %s\n",
293 __FILE__, __LINE__, asyncEventType2Str(t));
297 // A wrapper for pthread_create, or its equivalent.
299 inline THREAD_RETURN asyncHandlerWrapper(void *h)
301 ((BPatch_asyncEventHandler * )h)->main();
305 bool BPatch_asyncEventHandler::connectToProcess(BPatch_thread *p)
307 //fprintf(stderr, "%s[%d]: enter ConnectToProcess\n", __FILE__, __LINE__);
308 // All we do here is add the process to the list of connected processes
309 // with a fd equal to -1, indicating the not-yet-connected state.
311 // Then remotely execute code in the mutatee to initiate the connection.
313 // make sure that this process is not already known
314 for (unsigned int i = 0; i < process_fds.size(); ++i) {
315 if (p == process_fds[i].process) {
316 bperr("%s[%d]: duplicate request to connect to process %d\n",
317 __FILE__, __LINE__, p->getPid());
320 if (!process_fds[i].process) {
321 fprintf(stderr, "%s[%d]: Warning, invalid process entry\n", __FILE__, __LINE__);
324 if (p->getPid() == process_fds[i].process->getPid()) {
325 bperr("%s[%d]: duplicate request to connect to process %d\n",
326 __FILE__, __LINE__, p->getPid());
331 ThreadLibrary *threadLib = newThreadLibrary(p);
333 // instrument thread reporting functions, as available:
335 if (threadLib->hasCapability(BPatch_threadCreateEvent)) {
336 BPatch_function *reportCreate;
337 reportCreate = threadLib->getDYNINSTreportFunc(BPatch_threadCreateEvent);
338 reportThreadCreateHandle = instrumentThreadEvent(p, threadLib,
339 BPatch_threadCreateEvent,
343 if (threadLib->hasCapability(BPatch_threadDestroyEvent)) {
344 BPatch_function *reportDestroy;
345 reportDestroy = threadLib->getDYNINSTreportFunc(BPatch_threadDestroyEvent);
346 reportThreadDestroyHandle = instrumentThreadEvent(p, threadLib,
347 BPatch_threadDestroyEvent,
351 if (threadLib->hasCapability(BPatch_threadStartEvent)) {
352 BPatch_function *reportStart;
353 reportStart = threadLib->getDYNINSTreportFunc(BPatch_threadStartEvent);
354 reportThreadStartHandle = instrumentThreadEvent(p, threadLib,
355 BPatch_threadStartEvent,
359 if (threadLib->hasCapability(BPatch_threadStopEvent)) {
360 BPatch_function *reportStop;
361 reportStop = threadLib->getDYNINSTreportFunc(BPatch_threadStopEvent);
362 reportThreadStopHandle = instrumentThreadEvent(p, threadLib,
363 BPatch_threadStopEvent,
367 // add process to list
371 newp.threadlib = threadLib;
372 process_fds.push_back(newp);
374 // get mutatee to initiate connection
376 // find the runtime library module
377 BPatch_module *dyninstLib = threadLib->getDyninstRT();
379 #if defined (os_windows)
380 // find the variable to set with the port number to connect to
381 BPatch_variableExpr *portVar;
382 portVar = p->getImage()->findVariable("connect_port");
384 fprintf(stderr, "%s[%d]: cannot find var connect_port in rt lib\n",
388 if (!portVar->writeValue((void *) &listen_port, sizeof(listen_port), false)) {
389 fprintf(stderr, "%s[%d]: cannot write var connect_port in rt lib\n",
395 // find the function that will initiate the connection
396 BPatch_Vector<BPatch_function *> funcs;
397 if (!dyninstLib->findFunction("DYNINSTasyncConnect", funcs, true, true, true)
398 || ! funcs.size() ) {
399 bpfatal("%s[%d]: could not find function: DYNINSTasyncConnect\n",
403 if (funcs.size() > 1) {
404 bperr("%s[%d]: found %d varieties of function: DYNINSTasyncConnect\n",
405 __FILE__, __LINE__, funcs.size());
408 // The (int) argument to this function is our pid
409 BPatch_Vector<BPatch_snippet *> args;
410 #if !defined(os_windows)
411 args.push_back(new BPatch_constExpr(getpid()));
413 BPatch_funcCallExpr connectcall(*funcs[0], args);
415 #if !defined (os_osf) && !defined (os_windows)
416 // Run the connect call as oneTimeCode
417 if (!p->oneTimeCode(connectcall)) {
418 bpfatal("%s[%d]: failed to connect mutatee to async handler\n", __FILE__, __LINE__);
423 //fprintf(stderr, "%s[%d]: leaveConnectToProcess\n", __FILE__, __LINE__);
427 bool BPatch_asyncEventHandler::detachFromProcess(BPatch_thread *p)
429 // find the fd for this process
430 // (reformat process vector while we're at it)
433 ThreadLibrary *threadlib = NULL;
434 for (unsigned int i = 0; i < process_fds.size(); ++i) {
435 if (process_fds[i].process == p) {
436 targetfd = process_fds[i].fd;
437 threadlib = process_fds[i].threadlib;
438 if (threadlib) delete threadlib;
439 process_fds.erase(i,i);
444 if (targetfd == -2) {
445 bperr("%s[%d]: detachFromProcess(%d) could not find process record\n",
446 __FILE__, __LINE__, p->getPid());
450 // remove thread instrumentation, if exists
451 if (reportThreadCreateHandle)
452 if (!p->deleteSnippet(reportThreadCreateHandle))
453 bperr("%s[%d]: detachFromProcess(%d) failed to remove instru\n",
454 __FILE__, __LINE__, p->getPid());
455 if (reportThreadDestroyHandle)
456 if (!p->deleteSnippet(reportThreadDestroyHandle))
457 bperr("%s[%d]: detachFromProcess(%d) failed to remove instru\n",
458 __FILE__, __LINE__, p->getPid());
459 if (reportThreadStartHandle)
460 if (!p->deleteSnippet(reportThreadStartHandle))
461 bperr("%s[%d]: detachFromProcess(%d) failed to remove instru\n",
462 __FILE__, __LINE__, p->getPid());
463 if (reportThreadStopHandle)
464 if (!p->deleteSnippet(reportThreadStopHandle))
465 bperr("%s[%d]: detachFromProcess(%d) failed to remove instru\n",
466 __FILE__, __LINE__, p->getPid());
468 // if we never managed to fully attach, targetfd might still be -1.
469 // not sure if this could happen, but just return in this case.
470 if (targetfd == -1) return true;
472 // get the mutatee to close the comms file desc.
474 if (!mutateeDetach(p)) {
475 bperr("%s[%d]: detachFromProcess(%d) could not clean up mutatee\n",
476 __FILE__, __LINE__, p->getPid());
479 // close our own file desc for this process.
482 return false; // true
485 void *BPatch_asyncEventHandler::registerDynamicCallCallback(BPatchDynamicCallSiteCallback cb,
488 BPatch_thread *process = pt->getFunction()->getProc()->bpatch_thread;
489 ThreadLibrary *threadLib = NULL;
490 for (unsigned int i = 0; i < process_fds.size(); ++i) {
491 if (process_fds[i].process == process) {
492 threadLib = process_fds[i].threadlib;
497 BPatch_module *dyninstLib = threadLib->getDyninstRT();
499 // find the function that will report the function call
500 BPatch_Vector<BPatch_function *> funcs;
501 if (!dyninstLib->findFunction("DYNINSTasyncDynFuncCall", funcs)
502 || ! funcs.size() ) {
503 bpfatal("%s[%d]: could not find function: DYNINSTasyncDynFuncCall\n",
507 if (funcs.size() > 1) {
508 bperr("%s[%d]: found %d varieties of function: DYNINSTasyncDynFuncCall\n",
509 __FILE__, __LINE__, funcs.size());
512 void *handle = pt->monitorCalls(funcs[0]);
514 bperr("%s[%d]: registerDynamicCallCallback, could not monitor site\n",
519 dyncall_cb_record new_rec;
522 new_rec.handle = handle;
523 dyn_pts.push_back(new_rec);
528 bool BPatch_asyncEventHandler::removeDynamicCallCallback(void *handle)
531 BPatch_point *pt = NULL;
533 // find monitoring request corresp. to <handle>
534 // If we have a lot of points to monitor, this could be slow.
535 // Consider better data struct for dyn_pts ?
537 for (unsigned int i = 0; i < dyn_pts.size(); ++i) {
538 if (dyn_pts[i].handle == handle) {
539 target = dyn_pts[i].handle;
547 bperr("%s[%d]: unregisterDynamicCallCallback, handle not found\n",
552 // <handle> found, so we can proceed with inst removal.
555 if (! pt->stopMonitoring(handle)) {
556 bperr("%s[%d]: unregisterDynamicCallCallback, could not remove instrumentation\n",
564 pdvector<thread_event_cb_record> *
565 BPatch_asyncEventHandler::getCBsForType(BPatch_asyncEventType t)
568 case BPatch_threadCreateEvent: return &thread_create_cbs;
569 case BPatch_threadDestroyEvent: return &thread_destroy_cbs;
570 case BPatch_threadStartEvent: return &thread_start_cbs;
571 case BPatch_threadStopEvent: return &thread_stop_cbs;
574 bperr("%s[%d]: bad event type %s, cannot register callback\n",
575 __FILE__, __LINE__, asyncEventType2Str(t));
579 bool BPatch_asyncEventHandler::registerThreadEventCallback(BPatch_thread *thread,
580 BPatch_asyncEventType type,
581 BPatchThreadEventCallback cb)
583 ThreadLibrary *threadLib = NULL;
584 pdvector<thread_event_cb_record> *event_cbs = getCBsForType(type);
585 if (!event_cbs) return false;
587 // find the ThreadLib for this thread
588 for (unsigned int k = 0; k < process_fds.size(); ++k) {
589 if (process_fds[k].process == thread) {
590 threadLib = process_fds[k].threadlib;
596 bperr("%s[%d]: instrument thread event of type %s, cannot find thread lib\n",
597 __FILE__, __LINE__,asyncEventType2Str(type));
601 if (!threadLib->hasCapability(type)) {
602 bperr("%s[%d]: instrument thread event of type %s, not supported for lib %s\n",
603 __FILE__, __LINE__,asyncEventType2Str(type), threadLib->getLibName());
607 // find out if we already have (some) callback(s) for this thread
608 thread_event_cb_record thread_event_rec = {0,0,0,0};
610 for (unsigned int i = 0; i < event_cbs->size(); ++i) {
611 if ((*event_cbs)[i].thread == thread) {
612 thread_event_rec = (*event_cbs)[i];
617 if (thread_event_rec.thread && thread_event_rec.cbs) {
618 // already have callbacks for this thread, just add the new one
619 pdvector<BPatchThreadEventCallback> *cbs = thread_event_rec.cbs;
625 //fprintf(stderr, "%s[%d]: allocating new callbacks for event %s\n",
626 // __FILE__, __LINE__, asyncEventType2Str(type));
627 // don't have any yet, need to alloc a new callback vector
628 thread_event_rec.thread = thread;
629 thread_event_rec.cbs = new pdvector<BPatchThreadEventCallback>;
630 thread_event_rec.cbs->push_back(cb);
631 event_cbs->push_back(thread_event_rec);
635 bool BPatch_asyncEventHandler::registerThreadEventCallback(BPatch_thread *thread,
636 BPatch_asyncEventType type,
639 ThreadLibrary *threadLib = NULL;
640 pdvector<thread_event_cb_record> *event_cbs = getCBsForType(type);
641 if (!event_cbs) return false;
643 // find the ThreadLib for this thread
644 for (unsigned int k = 0; k < process_fds.size(); ++k) {
645 if (process_fds[k].process == thread) {
646 threadLib = process_fds[k].threadlib;
652 bperr("%s[%d]: instrument thread event of type %s, cannot find thread lib\n",
653 __FILE__, __LINE__,asyncEventType2Str(type));
657 if (!threadLib->hasCapability(type)) {
658 bperr("%s[%d]: instrument thread event of type %s, not supported for lib %s\n",
659 __FILE__, __LINE__,asyncEventType2Str(type), threadLib->getLibName());
663 // find out if we already have (some) callback(s) for this thread
664 thread_event_cb_record thread_event_rec = {0,0,0,0};
666 for (unsigned int i = 0; i < event_cbs->size(); ++i) {
667 if ((*event_cbs)[i].thread == thread) {
668 thread_event_rec = (*event_cbs)[i];
673 BPatchSnippetHandle *handle = NULL;
674 if (NULL == (handle = instrumentThreadEvent(thread, threadLib, type, cb))){
675 bperr("%s[%d]: cannot instrument thread event of type %s\n",
676 __FILE__, __LINE__,asyncEventType2Str(type));
680 // callback inserted, keep track of BPatch_function and handle, for possible removal
682 if (thread_event_rec.thread && thread_event_rec.mutatee_side_cbs) {
683 // already have callbacks for this thread, just add the new one
684 pdvector<BPatch_function *> *cbs = thread_event_rec.mutatee_side_cbs;
685 pdvector<BPatchSnippetHandle *> *handles = thread_event_rec.handles;
688 assert(cbs->size() == handles->size());
690 handles->push_back(handle);
694 // don't have any yet, need to alloc a new callback vector
695 thread_event_rec.thread = thread;
696 thread_event_rec.mutatee_side_cbs = new pdvector<BPatch_function *>;
697 thread_event_rec.mutatee_side_cbs->push_back(cb);
699 // and a new handle vector
700 assert(NULL == thread_event_rec.handles);
701 thread_event_rec.handles = new pdvector<BPatchSnippetHandle *>;
702 thread_event_rec.handles->push_back(handle);
707 bool BPatch_asyncEventHandler::removeThreadEventCallback(BPatch_thread *thread,
708 BPatch_asyncEventType type,
709 BPatchThreadEventCallback cb)
711 pdvector<thread_event_cb_record> *event_cbs = getCBsForType(type);
712 if (!event_cbs) return false;
714 thread_event_cb_record thread_event_rec = {0,0,0,0};
716 // find the callbacks for this thread
717 for (unsigned int i = 0; i < event_cbs->size(); ++i) {
718 if ((*event_cbs)[i].thread == thread) {
719 thread_event_rec = (*event_cbs)[i];
724 if (thread_event_rec.thread && thread_event_rec.cbs) {
725 pdvector<BPatchThreadEventCallback> *cbs = thread_event_rec.cbs;
727 for (unsigned int j = 0; j < cbs->size(); ++j) {
728 if (cb == (*cbs)[j]) {
731 // if we remove the last callback record, clean up the vector too.
732 if (!cbs->size()) delete cbs;
733 thread_event_rec.cbs = NULL;
739 bperr("%s[%d]: cannot remove thread event of type %s.\n",
740 __FILE__, __LINE__,asyncEventType2Str(type));
744 bool BPatch_asyncEventHandler::removeThreadEventCallback(BPatch_thread *thread,
745 BPatch_asyncEventType type,
748 pdvector<thread_event_cb_record> *event_cbs = getCBsForType(type);
749 if (!event_cbs) return false;
751 thread_event_cb_record thread_event_rec = {0,0,0,0};
753 // find the callbacks for this thread
754 for (unsigned int i = 0; i < event_cbs->size(); ++i) {
755 if ((*event_cbs)[i].thread == thread) {
756 thread_event_rec = (*event_cbs)[i];
761 if (thread_event_rec.thread && thread_event_rec.mutatee_side_cbs) {
763 pdvector<BPatch_function *> *cbs = thread_event_rec.mutatee_side_cbs;
764 pdvector<BPatchSnippetHandle *> *handles = thread_event_rec.handles;
768 for (unsigned int j = 0; j < cbs->size(); ++j) {
769 if (cb == (*cbs)[j]) {
770 BPatchSnippetHandle *handle = (*handles)[j];
773 assert(cbs->size() == handles->size());
775 // if we remove the last callback record, clean up the vector too.
778 thread_event_rec.mutatee_side_cbs = NULL;
780 if (!handles->size()) {
782 thread_event_rec.handles = NULL;
785 // remove the instrumentation:
786 if (!thread->deleteSnippet(handle)) {
787 bperr("%s[%d]: failed to remove thread event instrumentation of type %s.\n",
788 __FILE__, __LINE__,asyncEventType2Str(type));
797 bperr("%s[%d]: cannot remove thread event of type %s. No record.\n",
798 __FILE__, __LINE__,asyncEventType2Str(type));
803 BPatch_asyncEventHandler::BPatch_asyncEventHandler() :
804 #if !defined (os_windows)
809 reportThreadCreateHandle(NULL),
810 reportThreadDestroyHandle(NULL),
811 reportThreadStartHandle(NULL),
812 reportThreadStopHandle(NULL),
815 // prefer to do socket init in the initialize() function so that we can
818 #if !defined(os_windows)
819 // init pause mutex/cond
821 pthread_mutexattr_t attr;
822 err = pthread_mutexattr_init(&attr);
825 err = pthread_mutex_init(&pause_mutex, &attr);
828 err = pthread_cond_init(&pause_cond, NULL);
833 #if defined(os_windows)
836 cleanupSockets( void )
842 bool BPatch_asyncEventHandler::initialize()
845 #if defined(os_windows)
849 // request WinSock 2.0
850 if( WSAStartup( MAKEWORD(2,0), &data ) == 0 )
852 // verify that the version that was provided is one we can use
853 if( (LOBYTE(data.wVersion) == 2) && (HIBYTE(data.wVersion) == 0) )
860 // set up socket to accept connections from mutatees (on demand)
861 sock = P_socket(PF_INET, SOCK_STREAM, 0);
862 if (INVALID_PDSOCKET == sock) {
863 bperr("%s[%d]: new socket failed, sock = %d, lasterror = %d\n", __FILE__, __LINE__, (unsigned int) sock, WSAGetLastError());
867 struct sockaddr_in saddr;
868 struct in_addr *inadr;
869 struct hostent *hostptr;
871 hostptr = gethostbyname("localhost");
872 inadr = (struct in_addr *) ((void*) hostptr->h_addr_list[0]);
873 memset((void*) &saddr, 0, sizeof(saddr));
874 saddr.sin_family = PF_INET;
875 saddr.sin_port = htons(0); // ask system to assign
876 saddr.sin_addr = *inadr;
878 const char *path = "windows-socket";
880 // set up socket to accept connections from mutatees (on demand)
881 sock = P_socket(SOCKET_TYPE, SOCK_STREAM, 0);
882 if (INVALID_PDSOCKET == sock) {
883 bperr("%s[%d]: new socket failed\n", __FILE__, __LINE__);
888 sprintf(path, "%s/dyninstAsync.%d", P_tmpdir, (int) getpid());
890 struct sockaddr_un saddr;
891 saddr.sun_family = AF_UNIX;
892 strcpy(saddr.sun_path, path);
894 // make sure this file does not exist already.
898 // bind socket to port (windows) or temp file in the /tmp dir (unix)
900 if (PDSOCKET_ERROR == bind(sock, (struct sockaddr *) &saddr,
902 bperr("%s[%d]: bind socket to %s failed\n", __FILE__, __LINE__, path);
906 #if defined(os_windows)
907 // get the port number that was assigned to us
908 int length = sizeof(saddr);
909 if (PDSOCKET_ERROR == getsockname(sock, (struct sockaddr *) &saddr,
911 bperr("%s[%d]: getsockname failed\n", __FILE__, __LINE__);
914 listen_port = ntohs (saddr.sin_port);
917 // set socket to listen for connections
918 // (we will explicitly accept in the main event loop)
920 if (PDSOCKET_ERROR == listen(sock, 1)) { // should not need a backlog here
921 bperr("%s[%d]: listen to %s failed\n", __FILE__, __LINE__, path);
925 // Finally, create the event handling thread
926 if (!createThread()) {
927 bperr("%s[%d]: could not create event handling thread\n",
931 //fprintf(stderr, "%s[%d]: Created async thread\n", __FILE__ , __LINE__);
935 BPatch_asyncEventHandler::~BPatch_asyncEventHandler()
939 bperr("%s[%d]: shut down async event handler failed\n", __FILE__, __LINE__);
942 #if defined (os_windows)
945 // clean up any files left over in the /tmp dir
947 sprintf(path, "%s/dyninstAsync.%d", P_tmpdir, (int) getpid());
950 pthread_mutex_destroy(&pause_mutex);
951 pthread_cond_destroy(&pause_cond);
955 bool BPatch_asyncEventHandler::createThread()
957 #if defined(os_windows)
958 fprintf(stderr, "%s[%d]: about to start thread\n", __FILE__, __LINE__);
959 handler_thread = _beginthread(asyncHandlerWrapper, 0, (void *) this);
960 if (-1L == handler_thread) {
961 bperr("%s[%d]: _beginthread(...) failed\n", __FILE__, __LINE__);
962 fprintf(stderr,"%s[%d]: _beginthread(...) failed\n", __FILE__, __LINE__);
965 fprintf(stderr, "%s[%d]: started thread\n", __FILE__, __LINE__);
970 pthread_attr_t handler_thread_attr;
972 err = pthread_attr_init(&handler_thread_attr);
974 bperr("%s[%d]: could not init async handler thread attributes: %s, %d\n",
975 __FILE__, __LINE__, strerror(err), err);
979 #if defined (os_solaris)
980 err = pthread_attr_setdetachstate(&handler_thread_attr, PTHREAD_CREATE_DETACHED);
982 bperr("%s[%d]: could not set async handler thread attrixibcutes: %s, %d\n",
983 __FILE__, __LINE__, strerror(err), err);
988 err = pthread_create(&handler_thread, &handler_thread_attr,
989 &asyncHandlerWrapper, (void *) this);
991 bperr("%s[%d]: could not start async handler thread: %s, %d\n",
992 __FILE__, __LINE__, strerror(err), err);
993 fprintf(stderr,"%s[%d]: could not start async handler thread: %s, %d\n",
994 __FILE__, __LINE__, strerror(err), err);
1003 err = pthread_attr_destroy(&handler_thread_attr);
1005 bperr("%s[%d]: could not destroy async handler attr: %s, %d\n",
1006 __FILE__, __LINE__, strerror(err), err);
1010 #if defined (arch_ia64)
1012 sigaddset(&sigs, SIGTRAP);
1013 sigaddset(&sigs, SIGILL);
1014 sigaddset(&sigs, SIGSEGV);
1015 sigaddset(&sigs, SIGCHLD);
1016 sigaddset(&sigs, SIGALRM);
1017 int ret = pthread_sigmask(SIG_UNBLOCK, &sigs, NULL);
1019 fprintf(stderr, "%s[%d]: error setting thread sigmask: %s\%d\n",
1020 __FILE__, __LINE__, strerror(errno), errno);
1029 #if !defined (os_windows)
1030 void BPatch_asyncEventHandler::handlePauseRequest()
1033 pauseerr = pthread_mutex_lock(&pause_mutex);
1036 fprintf(stderr, "%s[%d]: Thr: Getting ready to pause\n", __FILE__, __LINE__);
1037 // request to pause thread has been issued, wait for signal
1038 pauseerr = pthread_cond_signal(&pause_cond);
1039 pauseerr = pthread_cond_wait(&pause_cond, &pause_mutex);
1041 fprintf(stderr, "%s[%d]: Thr: unpaused\n", __FILE__, __LINE__);
1042 // pause is over when signal received.
1046 pauseerr = pthread_mutex_unlock(&pause_mutex);
1049 void BPatch_asyncEventHandler::handleStopRequest()
1052 stoperr = pthread_mutex_lock(&pause_mutex);
1055 fprintf(stderr, "%s[%d]: Thr: Getting ready to stop\n", __FILE__, __LINE__);
1057 stoperr = pthread_mutex_unlock(&pause_mutex);
1060 stoperr = pthread_mutex_unlock(&pause_mutex);
1066 void BPatch_asyncEventHandler::main()
1068 #if defined (arch_ia64)
1070 sigaddset(&sigs, SIGTRAP);
1071 sigaddset(&sigs, SIGILL);
1072 sigaddset(&sigs, SIGSEGV);
1073 sigaddset(&sigs, SIGCHLD);
1074 sigaddset(&sigs, SIGALRM);
1075 int ret = pthread_sigmask(SIG_UNBLOCK, &sigs, NULL);
1077 fprintf(stderr, "%s[%d]: error setting thread sigmask: %s\%d\n",
1078 __FILE__, __LINE__, strerror(errno), errno);
1081 BPatch_asyncEventRecord ev;
1082 //fprintf(stderr, "%s[%d]: BPatch_asyncEventHandler::main(), thread id = %lu\n",
1083 // __FILE__, __LINE__, (unsigned long) pthread_self());
1086 #if !defined (os_windows)
1087 handlePauseRequest();
1088 handleStopRequest();
1091 if (waitNextEvent(ev)) {
1092 if (shutDownFlag) goto done; // want to flush here?
1093 if (ev.type == BPatch_nullEvent) continue;
1094 handleEvent(ev); // This is locked.
1097 // comms problem? what to do?
1098 bperr("%s[%d]: waitNextEvent returned false, async handler dying...\n",
1099 __FILE__, __LINE__);
1111 bool BPatch_asyncEventHandler::shutDown()
1113 if (!isRunning) goto close_comms;
1115 #if defined(os_windows)
1116 shutDownFlag = true;
1119 killres = pthread_kill(handler_thread, 9);
1121 fprintf(stderr, "%s[%d]: pthread_kill: %s[%d]\n", __FILE__, __LINE__,
1122 strerror(killres), killres);
1125 fprintf(stderr, "%s[%d]: \t\t..... killed.\n", __FILE__, __LINE__);
1134 #if !defined (os_windows)
1135 bool BPatch_asyncEventHandler::pause()
1139 err = pthread_mutex_lock(&pause_mutex);
1142 if ((paused) || (!isRunning)) {
1143 err = pthread_mutex_unlock(&pause_mutex);
1148 // set paused to true, even though we are not paused yet.
1151 // wait for thread to see that it should pause itself
1152 err = pthread_cond_wait(&pause_cond, &pause_mutex);
1157 err = pthread_mutex_unlock(&pause_mutex);
1163 bool BPatch_asyncEventHandler::unpause()
1166 err = pthread_mutex_lock(&pause_mutex);
1170 err = pthread_mutex_unlock(&pause_mutex);
1175 // set paused to false
1178 // and signal the thread (which is waiting on pause_cond)
1179 err = pthread_mutex_unlock(&pause_mutex);
1182 err = pthread_cond_signal(&pause_cond);
1187 bool BPatch_asyncEventHandler::stop()
1190 err = pthread_mutex_lock(&pause_mutex);
1193 err = pthread_mutex_unlock(&pause_mutex);
1198 err = pthread_mutex_unlock(&pause_mutex);
1201 err = pthread_join(handler_thread, NULL);
1203 return (!isRunning);
1205 bool BPatch_asyncEventHandler::resume()
1208 err = pthread_mutex_lock(&pause_mutex);
1211 err = pthread_mutex_unlock(&pause_mutex);
1216 return createThread();
1219 bool BPatch_asyncEventHandler::waitNextEvent(BPatch_asyncEventRecord &ev)
1222 // keep a static list of events in case we get several simultaneous
1223 // events from select()... just in case.
1225 static pdvector<BPatch_asyncEventRecord> event_queue;
1227 if (event_queue.size()) {
1228 // we already have one (from last call of this func)
1230 // this might result in an event reordering, not sure if important
1231 // (since we are removing from the end of the list)
1232 ev = event_queue[event_queue.size() - 1];
1233 event_queue.pop_back();
1244 struct timeval timeout;
1245 //timeout.tv_sec = 0;
1246 //timeout.tv_usec = 1000*100;
1247 #if defined(os_windows)
1248 timeout.tv_sec = 20;
1249 #elif defined(arch_ia64)
1254 timeout.tv_usec = 1;
1256 // start off with a NULL event:
1257 ev.type = BPatch_nullEvent;
1259 // build the set of fds we want to wait on, one fd per process
1260 for (unsigned int i = 0; i < process_fds.size(); ++i) {
1262 if (process_fds[i].fd == -1) continue; // waiting for connect/accept
1264 FD_SET(process_fds[i].fd, &readSet);
1265 FD_SET(process_fds[i].fd, &errSet);
1266 if (process_fds[i].fd > width)
1267 width = process_fds[i].fd;
1270 // Add the (listening) socket to set(s)
1271 FD_SET(sock, &readSet);
1275 // "width" is computed but ignored on Windows NT, where sockets
1276 // are not represented by nice little file descriptors.
1278 if (-1 == P_select(width+1, &readSet, NULL, &errSet, &timeout)) {
1279 bperr("%s[%d]: select returned -1\n", __FILE__, __LINE__);
1283 // See if we have any new connections (accept):
1284 if (FD_ISSET(sock, &readSet)) {
1286 struct sockaddr cli_addr;
1287 SOCKLEN_T clilen = sizeof(cli_addr);
1289 //fprintf(stderr, "%s[%d]: about to accept\n", __FILE__, __LINE__);
1291 int new_fd = P_accept(sock, (struct sockaddr *) &cli_addr, &clilen);
1293 bperr("%s[%d]: accept failed\n", __FILE__, __LINE__);
1297 //fprintf(stderr, "%s[%d]: about to read new connection\n", __FILE__, __LINE__);
1298 // do a (blocking) read so that we can get the pid associated with
1300 BPatch_asyncEventRecord pid_ev;
1301 if (! readEvent(new_fd, (void *) &pid_ev, sizeof(BPatch_asyncEventRecord))) {
1302 bperr("%s[%d]: readEvent failed\n", __FILE__, __LINE__);
1306 assert(pid_ev.type == BPatch_newConnectionEvent);
1308 ev.event_fd = new_fd;
1313 // See if we have any processes reporting events:
1315 for (unsigned int j = 0; j < process_fds.size(); ++j) {
1316 if (-1 == process_fds[j].fd) continue;
1318 // Possible race here, if mutator removes fd from set, but events
1321 if (FD_ISSET(process_fds[j].fd, &readSet)) {
1324 BPatch_asyncEventRecord new_ev;
1326 if (! readEvent(process_fds[j].fd, (void *) &new_ev,
1327 sizeof(BPatch_asyncEventRecord))) {
1328 // This read can fail if the mutatee has exited. Just note that this
1329 // fd is no longer valid, and keep quiet.
1330 //if (process_fds[j].process->isTerminated()) {
1332 // remove this process/fd from our vector
1333 //bpinfo("%s[%d]: readEvent failed due to process termination\n", __FILE__, __LINE__);
1334 for (unsigned int k = j+1; k < process_fds.size(); ++k) {
1335 process_fds[j] = process_fds[k];
1337 process_fds.pop_back();
1338 // and decrement counter so we examine this element (j) again
1342 bperr("%s[%d]: readEvent failed\n", __FILE__, __LINE__);
1346 if (ev.type != BPatch_nullEvent) {
1348 ev.event_fd = process_fds[j].fd;
1351 // Queue up events if we got more than one.
1353 if (new_ev.type != BPatch_nullEvent) {
1354 BPatch_asyncEventRecord qev = new_ev;
1355 qev.event_fd = process_fds[j].fd;
1356 event_queue.push_back(qev);
1365 fprintf(stderr, "%s[%d]: leaving waitNextEvent: events in queue:\n", __FILE__, __LINE__);
1366 for (unsigned int r = 0; r < event_queue.size(); ++r) {
1367 fprintf(stderr, "\t%s\n", asyncEventType2Str(event_queue[r].type));
1374 bool BPatch_asyncEventHandler::handleEventLocked(BPatch_asyncEventRecord &ev)
1376 //fprintf(stderr, "%s[%d]: inside handleEvent, got %s\n",
1377 // __FILE__, __LINE__, asyncEventType2Str(ev.type));
1380 BPatch_thread *appThread = NULL;
1381 ThreadLibrary *threadLibrary = NULL;
1383 // Go through our process list and find the appropriate record
1385 for (j = 0; j < process_fds.size(); ++j) {
1386 if (!process_fds[j].process) {
1387 fprintf(stderr, "%s[%d]: invalid process record!\n", __FILE__, __LINE__);
1390 unsigned int process_pid = process_fds[j].process->getPid();
1391 if (process_pid == ev.pid) {
1392 event_fd = process_fds[j].fd;
1393 appThread = process_fds[j].process;
1394 threadLibrary = process_fds[j].threadlib;
1401 if (ev.type == BPatch_nullEvent) return true;
1402 fprintf(stderr, "%s[%d]: ERROR: Got event for pid %d, but no proc\n",
1403 __FILE__, __LINE__, ev.pid);
1408 case BPatch_nullEvent:
1410 case BPatch_newConnectionEvent:
1412 // add this fd to the pair.
1413 // this fd will then be watched by select for new events.
1415 assert(event_fd == -1);
1416 process_fds[j].fd = ev.event_fd;
1419 fprintf(stderr, "%s[%d]: after handling new connection, we have\n", __FILE__, __LINE__);
1420 for (unsigned int t = 0; t < process_fds.size(); ++t) {
1421 fprintf(stderr, "\tpid = %d, fd = %d\n", process_fds[t].process->getPid(), process_fds[t].fd);
1427 case BPatch_internalShutDownEvent:
1430 case BPatch_threadCreateEvent:
1431 case BPatch_threadStartEvent:
1432 case BPatch_threadStopEvent:
1433 case BPatch_threadDestroyEvent:
1435 // Read auxilliary packet with dyn call info
1437 BPatch_threadEventRecord call_rec;
1438 if (!readEvent(ev.event_fd, (void *) &call_rec, sizeof(BPatch_threadEventRecord))) {
1439 bperr("%s[%d]: failed to read thread event call record\n",
1440 __FILE__, __LINE__);
1444 // BPatch_threadEventRecord contains specific info on this thread
1446 unsigned int tid = call_rec.tid;
1448 // find the callback list for this thread
1450 thread_event_cb_record *rec = NULL;
1451 pdvector<thread_event_cb_record> *event_cbs = getCBsForType(ev.type);
1452 if (!event_cbs) return false;
1454 for (unsigned int i = 0; i < event_cbs->size(); ++i) {
1455 if ((*event_cbs)[i].thread == appThread) {
1456 rec = &( (*event_cbs)[i] );
1462 // no record for this thread
1464 fprintf(stderr, "%s[%d]: FIXME ?? \n", __FILE__, __LINE__);
1465 fprintf(stderr, "%s[%d]: event_cbs.size() == %d\n", __FILE__, __LINE__, event_cbs->size());
1466 for (unsigned int i = 0; i < event_cbs->size(); ++i) {
1467 fprintf(stderr, "\t CB for thread %p, target = %p\n", (*event_cbs)[i].thread,appThread);
1473 pdvector<BPatchThreadEventCallback> *cbs = rec->cbs;
1475 // no callbacks for this event on this thread
1481 // no callbacks for this event on this thread
1486 // call all cbs in the list
1487 for (unsigned int j = 0; j < cbs->size(); ++j) {
1488 BPatchThreadEventCallback cb = (*cbs)[j];
1489 (cb)(appThread, tid);
1494 case BPatch_dynamicCallEvent:
1496 // Read auxilliary packet with dyn call info
1498 BPatch_dynamicCallRecord call_rec;
1499 if (!readEvent(ev.event_fd, (void *) &call_rec, sizeof(BPatch_dynamicCallRecord))) {
1500 bperr("%s[%d]: failed to read dynamic call record\n",
1501 __FILE__, __LINE__);
1505 Address callsite_addr = (Address) call_rec.call_site_addr;
1506 Address func_addr = (Address) call_rec.call_target;
1508 // find the record(s) for the pt that triggered this event
1511 pdvector<dyncall_cb_record *> pts;
1512 for (unsigned int i = 0; i < dyn_pts.size(); ++i) {
1513 if (dyn_pts[i].pt->getAddress() == (void *) callsite_addr) {
1514 pts.push_back(&(dyn_pts[i]));
1519 bperr("%s[%d]: failed to find async call point %p\n Valid Addrs:\n",
1520 __FILE__, __LINE__, callsite_addr);
1521 for (unsigned int r = 0; r < dyn_pts.size(); ++r) {
1522 bperr("\t%p\n", (void *) dyn_pts[r].pt->getAddress());
1527 // found the record(s), now find the function that was called
1528 int_function *f = appThread->proc->findFuncByAddr(func_addr);
1530 bperr("%s[%d]: failed to find BPatch_function\n",
1531 __FILE__, __LINE__);
1535 // find the BPatch_function...
1537 if (!appThread->proc->PDFuncToBPFuncMap.defines(f)) {
1538 bperr("%s[%d]: failed to find BPatch_function\n",
1539 __FILE__, __LINE__);
1543 BPatch_function *bpf = appThread->proc->PDFuncToBPFuncMap[f];
1546 bperr("%s[%d]: failed to find BPatch_function\n",
1547 __FILE__, __LINE__);
1551 // call the callback(s) and we're done:
1552 for (unsigned int j = 0; j < pts.size(); ++j) {
1554 BPatchDynamicCallSiteCallback cb = pts[j]->cb;
1555 BPatch_point *pt = pts[j]->pt;
1562 bperr("%s[%d]: request to handle unsupported event: %s\n",
1563 __FILE__, __LINE__, asyncEventType2Str(ev.type));
1571 bool BPatch_asyncEventHandler::mutateeDetach(BPatch_thread *p)
1573 BPatch_module *dyninstLib = NULL;
1574 for (unsigned int i = 0; i < process_fds.size(); ++i) {
1575 if (process_fds[i].process == p) {
1576 dyninstLib = process_fds[i].threadlib->getDyninstRT();
1580 // use oneTimeCode to call a function in the mutatee to handle
1581 // closing of the comms socket.
1582 if (!dyninstLib) return false;
1584 // find the function that will initiate the disconnection
1585 BPatch_Vector<BPatch_function *> funcs;
1586 if (!dyninstLib->findFunction("DYNINSTasyncDisconnect", funcs)
1587 || ! funcs.size() ) {
1588 bpfatal("%s[%d]: could not find function: DYNINSTasyncDisconnect\n",
1589 __FILE__, __LINE__);
1592 if (funcs.size() > 1) {
1593 bperr("%s[%d]: found %d varieties of function: DYNINSTasyncDisconnect\n",
1594 __FILE__, __LINE__, funcs.size());
1597 // The (int) argument to this function is our pid
1598 BPatch_Vector<BPatch_snippet *> args;
1599 args.push_back(new BPatch_constExpr(getpid()));
1600 BPatch_funcCallExpr disconnectcall(*funcs[0], args);
1602 // Run the connect call as oneTimeCode
1603 if (!p->oneTimeCode(disconnectcall)) {
1604 bpfatal("%s[%d]: failed to disconnect mutatee to async handler\n",
1605 __FILE__, __LINE__);
1613 BPatchSnippetHandle *
1614 BPatch_asyncEventHandler::instrumentThreadEvent(BPatch_thread *thread,
1615 ThreadLibrary *threadLib,
1616 BPatch_asyncEventType t,
1619 if (!f) return NULL;
1620 BPatchSnippetHandle *ret = NULL;
1621 BPatch_callWhen when = BPatch_callBefore;
1623 if (!threadLib->hasCapability(t)) {
1624 bperr("%s[%d]: thread event type %s not supported for thread lib %s\n",
1625 __FILE__, __LINE__, asyncEventType2Str(t), threadLib->getLibName());
1629 BPatch_Vector<BPatch_point *> pts;
1630 unsigned int numFuncs = threadLib->numberOfFuncsForEvent(t);
1632 // find entry point(s) for target inst funcs
1634 for (unsigned int i = 0; i < numFuncs; ++i) {
1635 BPatch_function *instruFunc = threadLib->funcForEvent(t,i);
1639 BPatch_Vector<BPatch_point *> *entryPoints = instruFunc->findPoint(BPatch_entry);
1640 if (!entryPoints || !entryPoints->size()) {
1642 bperr("%s[%d]: no entry points for function %s in module %s\n",
1643 __FILE__, __LINE__, instruFunc->getName(buf, 1024), threadLib->getLibName());
1646 if (entryPoints->size() > 1) {
1648 bperr("%s[%d]: WARN: %d entry points for function %s in module %s\n",
1649 __FILE__, __LINE__, entryPoints->size(), instruFunc->getName(buf, 1024),
1650 threadLib->getLibName());
1653 // construct function call and insert
1655 pts.push_back((*entryPoints)[0]);
1658 assert (pts.size());
1660 // generate function call snippet...
1662 BPatch_Vector<BPatch_snippet *> args;
1663 BPatch_funcCallExpr funcCall(*f, args);
1665 // ... and insert at all the interesting points we found.
1667 ret = thread->insertSnippet(funcCall, pts, when, BPatch_lastSnippet);
1670 bperr("%s[%d]: failed to insert instrumentation\n",
1671 __FILE__, __LINE__);
1677 ThreadLibrary *BPatch_asyncEventHandler::newThreadLibrary(BPatch_thread *thread)
1679 ThreadLibrary *tlib = new ThreadLibrary(thread, THREAD_LIB_NAME);
1680 if (!tlib->exists()) return tlib;
1681 #ifdef BPATCH_LIBRARY
1682 #if defined(os_windows)
1684 tlib->addThreadEventFunction(BPatch_threadCreateEvent, "_beginthread");
1685 tlib->addThreadEventFunction(BPatch_threadCreateEvent, "_beginthreadex");
1686 tlib->addThreadEventFunction(BPatch_threadDestroyEvent, "_endthread");
1687 tlib->addThreadEventFunction(BPatch_threadDestroyEvent, "_endthreadex");
1689 #elif defined(os_linux)
1690 tlib->addThreadEventFunction(BPatch_threadCreateEvent, "start_thread");
1691 tlib->addThreadEventFunction(BPatch_threadDestroyEvent, "pthread_exit");
1692 tlib->addThreadEventFunction(BPatch_threadStartEvent, "_longjmp");
1693 tlib->addThreadEventFunction(BPatch_threadStopEvent, "_usched_swtch");
1694 #elif defined(os_solaris)
1695 tlib->addThreadEventFunction(BPatch_threadCreateEvent, "_thrp_create");
1696 tlib->addThreadEventFunction(BPatch_threadDestroyEvent, "_thr_exit_common");
1697 #elif defined(os_aix)
1698 tlib->addThreadEventFunction(BPatch_threadCreateEvent, "_pthread_body");
1699 tlib->addThreadEventFunction(BPatch_threadDestroyEvent, "pthread_exit");
1700 tlib->addThreadEventFunction(BPatch_threadStartEvent, "_longjmp");
1701 tlib->addThreadEventFunction(BPatch_threadStopEvent, "_usched_swtch");
1702 #elif defined(os_osf)
1704 tlib->addThreadEventFunction(BPatch_threadCreateEvent, "_pthread_body");
1705 tlib->addThreadEventFunction(BPatch_threadDestroyEvent, "pthread_exit");
1706 tlib->addThreadEventFunction(BPatch_threadStartEvent, "_longjmp");
1707 tlib->addThreadEventFunction(BPatch_threadStopEvent, "_usched_swtch");
1709 #elif defined(os_irix)
1710 tlib->addThreadEventFunction(BPatch_threadCreateEvent, "_pthread_body");
1711 tlib->addThreadEventFunction(BPatch_threadDestroyEvent, "pthread_exit");
1712 tlib->addThreadEventFunction(BPatch_threadStartEvent, "_longjmp");
1713 tlib->addThreadEventFunction(BPatch_threadStopEvent, "_usched_swtch");
1715 #endif // BPATCH_LIBRARY
1719 #if defined(os_windows)
1721 bool BPatch_asyncEventHandler::readEvent(PDSOCKET fd, void *ev, ssize_t sz)
1723 fprintf(stderr, "%s[%d] about to recv\n", __FILE__, __LINE__);
1724 ssize_t bytes_read = 0;
1726 bytes_read = recv( fd, (char *)ev, sz, 0 );
1728 if ( PDSOCKET_ERROR == bytes_read ) {
1729 fprintf(stderr, "%s[%d]: read failed: %s:%d\n", __FILE__, __LINE__,
1730 strerror(errno), errno);
1734 if (0 == bytes_read) {
1735 // fd closed on other end (most likely)
1736 //bperr("%s[%d]: cannot read, fd is closed\n", __FILE__, __LINE__);
1740 if (bytes_read != sz) {
1741 bperr("%s[%d]: read wrong number of bytes!\n", __FILE__, __LINE__);
1742 bperr("FIXME: Need better logic to handle incomplete reads\n");
1746 fprintf(stderr, "%s[%d] done recv\n", __FILE__, __LINE__);
1751 bool BPatch_asyncEventHandler::readEvent(PDSOCKET fd, void *ev, ssize_t sz)
1753 ssize_t bytes_read = 0;
1756 #if defined(os_windows)
1757 bytes_read = _read(fd, ev , sz);
1759 bytes_read = read(fd, ev , sz);
1762 if ( (ssize_t)-1 == bytes_read ) {
1763 if (errno == EAGAIN || errno == EINTR)
1766 fprintf(stderr, "%s[%d]: read failed: %s:%d\n", __FILE__, __LINE__,
1767 strerror(errno), errno);
1771 if (0 == bytes_read) {
1772 // fd closed on other end (most likely)
1773 //bperr("%s[%d]: cannot read, fd is closed\n", __FILE__, __LINE__);
1777 if (bytes_read != sz) {
1778 bperr("%s[%d]: read wrong number of bytes! %d, not %d\n",
1779 __FILE__, __LINE__, bytes_read, sz);
1780 bperr("FIXME: Need better logic to handle incomplete reads\n");
1789 #ifndef CASE_RETURN_STR
1790 #define CASE_RETURN_STR(x) case x: return #x
1793 const char *asyncEventType2Str(BPatch_asyncEventType ev) {
1795 CASE_RETURN_STR(BPatch_nullEvent);
1796 CASE_RETURN_STR(BPatch_newConnectionEvent);
1797 CASE_RETURN_STR(BPatch_internalShutDownEvent);
1798 CASE_RETURN_STR(BPatch_threadCreateEvent);
1799 CASE_RETURN_STR(BPatch_threadStartEvent);
1800 CASE_RETURN_STR(BPatch_threadStopEvent);
1801 CASE_RETURN_STR(BPatch_threadDestroyEvent);
1802 CASE_RETURN_STR(BPatch_dynamicCallEvent);
1804 return "BadEventType";