Identify shared code regions
[dyninst.git] / proccontrol / src / int_thread_db.C
1 /*
2  * Copyright (c) 1996-2009 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  * By your use of Paradyn, you understand and agree that we (or any
12  * other person or entity with proprietary rights in Paradyn) are
13  * under no obligation to provide either maintenance services,
14  * update services, notices of latent defects, or correction of
15  * defects for Paradyn.
16  * 
17  * This library is free software; you can redistribute it and/or
18  * modify it under the terms of the GNU Lesser General Public
19  * License as published by the Free Software Foundation; either
20  * version 2.1 of the License, or (at your option) any later version.
21  * 
22  * This library is distributed in the hope that it will be useful,
23  * but WITHOUT ANY WARRANTY; without even the implied warranty of
24  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
25  * Lesser General Public License for more details.
26  * 
27  * You should have received a copy of the GNU Lesser General Public
28  * License along with this library; if not, write to the Free Software
29  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
30  */
31
32 #include <proc_service.h>
33 #include <thread_db.h>
34
35 #include <cassert>
36 #include <cerrno>
37 #include <set>
38 using std::set;
39
40 #include "common/h/dthread.h"
41 #include "dynutil/h/SymReader.h"
42 #include "int_thread_db.h"
43
44 /* 
45  * proc_service interface implementation, needed by libthread_db
46  */
47
48 ps_err_e ps_pglobal_lookup(struct ps_prochandle *handle, const char *objName, 
49         const char *symName, psaddr_t *symbolAddr)
50 {
51     return handle->thread_db_proc->getSymbolAddr(objName, symName, symbolAddr);
52 }
53
54 ps_err_e ps_pread(struct ps_prochandle *handle, psaddr_t remote, void *local, size_t size) {
55     pthrd_printf("thread_db reading from %#lx to %#lx, size = %d on %d\n",
56             (unsigned long)remote, (unsigned long)local, (int)size, handle->thread_db_proc->getPid());
57     if( !handle->thread_db_proc->plat_readProcMem(local, (Dyninst::Address)remote, size) )  {
58         pthrd_printf("Failed to read from %#lx to %#lx, size = %d on %d: %s\n",
59                     (unsigned long)remote, (unsigned long)local, (int)size, handle->thread_db_proc->getPid(),
60                     strerror(errno));
61         return PS_ERR;
62     }
63
64     return PS_OK;
65 }
66
67 ps_err_e ps_pwrite(struct ps_prochandle *handle, psaddr_t remote, const void *local, size_t size) {
68     pthrd_printf("thread_db writing to %#lx from %#lx, size = %d on %d\n",
69             (unsigned long)remote, (unsigned long)local, (int)size, handle->thread_db_proc->getPid());
70     if( !handle->thread_db_proc->plat_writeProcMem(const_cast<void *>(local), (Dyninst::Address)remote, size) ) {
71         pthrd_printf("Failed to write to %#lx from %#lx, size = %d on %d: %s\n",
72                 (unsigned long)remote, (unsigned long)local, (int)size, handle->thread_db_proc->getPid(),
73                 strerror(errno));
74         return PS_ERR;
75     }
76
77     return PS_OK;
78 }
79
80 ps_err_e ps_linfo(struct ps_prochandle *handle, lwpid_t lwp, void *lwpInfo) {
81     if( !handle->thread_db_proc->plat_getLWPInfo(lwp, lwpInfo) )
82         return PS_ERR;
83
84     return PS_OK;
85 }
86
87 ps_err_e ps_lstop(struct ps_prochandle *handle, lwpid_t lwp) {
88     if( !handle->thread_db_proc->plat_stopThread(lwp) ) {
89         return PS_ERR;
90     }
91
92     return PS_OK;
93 }
94
95 ps_err_e ps_lcontinue(struct ps_prochandle *handle, lwpid_t lwp) {
96     if( !handle->thread_db_proc->plat_contThread(lwp) ) {
97         return PS_ERR;
98     }
99
100     return PS_OK;
101 }
102
103 void     ps_plog(const char *format, ...) {
104     if( !dyninst_debug_proccontrol ) return;
105     if( NULL == format ) return;
106
107     va_list va;
108     va_start(va, format);
109     vfprintf(pctrl_err_out, format, va);
110     va_end(va);
111 }
112
113 #define NA_IMPLEMENTED "This function is not implemented"
114
115 ps_err_e ps_lgetfpregs(struct ps_prochandle *, lwpid_t, prfpregset_t *) {
116     assert(!NA_IMPLEMENTED);
117     return PS_ERR;
118 }
119
120 ps_err_e ps_lgetregs(struct ps_prochandle *, lwpid_t, prgregset_t) {
121     assert(!NA_IMPLEMENTED);
122     return PS_ERR;
123 }
124
125 ps_err_e ps_lsetfpregs(struct ps_prochandle *, lwpid_t, const prfpregset_t *) {
126     assert(!NA_IMPLEMENTED);
127     return PS_ERR;
128 }
129
130 ps_err_e ps_lsetregs(struct ps_prochandle *, lwpid_t, const prgregset_t) {
131     assert(!NA_IMPLEMENTED);
132     return PS_ERR;
133 }
134
135 ps_err_e ps_lgetxmmregs (struct ps_prochandle *, lwpid_t, char *) {
136     assert(!NA_IMPLEMENTED);
137     return PS_ERR;
138 }
139
140 ps_err_e ps_lsetxmmregs (struct ps_prochandle *, lwpid_t, const char *) {
141     assert(!NA_IMPLEMENTED);
142     return PS_ERR;
143 }
144
145 ps_err_e ps_pcontinue(struct ps_prochandle *) {
146     assert(!NA_IMPLEMENTED);
147     return PS_ERR;
148 }
149
150 ps_err_e ps_pdmodel(struct ps_prochandle *, int *) {
151     assert(!NA_IMPLEMENTED);
152     return PS_ERR;
153 }
154
155 ps_err_e ps_pstop(struct ps_prochandle *) {
156     assert(!NA_IMPLEMENTED);
157     return PS_ERR;
158 }
159
160 #ifndef CASE_RETURN_STR
161 #define CASE_RETURN_STR(x) case x: return #x;
162 #endif
163
164 static const char *tdErr2Str(td_err_e errVal) {
165     switch(errVal) {
166         CASE_RETURN_STR(TD_ERR)
167         CASE_RETURN_STR(TD_OK)
168         CASE_RETURN_STR(TD_BADKEY)
169         CASE_RETURN_STR(TD_BADPH)
170         CASE_RETURN_STR(TD_BADSH)
171         CASE_RETURN_STR(TD_BADTA)
172         CASE_RETURN_STR(TD_BADTH)
173         CASE_RETURN_STR(TD_DBERR)
174         CASE_RETURN_STR(TD_MALLOC)
175         CASE_RETURN_STR(TD_NOAPLIC)
176         CASE_RETURN_STR(TD_NOCAPAB)
177         CASE_RETURN_STR(TD_NOEVENT)
178         CASE_RETURN_STR(TD_NOFPREGS)
179         CASE_RETURN_STR(TD_NOLIBTHREAD)
180         CASE_RETURN_STR(TD_NOLWP)
181         CASE_RETURN_STR(TD_NOMSG)
182         CASE_RETURN_STR(TD_NOSV)
183         CASE_RETURN_STR(TD_NOTHR)
184         CASE_RETURN_STR(TD_NOTSD)
185         CASE_RETURN_STR(TD_NOXREGS)
186         CASE_RETURN_STR(TD_PARTIALREG)
187         default:
188             return "?";
189     }
190 }
191
192 static
193 Event::ptr decodeThreadEvent(td_event_msg_t *eventMsg) {
194     td_thrinfo_t threadInfo;
195     td_err_e errVal;
196     if( TD_OK != (errVal = td_thr_get_info((const td_thrhandle_t *)eventMsg->th_p, &threadInfo)) ) {
197         perr_printf("Failed to get thread event info from event msg: %s(%d)\n",
198                 tdErr2Str(errVal), errVal);
199         return Event::ptr();
200     }
201
202     switch(eventMsg->event) {
203         case TD_CREATE:
204             if( TD_OK != (errVal = td_thr_dbsuspend((const td_thrhandle_t *)eventMsg->th_p)) ) {
205                 perr_printf("Failed suspend new thread via thread_db: %s(%d)\n",
206                         tdErr2Str(errVal), errVal);
207                 return Event::ptr();
208             }
209             return Event::ptr(new EventNewThread((Dyninst::LWP)threadInfo.ti_lid));
210             break;
211         case TD_DEATH:
212             return Event::ptr(new EventThreadDestroy(EventType::Pre));
213             break;
214         default:
215             pthrd_printf("Unimplemented libthread_db event encountered. Skipping for now.\n");
216             break;
217     }
218
219     return Event::ptr();
220 }
221
222 volatile bool thread_db_process::thread_db_initialized = false;
223 Mutex thread_db_process::thread_db_init_lock;
224
225 thread_db_process::thread_db_process(Dyninst::PID p, std::string e, std::vector<std::string> a, std::map<int, int> f) :
226   int_process(p, e, a, f),
227   threadAgent(NULL)
228 {
229   self = new ps_prochandle();
230   assert(self);
231   self->thread_db_proc = this;
232 }
233
234 thread_db_process::thread_db_process(Dyninst::PID pid_, int_process *p) :
235   int_process(pid_, p), 
236   threadAgent(NULL)
237 {
238   self = new ps_prochandle();
239   assert(self);
240   self->thread_db_proc = this;
241 }
242
243 thread_db_process::~thread_db_process() 
244 {
245     // Free the breakpoints allocated for events
246     map<Dyninst::Address, pair<int_breakpoint *, EventType> >::iterator brkptIter;
247     for(brkptIter = addr2Event.begin(); brkptIter != addr2Event.end(); ++brkptIter) {
248         delete brkptIter->second.first;
249     }
250
251     delete self;
252 }
253
254 // A callback passed to td_ta_thr_iter
255 // A non-zero return value is an error
256 static
257 int bootstrap_cb(const td_thrhandle_t *handle, void * /* unused */) {
258     td_err_e errVal = td_thr_dbsuspend(handle);
259
260     if( TD_OK != errVal ) return 1;
261
262     errVal = td_thr_event_enable(handle, 1);
263
264     if( TD_OK != errVal ) return 1;
265
266     return 0;
267 }
268
269 bool thread_db_process::initThreadDB() {
270     // Q: Why isn't this in the constructor? 
271     // A: This function depends on the corresponding thread library being loaded
272     // and this event occurs some time after process creation.
273
274     // Make sure thread_db is initialized - only once for all instances
275     if( !thread_db_initialized ) {
276         thread_db_init_lock.lock();
277         if( !thread_db_initialized ) {
278             td_err_e errVal;
279             if( TD_OK != (errVal = td_init()) ) {
280                 perr_printf("Failed to initialize libthread_db: %s(%d)\n",
281                         tdErr2Str(errVal), errVal);
282                 setLastError(err_internal, "libthread_db initialization failed");
283                 return false;
284             }
285             pthrd_printf("Sucessfully initialized thread_db\n");
286             thread_db_initialized = true;
287         }
288         thread_db_init_lock.unlock();
289     }
290
291     // Create the thread agent
292     td_err_e errVal = td_ta_new(self, &threadAgent);
293     switch(errVal) {
294         case TD_OK:
295             pthrd_printf("Retrieved thread agent from thread_db\n");
296             break;
297         case TD_NOLIBTHREAD:
298             pthrd_printf("Debuggee isn't multithreaded at this point, libthread_db not enabled\n");
299             return true;
300         default:
301             perr_printf("Failed to create thread agent: %s(%d)\n",
302                     tdErr2Str(errVal), errVal);
303             setLastError(err_internal, "Failed to create libthread_db agent");
304             return false;
305     }
306
307     // Enable all events
308     td_thr_events_t eventMask;
309     td_event_fillset(&eventMask);
310
311     errVal = td_ta_set_event(threadAgent, &eventMask);
312     if( TD_OK != errVal ) {
313         perr_printf("Failed to enable events: %s(%d)\n",
314                 tdErr2Str(errVal), errVal);
315         setLastError(err_internal, "Failed to enable libthread_db events");
316         return false;
317     }
318
319     errVal = td_ta_thr_iter(threadAgent, bootstrap_cb, NULL,
320                 TD_THR_ANY_STATE, TD_THR_LOWEST_PRIORITY, TD_SIGNO_MASK,
321                 TD_THR_ANY_USER_FLAGS);
322
323     if( TD_OK != errVal ) {
324         perr_printf("Failed to enable events for specific-threads: %s(%d)\n",
325                 tdErr2Str(errVal), errVal);
326         setLastError(err_internal, "Failed to enable libthread_db events");
327         return false;
328     }
329
330     // Determine the addresses for all events
331     td_event_e allEvents[] = { TD_CATCHSIG, TD_CONCURRENCY, TD_CREATE,
332         TD_DEATH, TD_IDLE, TD_LOCK_TRY, TD_PREEMPT, TD_PRI_INHERIT,
333         TD_READY, TD_REAP, TD_SLEEP, TD_SWITCHFROM, TD_SWITCHTO,
334         TD_TIMEOUT };
335
336     for(unsigned i = 0; i < (sizeof(allEvents)/sizeof(td_event_e)); ++i) {
337         td_notify_t notifyResult;
338         errVal = td_ta_event_addr(threadAgent, allEvents[i], &notifyResult);
339
340         // This indicates that the event isn't supported
341         if( TD_OK != errVal ) continue;
342
343         assert( notifyResult.type == NOTIFY_BPT && "Untested notify type" );
344
345         EventType newEvent;
346         switch(allEvents[i]) {
347             case TD_CREATE:
348                 newEvent = EventType(EventType::Post, EventType::ThreadCreate);
349                 pthrd_printf("Installing breakpoint for thread creation events\n");
350                 break;
351             case TD_DEATH:
352                 newEvent = EventType(EventType::Post, EventType::ThreadDestroy);
353                 pthrd_printf("Installing breakpoint for thread destroy events\n");
354                 break;
355             default:
356                 pthrd_printf("Unimplemented libthread_db event encountered. Skipping for now.\n");
357                 continue;
358         }
359
360         int_breakpoint *newEventBrkpt = new int_breakpoint(Breakpoint::ptr());
361         if( !addBreakpoint((Dyninst::Address)notifyResult.u.bptaddr,
362                     newEventBrkpt))
363         {
364             perr_printf("Failed to install new event breakpoint\n");
365             setLastError(err_internal, "Failed to install new thread_db event breakpoint");
366             delete newEventBrkpt;
367
368             return false;
369         }
370
371         pair<map<Dyninst::Address, pair<int_breakpoint *, EventType> >::iterator, bool> insertIter;
372         insertIter = addr2Event.insert(make_pair((Dyninst::Address)notifyResult.u.bptaddr,
373                     make_pair(newEventBrkpt, newEvent)));
374
375         assert( insertIter.second && "event breakpoint address not unique" );
376     }
377
378     return true;
379 }
380
381 void thread_db_process::freeThreadDBAgent() {
382     // This code cannot be in the destructor because it makes use of
383     // the proc_service interface and this makes calls to functions
384     // that are pure virtual in this class.
385     //
386     // A possible, better solution would be to make the functions static
387     // but we lose all the convenience of pure virtual functions
388     //
389     // At any rate, this function should be called from a derived class' 
390     // destructor for the time being.
391
392     if( thread_db_initialized && threadAgent ) {
393         td_err_e errVal = td_ta_delete(threadAgent);
394         if( TD_OK != errVal ) {
395             perr_printf("Failed to delete thread agent: %s(%d)\n",
396                     tdErr2Str(errVal), errVal);
397         }
398         assert( TD_OK == errVal && "Failed to delete thread agent" );
399         threadAgent = NULL;
400     }
401 }
402
403 bool thread_db_process::getEventsAtAddr(Dyninst::Address addr, 
404         thread_db_thread *eventThread, vector<Event::ptr> &threadEvents) 
405 {
406     unsigned oldSize = threadEvents.size();
407
408     // Determine what type of event occurs at the specified address
409     map<Dyninst::Address, pair<int_breakpoint *, EventType> >::iterator addrIter;
410     addrIter = addr2Event.find(addr);
411     if( addrIter == addr2Event.end() ) return false;
412
413     switch(addrIter->second.second.code()) {
414         case EventType::ThreadCreate: 
415         {
416             pthrd_printf("Address 0x%lx corresponds to a thread create event.\n",
417                     addr);
418             // Need to ask via the thread_db agent for creation events. This
419             // could result in getting information about other events.  All of
420             // these events need to be handled.
421             td_event_msg_t threadMsg;
422             td_err_e msgErr = TD_OK;
423             while(msgErr == TD_OK) {
424                 msgErr = td_ta_event_getmsg(threadAgent, &threadMsg);
425                 if( msgErr == TD_OK ) {
426                     Event::ptr threadEvent = decodeThreadEvent(&threadMsg);
427                     if( threadEvent ) {
428                         threadEvents.push_back(threadEvent);
429                     }
430                 }
431             }
432
433             if( msgErr != TD_NOMSG ) {
434                 perr_printf("Failed to retrieve thread event: %s(%d)\n",
435                         tdErr2Str(msgErr), msgErr);
436             }
437             break;
438         }
439         case EventType::ThreadDestroy:
440         {
441             pthrd_printf("Address 0x%lx corresponds to a thread destroy event.\n",
442                     addr);
443             assert(eventThread);
444             Event::ptr threadEvent = eventThread->getThreadEvent();
445             if( threadEvent ) {
446                 threadEvents.push_back(threadEvent);
447             }else{
448                 perr_printf("Failed to retrieve thread event for LWP %d\n",
449                         eventThread->getLWP());
450             }
451             break;
452         }
453         default:
454             pthrd_printf("Unimplemented libthread_db event encountered. Skipping for now.\n");
455             break;
456     }
457
458     return oldSize != threadEvents.size();
459 }
460
461 td_thragent_t *thread_db_process::getThreadDBAgent() {
462     return threadAgent;
463 }
464
465 ps_err_e thread_db_process::getSymbolAddr(const char *objName, const char *symName,
466         psaddr_t *symbolAddr)
467 {
468     SymReader *objSymReader = NULL;
469     int_library *lib = NULL;
470     
471     if (plat_isStaticBinary()) {
472       // For static executables, we need to search the executable instead of the
473       // thread library. 
474        assert(memory()->libs.size() == 1);
475        lib = *memory()->libs.begin();
476     }
477     else
478     {
479         // FreeBSD implementation doesn't set objName
480         string name = objName ? objName : getThreadLibName(symName);
481         for (set<int_library *>::iterator i = memory()->libs.begin(); i != memory()->libs.end(); i++) {
482            int_library *l = *i;
483            if (strstr(l->getName().c_str(), name.c_str())) {
484               lib = l;
485               break;
486            }
487         }
488     }
489
490     if( NULL == lib ) {
491        perr_printf("Failed to find loaded library\n");
492        setLastError(err_internal, "Failed to find loaded library");
493        return PS_ERR;
494     }
495
496     objSymReader = plat_defaultSymReader()->openSymbolReader(lib->getName());
497     if( NULL == objSymReader ) {
498         perr_printf("Failed to open symbol reader for %s\n",
499                     lib->getName().c_str());
500         setLastError(err_internal, "Failed to open executable for symbol reading");
501         return PS_ERR;
502     }
503
504     Symbol_t lookupSym = objSymReader->getSymbolByName(string(symName));
505
506     if( !objSymReader->isValidSymbol(lookupSym) ) {
507         return PS_NOSYM;
508     }
509
510     *symbolAddr = (psaddr_t) (lib->getAddr() + 
511                               objSymReader->getSymbolOffset(lookupSym));
512
513     return PS_OK;
514 }
515
516 bool thread_db_process::post_create() {
517     if( !int_process::post_create() ) return false;
518
519     return initThreadDB();
520 }
521
522 bool thread_db_process::post_attach() {
523     if( !int_process::post_attach() ) return false;
524
525     return initThreadDB();
526 }
527
528 bool thread_db_process::getPostDestroyEvents(vector<Event::ptr> &events) {
529     unsigned oldSize = events.size();
530
531     int_threadPool::iterator i;
532     for(i = threadPool()->begin(); i != threadPool()->end(); ++i) {
533         thread_db_thread *tmpThread = static_cast<thread_db_thread *>(*i);
534         if( tmpThread->isDestroyed() ) {
535             pthrd_printf("Generating post-ThreadDestroy for %d/%d\n",
536                          getPid(), tmpThread->getLWP());
537
538             Event::ptr destroyEvent = Event::ptr(new EventThreadDestroy(EventType::Post));
539             destroyEvent->setThread(tmpThread->thread());
540             destroyEvent->setProcess(proc());
541             events.push_back(destroyEvent);
542         }
543     }
544
545     return events.size() != oldSize;
546 }
547
548 void thread_db_process::addThreadDBHandlers(HandlerPool *hpool) {
549     static bool initialized = false;
550     static ThreadDBLibHandler *libHandler = NULL;
551     static ThreadDBCreateHandler *createHandler = NULL;
552     static ThreadDBDestroyHandler *destroyHandler = NULL;
553     if( !initialized ) {
554         libHandler = new ThreadDBLibHandler();
555         createHandler = new ThreadDBCreateHandler();
556         destroyHandler = new ThreadDBDestroyHandler();
557         initialized = true;
558     }
559     hpool->addHandler(libHandler);
560     hpool->addHandler(createHandler);
561     hpool->addHandler(destroyHandler);
562 }
563
564 ThreadDBLibHandler::ThreadDBLibHandler() :
565     Handler("thread_db Library Handler")
566 {
567 }
568
569 ThreadDBLibHandler::~ThreadDBLibHandler() 
570 {
571 }
572
573 Handler::handler_ret_t ThreadDBLibHandler::handleEvent(Event::ptr ev) {
574     EventLibrary::const_ptr libEv = ev->getEventLibrary();
575
576     thread_db_process *proc = dynamic_cast<thread_db_process *>(ev->getProcess()->llproc());
577
578     const set<Library::ptr> &addLibs = libEv->libsAdded();
579
580     set<Library::ptr>::iterator libIter;
581     for( libIter = addLibs.begin(); libIter != addLibs.end(); ++libIter ) {
582         if( proc->isSupportedThreadLib((*libIter)->getName()) ) {
583             pthrd_printf("Enabling thread_db support for pid %d\n",
584                     proc->getPid());
585             if( !proc->initThreadDB() ) {
586                 pthrd_printf("Failed to initialize thread_db for pid %d\n",
587                         proc->getPid());
588                 return Handler::ret_error;
589             }
590             break;
591         }
592     }
593
594     return Handler::ret_success;
595 }
596
597 int ThreadDBLibHandler::getPriority() const {
598     return PostPlatformPriority;
599 }
600
601 void ThreadDBLibHandler::getEventTypesHandled(vector<EventType> &etypes) {
602     etypes.push_back(EventType(EventType::None, EventType::Library));
603 }
604
605 ThreadDBCreateHandler::ThreadDBCreateHandler() :
606     Handler("thread_db New Thread Handler")
607 {
608 }
609
610 ThreadDBCreateHandler::~ThreadDBCreateHandler() 
611 {
612 }
613
614 Handler::handler_ret_t ThreadDBCreateHandler::handleEvent(Event::ptr ev) {
615     EventNewThread::const_ptr threadEv = ev->getEventNewThread();
616
617     thread_db_thread *thread = static_cast<thread_db_thread *>(threadEv->getNewThread()->llthrd());
618
619     assert(thread && "Thread was not initialized before calling this handler");
620
621     // Because the new thread was created during a Breakpoint, it is already
622     // out of sync with the user state and the thread is in the stopped state
623     thread->desyncInternalState();
624
625     thread->setInternalState(int_thread::stopped);
626
627     // Explicitly ignore errors here
628     thread->setEventReporting(true);
629
630     return Handler::ret_success;
631 }
632
633 int ThreadDBCreateHandler::getPriority() const {
634     return PostPlatformPriority;
635 }
636
637 void ThreadDBCreateHandler::getEventTypesHandled(vector<EventType> &etypes) {
638     etypes.push_back(EventType(EventType::None, EventType::ThreadCreate));
639 }
640
641 ThreadDBDestroyHandler::ThreadDBDestroyHandler() :
642     Handler("thread_db Destroy Handler")
643 {
644 }
645
646 ThreadDBDestroyHandler::~ThreadDBDestroyHandler()
647 {
648 }
649
650 Handler::handler_ret_t ThreadDBDestroyHandler::handleEvent(Event::ptr ev) {
651     thread_db_thread *thrd = static_cast<thread_db_thread *>(ev->getThread()->llthrd());
652     if( ev->getEventType().time() == EventType::Pre) {
653         pthrd_printf("Marking LWP %d destroyed\n", thrd->getLWP());
654         thrd->markDestroyed();
655     }else if( ev->getEventType().time() == EventType::Post) {
656         // TODO this needs to be reworked -- it isn't quite right
657         // Need to make sure that the thread actually finishes and is cleaned up
658         // by the OS
659         thrd->plat_resume();
660     }
661
662     return Handler::ret_success;
663 }
664
665 int ThreadDBDestroyHandler::getPriority() const {
666     return PrePlatformPriority;
667 }
668
669 void ThreadDBDestroyHandler::getEventTypesHandled(vector<EventType> &etypes) {
670     etypes.push_back(EventType(EventType::Any, EventType::ThreadDestroy));
671 }
672
673 thread_db_thread::thread_db_thread(int_process *p, Dyninst::THR_ID t, Dyninst::LWP l)
674     : int_thread(p, t, l), threadHandle(NULL), destroyed(false)
675 {
676 }
677
678 thread_db_thread::~thread_db_thread() 
679 {
680     delete threadHandle;
681 }
682
683 bool thread_db_thread::initThreadHandle() {
684     if( NULL != threadHandle ) return true;
685
686     thread_db_process *lproc = dynamic_cast<thread_db_process *>(llproc());
687     if( NULL == lproc->getThreadDBAgent() ) return false;
688
689     threadHandle = new td_thrhandle_t;
690
691     td_err_e errVal = td_ta_map_lwp2thr(lproc->getThreadDBAgent(),
692             lwp, threadHandle);
693     if( TD_OK != errVal ) {
694         perr_printf("Failed to map LWP %d to thread_db thread: %s(%d)\n",
695                 lwp, tdErr2Str(errVal), errVal);
696         setLastError(err_internal, "Failed to get thread_db thread handle");
697         threadHandle = NULL;
698         return false;
699     }
700
701     return true;
702 }
703
704 Event::ptr thread_db_thread::getThreadEvent() {
705     if( !initThreadHandle() ) return Event::ptr();
706
707     td_event_msg_t eventMsg;
708
709     td_err_e errVal = td_thr_event_getmsg(threadHandle, &eventMsg);
710
711     if( TD_NOMSG == errVal ) {
712         pthrd_printf("No message available for LWP %d via thread_db\n", lwp);
713         return Event::ptr();
714     }
715
716     if( TD_OK != errVal ) {
717         perr_printf("Failed to get thread event message: %s(%d)\n",
718                 tdErr2Str(errVal), errVal);
719         setLastError(err_internal, "Failed to get thread event message");
720         return Event::ptr();
721     }
722
723     return decodeThreadEvent(&eventMsg);
724 }
725
726 bool thread_db_thread::setEventReporting(bool on) {
727     if( !initThreadHandle() ) return false;
728
729     td_err_e errVal = td_thr_event_enable(threadHandle, (on ? 1 : 0 ));
730
731     if( TD_OK != errVal ) {
732         perr_printf("Failed to enable events for LWP %d: %s(%d)\n",
733                 lwp, tdErr2Str(errVal), errVal);
734         setLastError(err_internal, "Failed to enable thread_db events");
735         return false;
736     }
737
738     pthrd_printf("Enabled thread_db events for LWP %d\n", lwp);
739
740     return true;
741 }
742
743 bool thread_db_thread::plat_resume() {
744     if( !initThreadHandle() ) return false;
745
746     td_err_e errVal = td_thr_dbresume(threadHandle);
747
748     if( TD_OK != errVal ) {
749         perr_printf("Failed to resume %d/%d: %s(%d)\n",
750                 llproc()->getPid(), lwp, tdErr2Str(errVal), errVal);
751         setLastError(err_internal, "Failed to resume LWP");
752         return false;
753     }
754
755     return true;
756 }
757
758 bool thread_db_thread::plat_suspend() {
759     if( !initThreadHandle() ) return false;
760
761     td_err_e errVal = td_thr_dbsuspend(threadHandle);
762
763     if( TD_OK != errVal ) {
764         perr_printf("Failed to suspend %d/%d: %s(%d)\n",
765                 llproc()->getPid(), lwp, tdErr2Str(errVal), errVal);
766         setLastError(err_internal, "Failed to suspend LWP");
767         return false;
768     }
769
770     return true;
771 }
772
773 void thread_db_thread::markDestroyed() {
774     destroyed = true;
775 }
776
777 bool thread_db_thread::isDestroyed() {
778     return destroyed;
779 }