Merge branch 'dyn_pc_integration' of ssh://wasabi.cs.wisc.edu/p/paradyn/development...
[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 "common/h/Types.h"
33
34 #include "proccontrol/src/int_thread_db.h"
35
36 #if defined(cap_thread_db)
37
38 #include <cassert>
39 #include <cerrno>
40 #include <cstdarg>
41 #include <cstring>
42 #include <set>
43
44 using namespace std;
45
46 #include "common/h/dthread.h"
47 #include "dynutil/h/SymReader.h"
48 #include "proccontrol/src/int_event.h"
49
50 static bool ll_fetchThreadInfo(td_thrhandle_t *th, td_thrinfo_t *info);
51
52 /* 
53  * proc_service interface implementation, needed by libthread_db
54  */
55
56 ps_err_e ps_pglobal_lookup(struct ps_prochandle *handle, const char *objName, 
57         const char *symName, psaddr_t *symbolAddr)
58 {
59     return handle->thread_db_proc->getSymbolAddr(objName, symName, symbolAddr);
60 }
61
62 ps_err_e ps_pread(struct ps_prochandle *handle, psaddr_t remote, void *local, size_t size) {
63     pthrd_printf("thread_db reading from %#lx to %#lx, size = %d on %d\n",
64             (unsigned long)remote, (unsigned long)local, (int)size, handle->thread_db_proc->getPid());
65
66     mem_response::ptr resp = mem_response::createMemResponse((char *) local, size);
67     bool result = handle->thread_db_proc->readMem((Dyninst::Address) remote, resp,
68                                                   handle->thread_db_proc->triggerThread());
69     if (!result) {
70        goto err;
71     }
72     result = int_process::waitForAsyncEvent(resp);
73     if (!result || resp->hasError()) {
74        goto err;
75     }
76     
77     return PS_OK;
78   err:
79     pthrd_printf("Failed to read from %#lx to %#lx, size = %d on %d: %s\n",
80                  (unsigned long)remote, (unsigned long)local, (int)size, handle->thread_db_proc->getPid(),
81                  strerror(errno));
82     return PS_ERR;
83 }
84
85 ps_err_e ps_pdread(struct ps_prochandle *handle, psaddr_t remote, void *local, size_t size) {
86    return ps_pread(handle, remote, local, size);
87 }
88
89 ps_err_e ps_ptread(struct ps_prochandle *handle, psaddr_t remote, void *local, size_t size) {
90    return ps_pread(handle, remote, local, size);
91 }
92
93 ps_err_e ps_pwrite(struct ps_prochandle *handle, psaddr_t remote, const void *local, size_t size) {
94     pthrd_printf("thread_db writing to %#lx from %#lx, size = %d on %d\n",
95             (unsigned long)remote, (unsigned long)local, (int)size, handle->thread_db_proc->getPid());
96     result_response::ptr resp = result_response::createResultResponse();
97     bool result = handle->thread_db_proc->writeMem(const_cast<void *>(local), (Dyninst::Address) remote, size, resp, 
98                                                    handle->thread_db_proc->triggerThread());
99     if (!result) {
100        goto err;
101     }
102     result = int_process::waitForAsyncEvent(resp);
103     if (!result || resp->hasError()) {
104        goto err;
105     }
106     
107     return PS_OK;
108   err:
109     pthrd_printf("Failed to write to %#lx from %#lx, size = %d on %d: %s\n",
110                  (unsigned long)remote, (unsigned long)local, (int)size, handle->thread_db_proc->getPid(),
111                  strerror(errno));
112     return PS_ERR;
113 }
114
115 ps_err_e ps_pdwrite(struct ps_prochandle *handle, psaddr_t remote, const void *local, size_t size) {
116    return ps_pwrite(handle, remote, local, size);
117 }
118
119 ps_err_e ps_ptwrite(struct ps_prochandle *handle, psaddr_t remote, const void *local, size_t size) {
120    return ps_pwrite(handle, remote, local, size);
121 }
122
123 ps_err_e ps_linfo(struct ps_prochandle *handle, lwpid_t lwp, void *lwpInfo) {
124     if( !handle->thread_db_proc->plat_getLWPInfo(lwp, lwpInfo) )
125         return PS_ERR;
126
127     return PS_OK;
128 }
129
130 ps_err_e ps_lstop(struct ps_prochandle *handle, lwpid_t lwp) {
131    int_process *proc = handle->thread_db_proc;
132    int_threadPool *tp = proc->threadPool();
133    assert(tp);
134    int_thread *thr = tp->findThreadByLWP((Dyninst::LWP) lwp);
135    if (!thr) {
136       perr_printf("ps_lstop is unable to find LWP %d in process %d\n",
137                   lwp, proc->getPid());
138       return PS_ERR;
139    }
140    pthrd_printf("ps_lstop on %d/%d\n", proc->getPid(), thr->getLWP());
141    
142    if (thr->getInternalState() == int_thread::stopped) {
143       return PS_OK;
144    }
145    else if (thr->getInternalState() != int_thread::running) {
146       perr_printf("Error, ps_lstop on thread in bad state\n");
147       return PS_ERR;
148    }
149    
150    if( !thr->intStop() ) {
151       return PS_ERR;
152    }
153    return PS_OK;
154 }
155
156 ps_err_e ps_lcontinue(struct ps_prochandle *handle, lwpid_t lwp) {
157    int_process *proc = handle->thread_db_proc;
158    int_threadPool *tp = proc->threadPool();
159    assert(tp);
160    int_thread *thr = tp->findThreadByLWP((Dyninst::LWP) lwp);
161    if (!thr) {
162       perr_printf("ps_lcontinue is unable to find LWP %d in process %d\n",
163                   lwp, proc->getPid());
164       return PS_ERR;
165    }
166    pthrd_printf("ps_lcontinue on %d/%d\n", proc->getPid(), thr->getLWP());
167    
168    if (thr->getInternalState() == int_thread::running) {
169       return PS_OK;
170    }
171    else if (thr->getInternalState() != int_thread::stopped) {
172       perr_printf("Error, ps_lcontinue on thread in bad state\n");
173       return PS_ERR;
174    }
175    
176    if( !thr->intCont() ) {
177       return PS_ERR;
178    }
179    return PS_OK;
180 }
181
182 ps_err_e ps_lgetregs(struct ps_prochandle *handle, lwpid_t lwp, prgregset_t regs) {
183     thread_db_process *proc = handle->thread_db_proc;
184     int_threadPool *tp = proc->threadPool();
185     assert(tp);
186     int_thread *llthr = tp->findThreadByLWP((Dyninst::LWP) lwp);
187     if (!llthr) {
188         perr_printf("ps_lgetregs is unable to find LWP %d in process %d\n",
189                 lwp, proc->getPid());
190         return PS_ERR;
191     }
192
193     thread_db_thread *thr = static_cast<thread_db_thread *>(llthr);
194
195     pthrd_printf("thread_db reading registers on thread %d/%d\n",
196             proc->getPid(), thr->getLWP());
197
198     int_registerPool pool;
199     allreg_response::ptr resp = allreg_response::createAllRegResponse(&pool);
200
201     bool hadError = false;
202     do{
203         if( !thr->getAllRegisters(resp) ) {
204             hadError = true;
205             break;
206         }
207         if( !int_process::waitForAsyncEvent(resp) || resp->hasError() ) {
208             hadError = true;
209             break;
210         }
211
212         if( !thr->plat_convertToSystemRegs(pool, (unsigned char *)regs) ) {
213             hadError = true;
214             break;
215         }
216     }while(0);
217
218     if( hadError ) {
219         perr_printf("failed to read registers on thread %d/%d\n",
220                 proc->getPid(), thr->getLWP());
221         return PS_ERR;
222     }
223
224     return PS_OK;
225 }
226
227 pid_t ps_getpid (struct ps_prochandle *ph)
228 {
229    return ph->thread_db_proc->getPid();
230 }
231
232 void     ps_plog(const char *format, ...) {
233     if( !dyninst_debug_proccontrol ) return;
234     if( NULL == format ) return;
235
236     va_list va;
237     va_start(va, format);
238     vfprintf(pctrl_err_out, format, va);
239     va_end(va);
240 }
241
242 #define NA_IMPLEMENTED "This function is not implemented"
243
244 ps_err_e ps_lgetfpregs(struct ps_prochandle *, lwpid_t, prfpregset_t *) {
245     assert(!NA_IMPLEMENTED);
246     return PS_ERR;
247 }
248
249 ps_err_e ps_lsetfpregs(struct ps_prochandle *, lwpid_t, const prfpregset_t *) {
250     assert(!NA_IMPLEMENTED);
251     return PS_ERR;
252 }
253
254 ps_err_e ps_lsetregs(struct ps_prochandle *, lwpid_t, const prgregset_t) {
255     assert(!NA_IMPLEMENTED);
256     return PS_ERR;
257 }
258
259 ps_err_e ps_lgetxmmregs (struct ps_prochandle *, lwpid_t, char *) {
260     assert(!NA_IMPLEMENTED);
261     return PS_ERR;
262 }
263
264 ps_err_e ps_lsetxmmregs (struct ps_prochandle *, lwpid_t, const char *) {
265     assert(!NA_IMPLEMENTED);
266     return PS_ERR;
267 }
268
269 ps_err_e ps_pcontinue(struct ps_prochandle *) {
270     assert(!NA_IMPLEMENTED);
271     return PS_ERR;
272 }
273
274 ps_err_e ps_pdmodel(struct ps_prochandle *, int *) {
275     assert(!NA_IMPLEMENTED);
276     return PS_ERR;
277 }
278
279 ps_err_e ps_pstop(struct ps_prochandle *) {
280     assert(!NA_IMPLEMENTED);
281     return PS_ERR;
282 }
283
284 ps_err_e ps_get_thread_area(const struct ps_prochandle *phandle, lwpid_t lwp, int val, psaddr_t *addr)
285 {
286    thread_db_process *tdb_proc = phandle->thread_db_proc;
287    thread_db_thread *tdb_thread = static_cast<thread_db_thread *>(tdb_proc->threadPool()->findThreadByLWP(lwp));
288
289    Dyninst::Address daddr = 0;
290    bool result = tdb_thread->plat_getThreadArea(val, daddr);
291    if (addr && result)
292       *addr = (psaddr_t) daddr;
293       
294    return result ? PS_OK : PS_ERR;
295 }
296
297 #ifndef CASE_RETURN_STR
298 #define CASE_RETURN_STR(x) case x: return #x;
299 #endif
300
301 static const char *tdErr2Str(td_err_e errVal) {
302     switch(errVal) {
303         CASE_RETURN_STR(TD_ERR)
304         CASE_RETURN_STR(TD_OK)
305         CASE_RETURN_STR(TD_BADKEY)
306         CASE_RETURN_STR(TD_BADPH)
307         CASE_RETURN_STR(TD_BADSH)
308         CASE_RETURN_STR(TD_BADTA)
309         CASE_RETURN_STR(TD_BADTH)
310         CASE_RETURN_STR(TD_DBERR)
311         CASE_RETURN_STR(TD_MALLOC)
312         CASE_RETURN_STR(TD_NOAPLIC)
313         CASE_RETURN_STR(TD_NOCAPAB)
314         CASE_RETURN_STR(TD_NOEVENT)
315         CASE_RETURN_STR(TD_NOFPREGS)
316         CASE_RETURN_STR(TD_NOLIBTHREAD)
317         CASE_RETURN_STR(TD_NOLWP)
318         CASE_RETURN_STR(TD_NOMSG)
319         CASE_RETURN_STR(TD_NOSV)
320         CASE_RETURN_STR(TD_NOTHR)
321         CASE_RETURN_STR(TD_NOTSD)
322         CASE_RETURN_STR(TD_NOXREGS)
323         CASE_RETURN_STR(TD_PARTIALREG)
324         default:
325             return "?";
326     }
327 }
328
329 Event::ptr thread_db_process::decodeThreadEvent(td_event_msg_t *eventMsg)
330 {
331    td_thrinfo_t info;
332    bool result = ll_fetchThreadInfo(const_cast<td_thrhandle_t *>(eventMsg->th_p), &info);
333    if (!result) {
334       pthrd_printf("Failed to fetch thread info\n");
335       return Event::ptr();
336    }
337    Dyninst::LWP lwp = (Dyninst::LWP) info.ti_lid;
338    switch(eventMsg->event) {
339       case TD_CREATE:
340       {
341          pthrd_printf("Decoded to user thread create of %d/%d\n", getPid(), lwp);
342          EventNewUserThread::ptr new_ev = EventNewUserThread::ptr(new EventNewUserThread());
343          int_eventNewUserThread *iev = new_ev->getInternalEvent();
344          
345          new_thread_data_t *thrdata = (new_thread_data_t *) malloc(sizeof(new_thread_data_t));
346          thrdata->thr_handle = new td_thrhandle_t(*(eventMsg->th_p));
347          thrdata->thr_info = info;
348          thrdata->threadHandle_alloced = true;
349
350          iev->raw_data = (void *) thrdata;
351          iev->lwp = lwp;
352
353          return new_ev;
354       }
355       case TD_DEATH: {
356          pthrd_printf("Decoded to user thread death of %d/%d\n", getPid(), lwp);
357          int_thread *thr = threadPool()->findThreadByLWP(lwp);
358          if (!thr) {
359             perr_printf("Error.  Got thread delete event for unknown LWP\n");
360             return Event::ptr();
361          }
362
363          EventUserThreadDestroy::ptr new_ev = EventUserThreadDestroy::ptr(new EventUserThreadDestroy(EventType::Pre));
364          new_ev->setProcess(proc());
365          new_ev->setThread(thr->thread());
366
367          return new_ev;
368       }
369       default: {
370          pthrd_printf("Unimplemented libthread_db event encountered. Skipping for now.\n");
371          break;
372       }
373    }
374
375    return Event::ptr();
376 }
377
378 volatile bool thread_db_process::thread_db_initialized = false;
379 Mutex thread_db_process::thread_db_init_lock;
380
381 thread_db_process::thread_db_process(Dyninst::PID p, std::string e, std::vector<std::string> envp, std::vector<std::string> a, std::map<int, int> f) :
382   int_process(p, e, a, envp, f),
383   thread_db_proc_initialized(false),
384   threadAgent(NULL),
385   trigger_thread(NULL),
386   needs_tid_update(false)
387 {
388   self = new ps_prochandle();
389   assert(self);
390   self->thread_db_proc = this;
391 }
392
393 thread_db_process::thread_db_process(Dyninst::PID pid_, int_process *p) :
394   int_process(pid_, p), 
395   thread_db_proc_initialized(false),
396   threadAgent(NULL),
397   trigger_thread(NULL),
398   needs_tid_update(false)  
399 {
400   self = new ps_prochandle();
401   assert(self);
402   self->thread_db_proc = this;
403 }
404
405 thread_db_process::~thread_db_process() 
406 {
407     // Free the breakpoints allocated for events
408     map<Dyninst::Address, pair<int_breakpoint *, EventType> >::iterator brkptIter;
409     for(brkptIter = addr2Event.begin(); brkptIter != addr2Event.end(); ++brkptIter) {
410         delete brkptIter->second.first;
411     }
412
413     delete self;
414 }
415
416 bool thread_db_process::needsTidUpdate()
417 {
418    return needs_tid_update;
419 }
420  
421 bool thread_db_process::updateTidInfo(vector<Event::ptr> &threadEvents)
422 {
423    if (!needsTidUpdate())
424       return true;
425    bool had_error = false;
426    
427    pthrd_printf("Trying to update TID information for %d\n", getPid());
428    for (int_threadPool::iterator i = threadPool()->begin(); i != threadPool()->end(); i++) {
429       thread_db_thread *thr = static_cast<thread_db_thread *>(*i);
430       if (thr->tinfo_initialized || !thr->thread_initialized)
431          continue;
432       pthrd_printf("%d/%d needs a TID info update\n", getPid(), thr->getLWP());
433       
434       if (!thr->threadHandle) {
435          thr->threadHandle = new td_thrhandle_t;
436          thr->threadHandle_alloced = true;
437       }
438       td_err_e errVal = td_ta_map_lwp2thr(getThreadDBAgent(), thr->getLWP(), thr->threadHandle);
439       if (errVal != TD_OK) {
440          perr_printf("Error. Failed to get new thread handle\n");
441          continue;
442       }
443
444       bool result = ll_fetchThreadInfo(thr->threadHandle, &thr->tinfo);
445       if (!result) {
446          perr_printf("%d/%d had an error while updating TID info\n", getPid(), thr->getLWP());
447          had_error = true;
448       }
449
450       if (!thr->tinfo.ti_tid) {
451          pthrd_printf("%d/%d still does not have valid TID info (lwp = %u)\n", getPid(), thr->getLWP(), (unsigned) thr->tinfo.ti_lid);
452          had_error = true;
453          continue;
454       }
455       pthrd_printf("%d/%d successfully updated TID info\n", getPid(), thr->getLWP());
456
457       EventNewUserThread::ptr new_ev = EventNewUserThread::ptr(new EventNewUserThread());
458       int_eventNewUserThread *iev = new_ev->getInternalEvent();
459       iev->needs_update = false;
460       iev->lwp = thr->getLWP();
461       threadEvents.push_back(new_ev);
462
463       pthrd_printf("Decoding new user thread to report updated TID info\n");
464    }
465    if (!had_error)
466       needs_tid_update = false;
467    return true;
468 }
469
470 thread_db_thread *thread_db_process::initThreadWithHandle(td_thrhandle_t *thr, td_thrinfo_t *info)
471 {
472    td_thrinfo_t tinfo;
473    if (!info) {
474       bool result = ll_fetchThreadInfo(thr, &tinfo);
475       if (!result) {
476          return false;
477       }
478       info = &tinfo;
479    }
480
481    Dyninst::LWP lwp = (Dyninst::LWP) info->ti_lid;
482    thread_db_thread *tdb_thread = static_cast<thread_db_thread *>(threadPool()->findThreadByLWP(lwp));
483    if (!tdb_thread) { 
484       perr_printf("Error.  Thread_db reports thread %d/%d, but couldn't find existing LWP\n",
485                   getPid(), lwp);
486       return NULL;
487    }
488    pthrd_printf("thread_db handling thread create for %d/%d\n", getPid(), lwp);
489    tdb_thread->threadHandle = thr;
490    tdb_thread->tinfo = *info;
491    if (info->ti_tid)
492       tdb_thread->tinfo_initialized = true;
493    else {
494       //On linux the TID of the initial thread isn't available at startup time.  
495       // We'll mark this and try to get the TID the next time a thread_db event
496       // comes along.
497       needs_tid_update = true;
498    }
499    tdb_thread->thread_initialized = true;
500
501    tdb_thread->setEventReporting(true);
502
503    return tdb_thread;
504 }
505
506
507 bool thread_db_process::handleThreadAttach(td_thrhandle_t *thr) {
508     return ( (initThreadWithHandle(thr, NULL) == NULL) ? false : true );
509 }
510
511 bool thread_db_process::initThreadDB() {
512     // Q: Why isn't this in the constructor? 
513     // A: This function depends on the corresponding thread library being loaded
514     // and this event occurs some time after process creation.
515
516     // Make sure thread_db is initialized - only once for all instances
517     if( !thread_db_initialized ) {
518         thread_db_init_lock.lock();
519         if( !thread_db_initialized ) {
520             td_err_e errVal;
521             if( TD_OK != (errVal = td_init()) ) {
522                 perr_printf("Failed to initialize libthread_db: %s(%d)\n",
523                         tdErr2Str(errVal), errVal);
524                 setLastError(err_internal, "libthread_db initialization failed");
525                 return false;
526             }
527             pthrd_printf("Sucessfully initialized thread_db\n");
528             thread_db_initialized = true;
529         }
530         thread_db_init_lock.unlock();
531     }
532     if (thread_db_proc_initialized) {
533        return true;
534     }
535
536     // Create the thread agent
537     td_err_e errVal = td_ta_new(self, &threadAgent);
538     switch(errVal) {
539         case TD_OK:
540             pthrd_printf("Retrieved thread agent from thread_db\n");
541             thread_db_proc_initialized = true;
542             break;
543         case TD_NOLIBTHREAD:
544             pthrd_printf("Debuggee isn't multithreaded at this point, libthread_db not enabled\n");
545             return true;
546         default:
547             perr_printf("Failed to create thread agent: %s(%d)\n",
548                     tdErr2Str(errVal), errVal);
549             thread_db_proc_initialized = true;
550             setLastError(err_internal, "Failed to create libthread_db agent");
551             return false;
552     }
553
554     set<td_thrhandle_t *> all_handles;
555     for (int_threadPool::iterator i = threadPool()->begin(); i != threadPool()->end(); i++) {
556        thread_db_thread *tdb_thread = static_cast<thread_db_thread *>(*i);
557        tdb_thread->threadHandle = new td_thrhandle_t;
558
559        errVal = td_ta_map_lwp2thr(getThreadDBAgent(), tdb_thread->getLWP(), tdb_thread->threadHandle);
560        if (errVal != TD_OK) {
561           perr_printf("Failed to map LWP %d to thread_db thread: %s(%d)\n",
562                       tdb_thread->getLWP(), tdErr2Str(errVal), errVal);
563           setLastError(err_internal, "Failed to get thread_db thread handle");
564           delete tdb_thread->threadHandle;
565           tdb_thread->threadHandle = NULL;
566           continue;
567        }
568        tdb_thread->threadHandle_alloced = true;
569
570        all_handles.insert(tdb_thread->threadHandle);
571     }
572
573     for (set<td_thrhandle_t *>::iterator i = all_handles.begin(); i != all_handles.end(); i++)
574     {
575        bool result = handleThreadAttach(*i);
576        if (!result) {
577           perr_printf("Error handling thread_db attach\n");
578        }
579     }
580
581     // Enable all events
582     td_thr_events_t eventMask;
583     td_event_fillset(&eventMask);
584
585     errVal = td_ta_set_event(threadAgent, &eventMask);
586     if( TD_OK != errVal ) {
587         perr_printf("Failed to enable events: %s(%d)\n",
588                 tdErr2Str(errVal), errVal);
589         setLastError(err_internal, "Failed to enable libthread_db events");
590         return false;
591     }
592
593     // Determine the addresses for all events
594     td_event_e allEvents[] = { TD_CATCHSIG, TD_CONCURRENCY, TD_CREATE,
595         TD_DEATH, TD_IDLE, TD_LOCK_TRY, TD_PREEMPT, TD_PRI_INHERIT,
596         TD_READY, TD_REAP, TD_SLEEP, TD_SWITCHFROM, TD_SWITCHTO,
597         TD_TIMEOUT };
598
599     for(unsigned i = 0; i < (sizeof(allEvents)/sizeof(td_event_e)); ++i) {
600         td_notify_t notifyResult;
601         errVal = td_ta_event_addr(threadAgent, allEvents[i], &notifyResult);
602
603         // This indicates that the event isn't supported
604         if( TD_OK != errVal ) continue;
605
606         assert( notifyResult.type == NOTIFY_BPT && "Untested notify type" );
607
608         EventType newEvent;
609         switch(allEvents[i]) {
610             case TD_CREATE:
611                 newEvent = EventType(EventType::Post, EventType::ThreadCreate);
612                 pthrd_printf("Installing breakpoint for thread creation events\n");
613                 break;
614             case TD_DEATH:
615                 newEvent = EventType(EventType::Post, EventType::ThreadDestroy);
616                 pthrd_printf("Installing breakpoint for thread destroy events\n");
617                 break;
618             default:
619                 pthrd_printf("Unimplemented libthread_db event encountered. Skipping for now.\n");
620                 continue;
621         }
622
623         if( !plat_convertToBreakpointAddress(notifyResult.u.bptaddr) ) {
624             perr_printf("Failed to determine breakpoint address\n");
625             setLastError(err_internal, "Failed to install new thread_db event breakpoint");
626             return false;
627         }
628
629         int_breakpoint *newEventBrkpt = new int_breakpoint(Breakpoint::ptr());
630         if( !addBreakpoint((Dyninst::Address)notifyResult.u.bptaddr,
631                     newEventBrkpt))
632         {
633             perr_printf("Failed to install new event breakpoint\n");
634             setLastError(err_internal, "Failed to install new thread_db event breakpoint");
635             delete newEventBrkpt;
636
637             return false;
638         }
639
640         pair<map<Dyninst::Address, pair<int_breakpoint *, EventType> >::iterator, bool> insertIter;
641         insertIter = addr2Event.insert(make_pair((Dyninst::Address)notifyResult.u.bptaddr,
642                     make_pair(newEventBrkpt, newEvent)));
643
644         assert( insertIter.second && "event breakpoint address not unique" );
645     }
646
647     return true;
648 }
649
650 bool thread_db_process::plat_convertToBreakpointAddress(psaddr_t &) {
651     // Default behavior is no translation
652     return true;
653 }
654
655 void thread_db_process::freeThreadDBAgent() {
656     // This code cannot be in the destructor because it makes use of
657     // the proc_service interface and this makes calls to functions
658     // that are pure virtual in this class.
659     //
660     // A possible, better solution would be to make the functions static
661     // but we lose all the convenience of pure virtual functions
662     //
663     // At any rate, this function should be called from a derived class' 
664     // destructor for the time being.
665
666     if( thread_db_initialized && threadAgent ) {
667         td_err_e errVal = td_ta_delete(threadAgent);
668         if( TD_OK != errVal ) {
669             perr_printf("Failed to delete thread agent: %s(%d)\n",
670                     tdErr2Str(errVal), errVal);
671         }
672         assert( TD_OK == errVal && "Failed to delete thread agent" );
673         threadAgent = NULL;
674     }
675 }
676
677 const char *thread_db_process::getThreadLibName(const char *)
678 {
679    return "";
680 }
681
682 bool thread_db_process::decodeTdbLWPExit(EventLWPDestroy::ptr lwp_ev)
683 {
684    thread_db_thread *db_thread = static_cast<thread_db_thread *>(lwp_ev->getThread()->llthrd());
685    assert(db_thread);
686    
687    if (db_thread->destroyed || !db_thread->thread_initialized)
688       return false;
689
690    pthrd_printf("Decoded LWP exit without thread exit on %d/%d.  Faking thread exit event\n",
691                 db_thread->llproc()->getPid(), db_thread->getLWP());
692    
693    EventUserThreadDestroy::ptr new_ev = EventUserThreadDestroy::ptr(new EventUserThreadDestroy(EventType::Pre));
694    new_ev->setProcess(db_thread->llproc()->proc());
695    new_ev->setThread(db_thread->thread());
696    lwp_ev->addSubservientEvent(new_ev);
697    return true;
698 }
699
700 bool thread_db_process::decodeTdbLibLoad(EventLibrary::ptr lib_ev)
701 {
702    if (!needsTidUpdate())
703       return false;
704    
705    pthrd_printf("Trying to update TID data upon library load event on %d\n", getPid());
706
707    vector<Event::ptr> threadEvents;
708    trigger_thread = lib_ev->getThread()->llthrd();
709    updateTidInfo(threadEvents);
710    
711    if (threadEvents.empty())
712       return false;
713
714    pthrd_printf("Decoding thread create with library load\n");
715    for (vector<Event::ptr>::iterator i = threadEvents.begin(); i != threadEvents.end(); i++) {
716       Event::ptr ev = *i;
717       if (!ev->getThread()) 
718          ev->setThread(lib_ev->getThread());
719       if (!ev->getProcess()) 
720          ev->setProcess(proc());
721       lib_ev->addSubservientEvent(ev);
722    }
723
724    return true;
725 }
726
727 bool thread_db_process::decodeTdbBreakpoint(EventBreakpoint::ptr bp)
728 {
729     Dyninst::Address addr = bp->getAddress();
730     
731     // Determine what type of event occurs at the specified address
732     map<Dyninst::Address, pair<int_breakpoint *, EventType> >::iterator addrIter;
733     addrIter = addr2Event.find(addr);
734     if( addrIter == addr2Event.end() ) 
735        return false;
736
737     vector<Event::ptr> threadEvents;
738     trigger_thread = bp->getThread()->llthrd();
739
740     if (needsTidUpdate())
741        updateTidInfo(threadEvents);
742
743     EventType::Code ecode = addrIter->second.second.code();
744     switch(ecode) {
745         case EventType::ThreadCreate: 
746         case EventType::ThreadDestroy:
747         {
748             pthrd_printf("Address 0x%lx corresponds to a thread %s event.\n",
749                          addr, ecode == EventType::ThreadCreate ? "create" : "destroy");
750             // Need to ask via the thread_db agent for creation events. This
751             // could result in getting information about other events.  All of
752             // these events need to be handled.
753             td_event_msg_t threadMsg;
754             td_err_e msgErr = TD_OK;
755             while(msgErr == TD_OK) {
756                 msgErr = td_ta_event_getmsg(threadAgent, &threadMsg);
757                 if( msgErr == TD_OK ) {
758                     Event::ptr threadEvent = decodeThreadEvent(&threadMsg);
759                     if( threadEvent ) {
760                         threadEvents.push_back(threadEvent);
761                     }
762                 }
763             }
764
765             if( msgErr != TD_NOMSG ) {
766                 perr_printf("Failed to retrieve thread event: %s(%d)\n",
767                         tdErr2Str(msgErr), msgErr);
768             }
769             break;
770         }
771         default:
772             pthrd_printf("Unimplemented libthread_db event encountered. Skipping for now.\n");
773             break;
774     }
775     trigger_thread = NULL;
776
777     if (threadEvents.empty())
778        return false;
779
780     for (vector<Event::ptr>::iterator i = threadEvents.begin(); i != threadEvents.end(); i++) {
781        Event::ptr ev = *i;
782        if (!ev->getThread()) 
783           ev->setThread(bp->getThread());
784        if (!ev->getProcess()) 
785           ev->setProcess(proc());
786        bp->addSubservientEvent(ev);
787     }
788     bp->setSuppressCB(true);
789     return true;
790 }
791
792 td_thragent_t *thread_db_process::getThreadDBAgent() {
793     return threadAgent;
794 }
795
796 static string stripLibraryName(const char *libname)
797 {
798    const char *filename_c = strrchr(libname, '/');
799    if (!filename_c)
800       filename_c = strrchr(libname, '\\');
801    if (!filename_c) 
802       filename_c = libname;
803    else 
804       filename_c++;
805    
806    const char *lesser_ext = NULL;
807    const char *dot_ext = strchr(filename_c, '.');
808    if (dot_ext)
809       lesser_ext = dot_ext;
810    const char *dash_ext = strchr(filename_c, '-');
811    if (dash_ext && (!lesser_ext || dash_ext < lesser_ext))
812       lesser_ext = dash_ext;
813
814    if (!lesser_ext) {
815       return std::string(filename_c);
816    }
817    return std::string(filename_c, lesser_ext - filename_c);
818 }
819
820 ps_err_e thread_db_process::getSymbolAddr(const char *objName, const char *symName,
821         psaddr_t *symbolAddr)
822 {
823     SymReader *objSymReader = NULL;
824     int_library *lib = NULL;
825     
826     if (plat_isStaticBinary()) {
827        // For static executables, we need to search the executable instead of the
828        // thread library. 
829        assert(memory()->libs.size() == 1);
830        lib = *memory()->libs.begin();
831     }
832     else
833     {
834        // FreeBSD implementation doesn't set objName
835        const char *name_c = objName ? objName : getThreadLibName(symName);
836        std::string name = stripLibraryName(name_c);
837        
838        for (set<int_library *>::iterator i = memory()->libs.begin(); i != memory()->libs.end(); i++) {
839           int_library *l = *i;
840           if (strstr(l->getName().c_str(), name.c_str())) {
841              lib = l;
842              break;
843           }
844        }
845     }
846
847     if( NULL == lib ) {
848        perr_printf("Failed to find loaded library\n");
849        setLastError(err_internal, "Failed to find loaded library");
850        return PS_ERR;
851     }
852
853     objSymReader = plat_defaultSymReader()->openSymbolReader(lib->getName());
854     if( NULL == objSymReader ) {
855         perr_printf("Failed to open symbol reader for %s\n",
856                     lib->getName().c_str());
857         setLastError(err_internal, "Failed to open executable for symbol reading");
858         return PS_ERR;
859     }
860
861     Symbol_t lookupSym = objSymReader->getSymbolByName(string(symName));
862
863     if( !objSymReader->isValidSymbol(lookupSym) ) {
864         return PS_NOSYM;
865     }
866
867     *symbolAddr = (psaddr_t) (lib->getAddr() + 
868                               objSymReader->getSymbolOffset(lookupSym));
869
870     return PS_OK;
871 }
872
873 bool thread_db_process::post_create() {
874     if( !int_process::post_create() ) return false;
875
876     return initThreadDB();
877 }
878
879 bool thread_db_process::post_attach() {
880     if( !int_process::post_attach() ) return false;
881
882     return initThreadDB();
883 }
884
885 bool thread_db_process::getPostDestroyEvents(vector<Event::ptr> &events) { 
886    unsigned oldSize = events.size();
887
888     int_threadPool::iterator i;
889     for(i = threadPool()->begin(); i != threadPool()->end(); ++i) {
890         thread_db_thread *tmpThread = static_cast<thread_db_thread *>(*i);
891         if( tmpThread->isDestroyed() ) {
892             pthrd_printf("Generating post-ThreadDestroy for %d/%d\n",
893                          getPid(), tmpThread->getLWP());
894
895             Event::ptr destroyEvent = Event::ptr(new EventUserThreadDestroy(EventType::Post));
896             destroyEvent->setThread(tmpThread->thread());
897             destroyEvent->setProcess(proc());
898             events.push_back(destroyEvent);
899         }
900     }
901
902     return events.size() != oldSize;
903 }
904
905 bool thread_db_process::isSupportedThreadLib(string libName) {
906    return (libName.find("libpthread") != string::npos);
907 }
908
909 void thread_db_process::addThreadDBHandlers(HandlerPool *hpool) {
910     static bool initialized = false;
911     static ThreadDBLibHandler *libHandler = NULL;
912     static ThreadDBCreateHandler *createHandler = NULL;
913     static ThreadDBDestroyHandler *destroyHandler = NULL;
914     if( !initialized ) {
915         libHandler = new ThreadDBLibHandler();
916         createHandler = new ThreadDBCreateHandler();
917         destroyHandler = new ThreadDBDestroyHandler();
918         initialized = true;
919     }
920     hpool->addHandler(libHandler);
921     hpool->addHandler(createHandler);
922     hpool->addHandler(destroyHandler);
923 }
924
925 bool thread_db_process::plat_getLWPInfo(lwpid_t, void *) 
926 {
927    perr_printf("Attempt to use unsupported plat_getLWPInfo\n");
928    return false;
929 }
930
931 bool thread_db_thread::plat_convertToSystemRegs(const int_registerPool &,
932         unsigned char *)
933 {
934     perr_printf("Attempt to use unsupported plat_convertToSystemRegs\n");
935     return true;
936 }
937
938 int_thread *thread_db_process::triggerThread() const
939 {
940    return trigger_thread;
941 }
942
943 ThreadDBLibHandler::ThreadDBLibHandler() :
944     Handler("thread_db Library Handler")
945 {
946 }
947
948 ThreadDBLibHandler::~ThreadDBLibHandler() 
949 {
950 }
951
952 Handler::handler_ret_t ThreadDBLibHandler::handleEvent(Event::ptr ev) {
953     EventLibrary::const_ptr libEv = ev->getEventLibrary();
954
955     thread_db_process *proc = dynamic_cast<thread_db_process *>(ev->getProcess()->llproc());
956
957     const set<Library::ptr> &addLibs = libEv->libsAdded();
958
959     set<Library::ptr>::iterator libIter;
960     for( libIter = addLibs.begin(); libIter != addLibs.end(); ++libIter ) {
961         if( ! proc->isSupportedThreadLib((*libIter)->getName()) )
962            continue;
963
964         pthrd_printf("Enabling thread_db support for pid %d\n",
965                      proc->getPid());
966         if( !proc->initThreadDB() ) {
967            pthrd_printf("Failed to initialize thread_db for pid %d\n",
968                         proc->getPid());
969            return Handler::ret_error;
970         }
971         break;
972     }
973
974     return Handler::ret_success;
975 }
976
977 int ThreadDBLibHandler::getPriority() const {
978     return PostPlatformPriority;
979 }
980
981 void ThreadDBLibHandler::getEventTypesHandled(vector<EventType> &etypes) {
982     etypes.push_back(EventType(EventType::None, EventType::Library));
983 }
984
985 ThreadDBCreateHandler::ThreadDBCreateHandler() :
986     Handler("thread_db New Thread Handler")
987 {
988 }
989
990 ThreadDBCreateHandler::~ThreadDBCreateHandler() 
991 {
992 }
993
994 Handler::handler_ret_t ThreadDBCreateHandler::handleEvent(Event::ptr ev) {
995     EventNewUserThread::ptr threadEv = ev->getEventNewUserThread();
996     if (threadEv->getInternalEvent()->needs_update) {
997        pthrd_printf("Updating user thread data for %d/%d in thread_db create handler\n",
998                     threadEv->getProcess()->llproc()->getPid(),
999                     threadEv->getNewThread()->llthrd()->getLWP());
1000        new_thread_data_t *thrdata = (new_thread_data_t *) threadEv->getInternalEvent()->raw_data;
1001        thread_db_process *tdb_proc = dynamic_cast<thread_db_process *>(ev->getProcess()->llproc());
1002        assert(tdb_proc);
1003        pthrd_printf("thread_db user create handler for %d/%d\n", tdb_proc->getPid(), threadEv->getLWP());
1004        
1005        thread_db_thread *newTdbThread = tdb_proc->initThreadWithHandle(thrdata->thr_handle, &thrdata->thr_info);
1006        if( newTdbThread == NULL ) return Handler::ret_error;
1007
1008        if( thrdata->threadHandle_alloced ) newTdbThread->threadHandle_alloced = true;
1009     }
1010
1011     return Handler::ret_success;
1012
1013 }
1014
1015 int ThreadDBCreateHandler::getPriority() const {
1016     return PostPlatformPriority;
1017 }
1018
1019 void ThreadDBCreateHandler::getEventTypesHandled(vector<EventType> &etypes) {
1020     etypes.push_back(EventType(EventType::None, EventType::UserThreadCreate));
1021 }
1022
1023 ThreadDBDestroyHandler::ThreadDBDestroyHandler() :
1024     Handler("thread_db Destroy Handler")
1025 {
1026 }
1027
1028 ThreadDBDestroyHandler::~ThreadDBDestroyHandler()
1029 {
1030 }
1031
1032 Handler::handler_ret_t ThreadDBDestroyHandler::handleEvent(Event::ptr ev) {
1033     thread_db_thread *thrd = static_cast<thread_db_thread *>(ev->getThread()->llthrd());
1034     if( ev->getEventType().time() == EventType::Pre) {
1035         pthrd_printf("Marking LWP %d destroyed\n", thrd->getLWP());
1036         thrd->markDestroyed();
1037     }else if( ev->getEventType().time() == EventType::Post) {
1038         // Need to make sure that the thread actually finishes and is cleaned up
1039         // by the OS
1040         if( !thrd->plat_resume() ) {
1041             perr_printf("Failed to resume LWP %d\n", thrd->getLWP());
1042             return Handler::ret_error;
1043         }
1044     }
1045
1046     return Handler::ret_success;
1047 }
1048
1049 int ThreadDBDestroyHandler::getPriority() const {
1050     return PrePlatformPriority;
1051 }
1052
1053 void ThreadDBDestroyHandler::getEventTypesHandled(vector<EventType> &etypes) {
1054     etypes.push_back(EventType(EventType::Any, EventType::UserThreadDestroy));
1055 }
1056
1057 thread_db_thread::thread_db_thread(int_process *p, Dyninst::THR_ID t, Dyninst::LWP l) :
1058    int_thread(p, t, l),
1059    threadHandle(NULL),
1060    destroyed(false),
1061    tinfo_initialized(false),
1062    thread_initialized(false),
1063    threadHandle_alloced(false)
1064 {
1065    memset(&tinfo, 0, sizeof(tinfo));
1066 }
1067
1068 thread_db_thread::~thread_db_thread() 
1069 {
1070    if (threadHandle_alloced)
1071       delete threadHandle;
1072 }
1073
1074 bool thread_db_thread::initThreadHandle() {
1075     if( NULL != threadHandle ) return true;
1076
1077     thread_db_process *lproc = dynamic_cast<thread_db_process *>(llproc());
1078     if( NULL == lproc->getThreadDBAgent() ) return false;
1079
1080     threadHandle = new td_thrhandle_t;
1081
1082     td_err_e errVal = td_ta_map_lwp2thr(lproc->getThreadDBAgent(),
1083             lwp, threadHandle);
1084     if( TD_OK != errVal ) {
1085         perr_printf("Failed to map LWP %d to thread_db thread: %s(%d)\n",
1086                 lwp, tdErr2Str(errVal), errVal);
1087         setLastError(err_internal, "Failed to get thread_db thread handle");
1088         delete threadHandle;
1089         threadHandle = NULL;
1090         return false;
1091     }
1092     threadHandle_alloced = true;
1093
1094     return true;
1095 }
1096
1097 Event::ptr thread_db_thread::getThreadEvent() {
1098     if( !initThreadHandle() ) return Event::ptr();
1099     thread_db_process *dbproc = dynamic_cast<thread_db_process *>(llproc());
1100
1101     td_event_msg_t eventMsg;
1102
1103     td_err_e errVal = td_thr_event_getmsg(threadHandle, &eventMsg);
1104
1105     if( TD_NOMSG == errVal ) {
1106         pthrd_printf("No message available for LWP %d via thread_db\n", lwp);
1107         return Event::ptr();
1108     }
1109
1110     if( TD_OK != errVal ) {
1111         perr_printf("Failed to get thread event message: %s(%d)\n",
1112                 tdErr2Str(errVal), errVal);
1113         setLastError(err_internal, "Failed to get thread event message");
1114         return Event::ptr();
1115     }
1116
1117     return dbproc->decodeThreadEvent(&eventMsg);
1118 }
1119
1120 bool thread_db_thread::setEventReporting(bool on) {
1121     if( !initThreadHandle() ) return false;
1122
1123     pthrd_printf("Enabling thread_db events for LWP %d\n", lwp);
1124     td_err_e errVal = td_thr_event_enable(threadHandle, (on ? 1 : 0 ));
1125     if( TD_OK != errVal ) {
1126         perr_printf("Failed to enable events for LWP %d: %s(%d)\n",
1127                 lwp, tdErr2Str(errVal), errVal);
1128         setLastError(err_internal, "Failed to enable thread_db events");
1129         return false;
1130     }
1131
1132     return true;
1133 }
1134
1135 static bool ll_fetchThreadInfo(td_thrhandle_t *th, td_thrinfo_t *info)
1136 {
1137    td_err_e result = td_thr_get_info(th, info);
1138    if (result != TD_OK) {
1139       perr_printf("Error calling td_thr_get_info: %s (%d)\n", tdErr2Str(result), (int) result);
1140       return false;      
1141    }
1142    return true;
1143 }
1144
1145 bool thread_db_thread::fetchThreadInfo() {
1146    if (!thread_initialized) {
1147       perr_printf("Attempt to read user thread info of %d/%d before user thread create\n",
1148                   llproc()->getPid(), getLWP());
1149       setLastError(err_nouserthrd, "Attempted to read user thread info, but user thread has not been created.");
1150       return false;
1151    }
1152    if( !initThreadHandle() ) return false;
1153    if (tinfo_initialized) {
1154       return true;
1155    }
1156
1157    pthrd_printf("Calling td_thr_get_info on %d/%d\n", llproc()->getPid(), getLWP());
1158    bool result = ll_fetchThreadInfo(threadHandle, &tinfo);
1159    if (!result) {
1160       return false;
1161    }
1162
1163    if( tinfo.ti_tid ) tinfo_initialized = true;
1164    return true;
1165 }
1166
1167 void thread_db_thread::markDestroyed() {
1168     destroyed = true;
1169 }
1170
1171 bool thread_db_thread::isDestroyed() {
1172     return destroyed;
1173 }
1174
1175 bool thread_db_thread::plat_getThreadArea(int, Dyninst::Address &)
1176 {
1177    assert(0); //Unsupported.  Currently only known to be needed on linux/x86_64
1178    return false;
1179 }
1180
1181 bool thread_db_thread::haveUserThreadInfo()
1182 {
1183    return thread_initialized;
1184 }
1185
1186 bool thread_db_thread::getTID(Dyninst::THR_ID &tid)
1187 {
1188    if (!fetchThreadInfo()) {
1189       return false;
1190    }
1191 #if defined(os_freebsd)
1192    tid = (Dyninst::THR_ID) tinfo.ti_thread;
1193 #else
1194    tid = (Dyninst::THR_ID) tinfo.ti_tid;
1195 #endif
1196    return true;
1197 }
1198
1199 bool thread_db_thread::getStartFuncAddress(Dyninst::Address &addr)
1200 {
1201    if (!fetchThreadInfo()) {
1202       return false;
1203    }
1204    addr = (Dyninst::Address) tinfo.ti_startfunc;
1205    return true;
1206 }
1207
1208 bool thread_db_thread::getStackBase(Dyninst::Address &addr)
1209 {
1210    if (!fetchThreadInfo()) {
1211       return false;
1212    }
1213    addr = (Dyninst::Address) tinfo.ti_stkbase;
1214    return true;
1215 }
1216
1217 bool thread_db_thread::getStackSize(unsigned long &size)
1218 {
1219    if (!fetchThreadInfo()) {
1220       return false;
1221    }
1222    size = (unsigned long) tinfo.ti_stksize;
1223    return true;
1224 }
1225
1226 bool thread_db_thread::getTLSPtr(Dyninst::Address &addr)
1227 {
1228    if (!fetchThreadInfo()) {
1229       return false;
1230    }
1231    addr = (Dyninst::Address) tinfo.ti_tls;
1232    return true;
1233 }
1234
1235 #else
1236
1237 //Empty place holder functions in-case we're built on a machine wihtout libthread_db.so
1238
1239 thread_db_process::thread_db_process(Dyninst::PID p, std::string e, std::vector<std::string> a, std::vector<std::string> envp, std::map<int, int> f) : 
1240    int_process(p, e, a, envp, f)
1241 {
1242 }
1243
1244 thread_db_process::thread_db_process(Dyninst::PID pid_, int_process *p) :
1245    int_process(pid_, p)
1246 {
1247 }
1248
1249 thread_db_process::~thread_db_process()
1250 {
1251 }
1252
1253 bool thread_db_process::decodeTdbLWPExit(EventLWPDestroy::ptr)
1254 {
1255    return false;
1256 }
1257
1258 bool thread_db_process::decodeTdbBreakpoint(EventBreakpoint::ptr)
1259 {
1260    return false;
1261 }
1262
1263 bool thread_db_process::decodeTdbLibLoad(EventLibrary::ptr)
1264 {
1265    return false;
1266 }
1267
1268 void thread_db_process::addThreadDBHandlers(HandlerPool *)
1269 {
1270 }
1271
1272 bool thread_db_process::plat_convertToBreakpointAddress(psaddr_t &) {
1273     return true;
1274 }
1275
1276 thread_db_thread::thread_db_thread(int_process *p, Dyninst::THR_ID t, Dyninst::LWP l) : 
1277    int_thread(p, t, l)
1278 {
1279 }
1280
1281 thread_db_thread::~thread_db_thread()
1282 {
1283 }
1284
1285 bool thread_db_thread::plat_getThreadArea(int, Dyninst::Address &)
1286 {
1287    assert(0); //Should not be called if there's no thread_db
1288    return false;
1289 }
1290
1291 bool thread_db_thread::haveUserThreadInfo()
1292 {
1293    return false;
1294 }
1295
1296 bool thread_db_thread::getTID(Dyninst::THR_ID &)
1297 {
1298    perr_printf("Error. thread_db not installed on this platform.\n");
1299    setLastError(err_unsupported, "Cannot perform thread operations without thread_db\n");
1300    return false;
1301 }
1302
1303 bool thread_db_thread::getStartFuncAddress(Dyninst::Address &)
1304 {
1305    perr_printf("Error. thread_db not installed on this platform.\n");
1306    setLastError(err_unsupported, "Cannot perform thread operations without thread_db\n");
1307    return false;
1308 }
1309
1310 bool thread_db_thread::getStackBase(Dyninst::Address &)
1311 {
1312    perr_printf("Error. thread_db not installed on this platform.\n");
1313    setLastError(err_unsupported, "Cannot perform thread operations without thread_db\n");
1314    return false;
1315 }
1316
1317 bool thread_db_thread::getStackSize(unsigned long &)
1318 {
1319    perr_printf("Error. thread_db not installed on this platform.\n");
1320    setLastError(err_unsupported, "Cannot perform thread operations without thread_db\n");
1321    return false;
1322 }
1323
1324 bool thread_db_thread::getTLSPtr(Dyninst::Address &)
1325 {
1326    perr_printf("Error. thread_db not installed on this platform.\n");
1327    setLastError(err_unsupported, "Cannot perform thread operations without thread_db\n");
1328    return false;
1329 }
1330
1331 #endif