First pass at thread_db integration for FreeBSD.
[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 <set>
37 using std::set;
38
39 #include "common/h/dthread.h"
40 #include "int_thread_db.h"
41
42 /* 
43  * proc_service interface implementation, needed by libthread_db
44  */
45
46 ps_err_e ps_pglobal_lookup(struct ps_prochandle *handle, const char *objName, 
47         const char *symName, psaddr_t *symbolAddr)
48 {
49     return handle->thread_db_proc->getSymbolAddr(objName, symName, symbolAddr);
50 }
51
52 ps_err_e ps_pread(struct ps_prochandle *handle, psaddr_t remote, void *local, size_t size) {
53     if( !handle->thread_db_proc->plat_readProcMem(local, (Dyninst::Address)remote, size) ) 
54         return PS_ERR;
55
56     return PS_OK;
57 }
58
59 ps_err_e ps_pwrite(struct ps_prochandle *handle, psaddr_t remote, const void *local, size_t size) {
60     if( !handle->thread_db_proc->plat_writeProcMem(const_cast<void *>(local), (Dyninst::Address)remote, size) )
61         return PS_ERR;
62
63     return PS_OK;
64 }
65
66 ps_err_e ps_linfo(struct ps_prochandle *handle, lwpid_t lwp, void *lwpInfo) {
67     if( !handle->thread_db_proc->plat_getLWPInfo(lwp, lwpInfo) )
68         return PS_ERR;
69
70     return PS_OK;
71 }
72
73 ps_err_e ps_lstop(struct ps_prochandle *handle, lwpid_t lwp) {
74     if( !handle->thread_db_proc->plat_stopThread(lwp) ) {
75         return PS_ERR;
76     }
77
78     return PS_OK;
79 }
80
81 ps_err_e ps_lcontinue(struct ps_prochandle *handle, lwpid_t lwp) {
82     if( !handle->thread_db_proc->plat_contThread(lwp) ) {
83         return PS_ERR;
84     }
85
86     return PS_OK;
87 }
88
89 void     ps_plog(const char *format, ...) {
90     if( !dyninst_debug_proccontrol ) return;
91     if( NULL == format ) return;
92
93     va_list va;
94     va_start(va, format);
95     vfprintf(pctrl_err_out, format, va);
96     va_end(va);
97 }
98
99 #define NA_IMPLEMENTED "This function is not implemented"
100
101 ps_err_e ps_lgetfpregs(struct ps_prochandle *, lwpid_t, prfpregset_t *) {
102     assert(!NA_IMPLEMENTED);
103     return PS_ERR;
104 }
105
106 ps_err_e ps_lgetregs(struct ps_prochandle *, lwpid_t, prgregset_t) {
107     assert(!NA_IMPLEMENTED);
108     return PS_ERR;
109 }
110
111 ps_err_e ps_lsetfpregs(struct ps_prochandle *, lwpid_t, const prfpregset_t *) {
112     assert(!NA_IMPLEMENTED);
113     return PS_ERR;
114 }
115
116 ps_err_e ps_lsetregs(struct ps_prochandle *, lwpid_t, const prgregset_t) {
117     assert(!NA_IMPLEMENTED);
118     return PS_ERR;
119 }
120
121 ps_err_e ps_lgetxmmregs (struct ps_prochandle *, lwpid_t, char *) {
122     assert(!NA_IMPLEMENTED);
123     return PS_ERR;
124 }
125
126 ps_err_e ps_lsetxmmregs (struct ps_prochandle *, lwpid_t, const char *) {
127     assert(!NA_IMPLEMENTED);
128     return PS_ERR;
129 }
130
131 ps_err_e ps_pcontinue(struct ps_prochandle *) {
132     assert(!NA_IMPLEMENTED);
133     return PS_ERR;
134 }
135
136 ps_err_e ps_pdmodel(struct ps_prochandle *, int *) {
137     assert(!NA_IMPLEMENTED);
138     return PS_ERR;
139 }
140
141 ps_err_e ps_pstop(struct ps_prochandle *) {
142     assert(!NA_IMPLEMENTED);
143     return PS_ERR;
144 }
145
146 #ifndef CASE_RETURN_STR
147 #define CASE_RETURN_STR(x) case x: return #x;
148 #endif
149
150 static const char *tdErr2Str(td_err_e errVal) {
151     switch(errVal) {
152         CASE_RETURN_STR(TD_ERR)
153         CASE_RETURN_STR(TD_OK)
154         CASE_RETURN_STR(TD_BADKEY)
155         CASE_RETURN_STR(TD_BADPH)
156         CASE_RETURN_STR(TD_BADSH)
157         CASE_RETURN_STR(TD_BADTA)
158         CASE_RETURN_STR(TD_BADTH)
159         CASE_RETURN_STR(TD_DBERR)
160         CASE_RETURN_STR(TD_MALLOC)
161         CASE_RETURN_STR(TD_NOAPLIC)
162         CASE_RETURN_STR(TD_NOCAPAB)
163         CASE_RETURN_STR(TD_NOEVENT)
164         CASE_RETURN_STR(TD_NOFPREGS)
165         CASE_RETURN_STR(TD_NOLIBTHREAD)
166         CASE_RETURN_STR(TD_NOLWP)
167         CASE_RETURN_STR(TD_NOMSG)
168         CASE_RETURN_STR(TD_NOSV)
169         CASE_RETURN_STR(TD_NOTHR)
170         CASE_RETURN_STR(TD_NOTSD)
171         CASE_RETURN_STR(TD_NOXREGS)
172         CASE_RETURN_STR(TD_PARTIALREG)
173         default:
174             return "?";
175     }
176 }
177
178 static
179 Event::ptr decodeThreadEvent(td_event_msg_t *eventMsg) {
180     td_thrinfo_t threadInfo;
181     td_err_e errVal;
182     if( TD_OK != (errVal = td_thr_get_info(eventMsg->th_p, &threadInfo)) ) {
183         perr_printf("Failed to get thread event info from event msg: %s(%d)\n",
184                 tdErr2Str(errVal), errVal);
185         return Event::ptr();
186     }
187
188     switch(eventMsg->event) {
189         case TD_CREATE:
190             return Event::ptr(new EventNewThread((Dyninst::LWP)threadInfo.ti_lid));
191             break;
192         case TD_DEATH:
193             return Event::ptr(new EventThreadDestroy(EventType::Pre));
194             break;
195         default:
196             pthrd_printf("Unimplemented libthread_db event encountered. Skipping for now.\n");
197             break;
198     }
199
200     return Event::ptr();
201 }
202
203 volatile bool thread_db_process::thread_db_initialized = false;
204
205 thread_db_process::thread_db_process(Dyninst::PID p, std::string e, std::vector<std::string> a)
206     : sysv_process(p, e, a), threadAgent(NULL)
207 {
208     self = new ps_prochandle();
209     self->thread_db_proc = this;
210     assert(self);
211 }
212
213 thread_db_process::thread_db_process(Dyninst::PID pid_, int_process *p) 
214     : sysv_process(pid_, p), threadAgent(NULL)
215 {
216     self = new ps_prochandle();
217     self->thread_db_proc = this;
218     assert(self);
219 }
220
221 thread_db_process::~thread_db_process() 
222 {
223     delete self;
224
225     if( thread_db_initialized && threadAgent ) {
226         td_err_e errVal = td_ta_delete(threadAgent);
227         if( TD_OK != errVal ) {
228             perr_printf("Failed to delete thread agent: %s(%d)\n",
229                     tdErr2Str(errVal), errVal);
230         }
231         assert( TD_OK == errVal && "Failed to delete thread agent" );
232     }
233
234     // Free the breakpoints allocated for events
235     map<Dyninst::Address, pair<int_breakpoint *, EventType> >::iterator brkptIter;
236     for(brkptIter = addr2Event.begin(); brkptIter != addr2Event.end(); ++brkptIter) {
237         delete brkptIter->second.first;
238     }
239
240     // Close all the symbol readers used
241     map<string, pair<LoadedLib *, SymReader *> >::iterator symReaderIter;
242     for(symReaderIter = symReaders.begin(); symReaderIter != symReaders.end(); 
243             ++symReaderIter)
244     {
245         symreader_factory->closeSymbolReader(symReaderIter->second.second);
246     }
247 }
248
249 bool thread_db_process::initThreadDB() {
250     // Q: Why isn't this in the constructor? 
251     // A: This function depends on the corresponding thread library being loaded
252     // and this event occurs some time after process creation.
253
254     // Make sure thread_db is initialized
255     if( !thread_db_initialized ) {
256         td_err_e errVal;
257         if( TD_OK != (errVal = td_init()) ) {
258             perr_printf("Failed to initialize libthread_db: %s(%d)\n",
259                     tdErr2Str(errVal), errVal);
260             setLastError(err_internal, "libthread_db initialization failed");
261             return false;
262         }
263         pthrd_printf("Sucessfully initialized thread_db\n");
264         thread_db_initialized = true;
265     }
266
267     // Create the thread agent
268     td_err_e errVal = td_ta_new(self, &threadAgent);
269     switch(errVal) {
270         case TD_OK:
271             break;
272         case TD_NOLIBTHREAD:
273             pthrd_printf("Debuggee isn't multithreaded at this point, libthread_db not enabled\n");
274             return true;
275         default:
276             perr_printf("Failed to create thread agent: %s(%d)\n",
277                     tdErr2Str(errVal), errVal);
278             setLastError(err_internal, "Failed to create libthread_db agent");
279             return false;
280     }
281
282     // Enable all events
283     td_thr_events_t eventMask;
284     td_event_fillset(&eventMask);
285
286     errVal = td_ta_set_event(threadAgent, &eventMask);
287     if( TD_OK != errVal ) {
288         perr_printf("Failed to enable events: %s(%d)\n",
289                 tdErr2Str(errVal), errVal);
290         setLastError(err_internal, "Failed to enable libthread_db events");
291         return false;
292     }
293
294     // Determine the addresses for all events
295     td_event_e allEvents[] = { TD_CATCHSIG, TD_CONCURRENCY, TD_CREATE,
296         TD_DEATH, TD_IDLE, TD_LOCK_TRY, TD_PREEMPT, TD_PRI_INHERIT,
297         TD_READY, TD_REAP, TD_SLEEP, TD_SWITCHFROM, TD_SWITCHTO,
298         TD_TIMEOUT };
299
300     for(unsigned i = 0; i < (sizeof(allEvents)/sizeof(td_event_e)); ++i) {
301         td_notify_t notifyResult;
302         errVal = td_ta_event_addr(threadAgent, allEvents[i], &notifyResult);
303
304         // This indicates that the event isn't supported
305         if( TD_OK != errVal ) continue;
306
307         assert( notifyResult.type == NOTIFY_BPT && "Untested notify type" );
308
309         EventType newEvent;
310         switch(allEvents[i]) {
311             case TD_CREATE:
312                 newEvent = EventType(EventType::Post, EventType::ThreadCreate);
313                 pthrd_printf("Installing breakpoint for thread creation events\n");
314                 break;
315             case TD_DEATH:
316                 newEvent = EventType(EventType::Post, EventType::ThreadDestroy);
317                 pthrd_printf("Installing breakpoint for thread destroy events\n");
318                 break;
319             default:
320                 pthrd_printf("Unimplemented libthread_db event encountered. Skipping for now.\n");
321                 continue;
322         }
323
324         int_breakpoint *newEventBrkpt = new int_breakpoint(Breakpoint::ptr());
325         if( !addBreakpoint((Dyninst::Address)notifyResult.u.bptaddr,
326                     newEventBrkpt))
327         {
328             perr_printf("Failed to install new event breakpoint\n");
329             setLastError(err_internal, "Failed to install new thread_db event breakpoint");
330             delete newEventBrkpt;
331
332             return false;
333         }
334
335         pair<map<Dyninst::Address, pair<int_breakpoint *, EventType> >::iterator, bool> insertIter;
336         insertIter = addr2Event.insert(make_pair((Dyninst::Address)notifyResult.u.bptaddr,
337                     make_pair(newEventBrkpt, newEvent)));
338
339         assert( insertIter.second && "event breakpoint address not unique" );
340     }
341
342     return true;
343 }
344
345 bool thread_db_process::getEventsAtAddr(Dyninst::Address addr, 
346         thread_db_thread *eventThread, vector<Event::ptr> &threadEvents) 
347 {
348     unsigned oldSize = threadEvents.size();
349
350     // Determine what type event occurs at the specified address
351     map<Dyninst::Address, pair<int_breakpoint *, EventType> >::iterator addrIter;
352     addrIter = addr2Event.find(addr);
353     if( addrIter == addr2Event.end() ) return false;
354
355     switch(addrIter->second.second.code()) {
356         case EventType::ThreadCreate: 
357         {
358             pthrd_printf("Address 0x%lx corresponds to a thread create event.\n",
359                     addr);
360             // Need to ask via the thread_db agent for creation events. This
361             // could result in getting information about other events.  All of
362             // these events need to be handled.
363             td_event_msg_t threadMsg;
364             td_err_e msgErr = TD_OK;
365             while(msgErr == TD_OK) {
366                 msgErr = td_ta_event_getmsg(threadAgent, &threadMsg);
367                 if( msgErr == TD_OK ) {
368                     Event::ptr threadEvent = decodeThreadEvent(&threadMsg);
369                     if( threadEvent ) {
370                         threadEvents.push_back(threadEvent);
371                     }
372                 }
373             }
374
375             if( msgErr != TD_NOMSG ) {
376                 perr_printf("Failed to retrieve thread event: %s(%d)\n",
377                         tdErr2Str(msgErr), msgErr);
378             }
379             break;
380         }
381         case EventType::ThreadDestroy:
382         {
383             pthrd_printf("Address 0x%lx corresponds to a thread destroy event.\n",
384                     addr);
385             assert(eventThread);
386             Event::ptr threadEvent = eventThread->getThreadEvent();
387             if( threadEvent ) {
388                 threadEvents.push_back(threadEvent);
389             }else{
390                 perr_printf("Failed to retrieve thread event for LWP %d\n",
391                         eventThread->getLWP());
392             }
393             break;
394         }
395         default:
396             pthrd_printf("Unimplemented libthread_db event encountered. Skipping for now.\n");
397             break;
398     }
399
400     return oldSize != threadEvents.size();
401 }
402
403 td_thragent_t *thread_db_process::getThreadDBAgent() {
404     return threadAgent;
405 }
406
407 ps_err_e thread_db_process::getSymbolAddr(const char *objName, const char *symName,
408         psaddr_t *symbolAddr)
409 {
410     SymReader *objSymReader = NULL;
411     LoadedLib *lib = NULL;
412
413     // For static executables, we need to search the executable instead of the
414     // thread library. 
415
416     // For static executables, breakpoint_addr isn't set
417     if( !breakpoint_addr ) {
418         lib = translator->getExecutable();
419         if( NULL == lib ) {
420             perr_printf("Failed to get loaded version of executable\n");
421             setLastError(err_internal, "Failed to get loaded version of executable");
422             return PS_ERR;
423         }
424
425         map<string, pair<LoadedLib *, SymReader *> >::iterator symReaderIter;
426         symReaderIter = symReaders.find(lib->getName());
427         if( symReaderIter == symReaders.end() ) {
428             objSymReader = symreader_factory->openSymbolReader(lib->getName());
429             if( NULL == objSymReader ) {
430                 perr_printf("Failed to open symbol reader for %s\n",
431                         lib->getName().c_str());
432                 setLastError(err_internal, "Failed to open executable for symbol reading");
433                 return PS_ERR;
434             }
435             symReaders.insert(make_pair(lib->getName(), make_pair(lib, objSymReader)));
436         }else{
437             objSymReader = symReaderIter->second.second;
438         }
439     }else{
440         // FreeBSD implementation doesn't set objName
441         string objNameStr;
442         if( NULL == objName ) {
443             objNameStr = getThreadLibName(symName);
444         }else{
445             objNameStr = objName;
446         }
447
448         map<string, pair<LoadedLib *, SymReader *> >::iterator symReaderIter;
449         symReaderIter = symReaders.find(objNameStr);
450         if( symReaderIter == symReaders.end() ) {
451             vector<LoadedLib *> libs;
452             if( !translator->getLibs(libs) ) {
453                 perr_printf("Failed to retrieve loaded libraries\n");
454                 setLastError(err_internal, "Failed to retrieve loaded libraries");
455                 return PS_ERR;
456             }
457
458             vector<LoadedLib *>::iterator loadedLibIter;
459             for(loadedLibIter = libs.begin(); loadedLibIter != libs.end();
460                     ++loadedLibIter)
461             {
462                 if( (*loadedLibIter)->getName().find(objNameStr) != string::npos ) {
463                     lib = (*loadedLibIter);
464                     break;
465                 }
466             }
467
468             if( NULL == lib ) {
469                 perr_printf("Failed to find loaded library for %s\n", objNameStr.c_str());
470                 setLastError(err_internal, "Failed to find loaded library");
471                 return PS_ERR;
472             }
473
474             objSymReader = symreader_factory->openSymbolReader(lib->getName());
475
476             if( NULL == objSymReader ) {
477                 perr_printf("Failed to open symbol reader for %s\n", objNameStr.c_str());
478                 setLastError(err_internal, "Failed to open library for symbol reading");
479                 return PS_ERR;
480             }
481
482             symReaders.insert(make_pair(objNameStr, make_pair(lib, objSymReader)));
483         }else{
484             lib = symReaderIter->second.first;
485             objSymReader = symReaderIter->second.second;
486         }
487     }
488
489     Symbol_t lookupSym = objSymReader->getSymbolByName(string(symName));
490
491     if( !objSymReader->isValidSymbol(lookupSym) ) {
492         return PS_NOSYM;
493     }
494
495     *symbolAddr = (psaddr_t)lib->offToAddress(
496             objSymReader->getSymbolOffset(lookupSym));
497
498     return PS_OK;
499 }
500
501 bool thread_db_process::post_create() {
502     if( !int_process::post_create() ) return false;
503
504     return initThreadDB();
505 }
506
507 bool thread_db_process::post_attach() {
508     if( !int_process::post_attach() ) return false;
509
510     return initThreadDB();
511 }
512
513 void thread_db_process::addThreadDBHandlers(HandlerPool *hpool) {
514     static bool initialized = false;
515     static ThreadDBLibHandler *libHandler = NULL;
516     static ThreadDBHandleNewThr *thrHandler = NULL;
517     if( !initialized ) {
518         libHandler = new ThreadDBLibHandler();
519         thrHandler = new ThreadDBHandleNewThr();
520         initialized = true;
521     }
522     hpool->addHandler(libHandler);
523     hpool->addHandler(thrHandler);
524 }
525
526 ThreadDBLibHandler::ThreadDBLibHandler() :
527     Handler("thread_db Library Handler")
528 {
529 }
530
531 ThreadDBLibHandler::~ThreadDBLibHandler() 
532 {
533 }
534
535 bool ThreadDBLibHandler::handleEvent(Event::ptr ev) {
536     EventLibrary::const_ptr libEv = ev->getEventLibrary();
537
538     thread_db_process *proc = static_cast<thread_db_process *>(ev->getProcess()->llproc());
539
540     const set<Library::ptr> &addLibs = libEv->libsAdded();
541
542     set<Library::ptr>::iterator libIter;
543     for( libIter = addLibs.begin(); libIter != addLibs.end(); ++libIter ) {
544         if( proc->isSupportedThreadLib((*libIter)->getName()) ) {
545             pthrd_printf("Enabling thread_db support for pid %d\n",
546                     proc->getPid());
547             if( !proc->initThreadDB() ) {
548                 pthrd_printf("Failed to initialize thread_db for pid %d\n",
549                         proc->getPid());
550                 return false;
551             }
552             break;
553         }
554     }
555
556     return true;
557 }
558
559 int ThreadDBLibHandler::getPriority() const {
560     return PostPlatformPriority;
561 }
562
563 void ThreadDBLibHandler::getEventTypesHandled(vector<EventType> &etypes) {
564     etypes.push_back(EventType(EventType::None, EventType::Library));
565 }
566
567 ThreadDBHandleNewThr::ThreadDBHandleNewThr() :
568     Handler("thread_db New Thread Handler")
569 {
570 }
571
572 ThreadDBHandleNewThr::~ThreadDBHandleNewThr() 
573 {
574 }
575
576 bool ThreadDBHandleNewThr::handleEvent(Event::ptr ev) {
577     EventNewThread::const_ptr threadEv = ev->getEventNewThread();
578
579     thread_db_thread *thread = static_cast<thread_db_thread *>(threadEv->getNewThread()->llthrd());
580
581     assert(thread && "Thread was not initialized before calling this handler");
582
583     // Explicitly ignore errors here
584     thread->setEventReporting(true);
585
586     return true;
587 }
588
589 int ThreadDBHandleNewThr::getPriority() const {
590     return PostPlatformPriority;
591 }
592
593 void ThreadDBHandleNewThr::getEventTypesHandled(vector<EventType> &etypes) {
594     etypes.push_back(EventType(EventType::None, EventType::ThreadCreate));
595 }
596
597 thread_db_thread::thread_db_thread(int_process *p, Dyninst::THR_ID t, Dyninst::LWP l)
598     : int_thread(p, t, l)
599 {
600 }
601
602 thread_db_thread::~thread_db_thread() 
603 {
604 }
605
606 Event::ptr thread_db_thread::getThreadEvent() {
607     thread_db_process *lproc = static_cast<thread_db_process *>(proc_);
608     td_thrhandle_t threadHandle;
609
610     // Get the thread handle
611     td_err_e errVal = td_ta_map_lwp2thr(lproc->getThreadDBAgent(),
612             lwp, &threadHandle);
613     if( TD_OK != errVal ) {
614         perr_printf("Failed to map lwp to thread_db thread: %s(%d)\n",
615                 tdErr2Str(errVal), errVal);
616         setLastError(err_internal, "Failed to get thread_db thread handle");
617         return Event::ptr();
618     }
619
620     td_event_msg_t eventMsg;
621
622     errVal = td_thr_event_getmsg(&threadHandle, &eventMsg);
623
624     if( TD_NOMSG == errVal ) {
625         pthrd_printf("No message available for LWP %d via thread_db\n", lwp);
626         return Event::ptr();
627     }
628
629     if( TD_OK != errVal ) {
630         perr_printf("Failed to get thread event message: %s(%d)\n",
631                 tdErr2Str(errVal), errVal);
632         setLastError(err_internal, "Failed to get thread event message");
633         return Event::ptr();
634     }
635
636     return decodeThreadEvent(&eventMsg);
637 }
638
639 bool thread_db_thread::setEventReporting(bool on) {
640     thread_db_process *lproc = static_cast<thread_db_process *>(proc_);
641     td_thrhandle_t threadHandle;
642
643     // Get the thread handle
644     td_err_e errVal = td_ta_map_lwp2thr(lproc->getThreadDBAgent(),
645             lwp, &threadHandle);
646     if( TD_OK != errVal ) {
647         perr_printf("Failed to map lwp to thread_db thread: %s(%d)\n",
648                 tdErr2Str(errVal), errVal);
649         setLastError(err_internal, "Failed to get thread_db thread handle");
650         return false;
651     }
652
653     errVal = td_thr_event_enable(&threadHandle, (on ? 1 : 0 ));
654
655     if( TD_OK != errVal ) {
656         perr_printf("Failed to enable events for LWP %d: %s(%d)\n",
657                 lwp, tdErr2Str(errVal), errVal);
658         setLastError(err_internal, "Failed to enable thread_db events");
659         return false;
660     }
661
662     pthrd_printf("Enabled thread_db events for LWP %d\n", lwp);
663
664     return true;
665 }