Convert Dyninst to use StackwalkerAPI
[dyninst.git] / dyninstAPI / src / freebsd.C
1 /*
2  * Copyright (c) 1996-2010 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 <cassert>
33
34 #include "freebsd.h"
35 #include "dyn_lwp.h"
36 #include "process.h"
37 #include "syscallNotification.h"
38 #include "dynamiclinking.h"
39 #include "signalgenerator.h"
40 #include "binaryEdit.h"
41 #include "mapped_object.h"
42
43 void loadNativeDemangler() {}
44
45 bool BinaryEdit::getResolvedLibraryPath(const std::string &filename, std::vector<std::string> &paths) {
46     char *libPathStr, *libPath;
47     std::vector<std::string> libPaths;
48     struct stat dummy;
49     FILE *ldconfig;
50     char buffer[512];
51
52     // prefer qualified file paths
53     if (stat(filename.c_str(), &dummy) == 0) {
54         paths.push_back(filename);
55     }
56
57     // search paths from environment variables
58     libPathStr = strdup(getenv("LD_LIBRARY_PATH"));
59     libPath = strtok(libPathStr, ":");
60     while (libPath != NULL) {
61         libPaths.push_back(std::string(libPath));
62         libPath = strtok(NULL, ":");
63     }
64     free(libPathStr);
65
66     for (unsigned int i = 0; i < libPaths.size(); i++) {
67         std::string str = libPaths[i] + "/" + filename;
68         if (stat(str.c_str(), &dummy) == 0) {
69             paths.push_back(str);
70         }
71     }
72
73     // search ld.so hints file
74     ldconfig = popen("/sbin/ldconfig -r", "r");
75     if( ldconfig ) {
76         // ignore first and second line
77         fgets(buffer, 512, ldconfig);
78         fgets(buffer, 512, ldconfig);
79
80         // Here is the expected format:
81         // [^/]* => (path)/(filename)
82         while(fgets(buffer, 512, ldconfig) != NULL) {
83             size_t fileBegin, pathBegin;
84
85             // Remove any whitespace at the end
86             std::string strBuf(buffer);
87             strBuf = strBuf.substr(0, strBuf.find_last_not_of(" \t\n\r")+1);
88
89             // Locate the filename
90             fileBegin = strBuf.rfind("/");
91             if( fileBegin == std::string::npos ||
92                 fileBegin+1 >= strBuf.length() ) continue;
93
94             if( strBuf.substr(fileBegin+1) == filename ) {
95                 // Locate the path
96                 pathBegin = strBuf.find("/");
97                 if( pathBegin == std::string::npos ) continue;
98                 paths.push_back(strBuf.substr(pathBegin));
99             }
100         }
101
102         pclose(ldconfig);
103     }
104
105     // search hard-coded system paths
106     libPaths.clear();
107     libPaths.push_back("/lib");
108     libPaths.push_back("/usr/lib");
109     libPaths.push_back("/usr/local/lib");
110     for (unsigned int i = 0; i < libPaths.size(); i++) {
111         std::string str = libPaths[i] + "/" + filename;
112         if (stat(str.c_str(), &dummy) == 0) {
113             paths.push_back(str);
114         }
115     }
116
117     return ( 0 < paths.size() );
118 }
119
120 sharedLibHook::~sharedLibHook() {}
121
122 bool BinaryEdit::archSpecificMultithreadCapable() {
123     /*
124      * The heuristic on FreeBSD is to check for some symbols that are
125      * only included in a binary when pthreads has been linked into the
126      * binary. If the binary contains these symbols, it is multithread
127      * capable.
128      */
129     const int NUM_PTHREAD_SYMS = 6;
130     const char *pthreadSyms[NUM_PTHREAD_SYMS] =
131     { "pthread_attr_get_np", "pthread_attr_getaffinity_np",
132       "pthread_attr_getstack", "pthread_attr_setaffinity_np",
133       "pthread_attr_setcreatesuspend_np", "pthread_attr_setstack"
134     };
135
136     if( mobj->isStaticExec() ) {
137         int numSymsFound = 0;
138         for(int i = 0; i < NUM_PTHREAD_SYMS; ++i) {
139             const pdvector<int_function *> *tmpFuncs = 
140                 mobj->findFuncVectorByPretty(pthreadSyms[i]);
141             if( tmpFuncs != NULL && tmpFuncs->size() ) numSymsFound++;
142         }
143
144         if( numSymsFound == NUM_PTHREAD_SYMS ) return true;
145     }
146
147     return false;
148 }
149
150 bool AddressSpace::getDyninstRTLibName() {
151    startup_printf("dyninstRT_name: %s\n", dyninstRT_name.c_str());
152     if (dyninstRT_name.length() == 0) {
153         // Get env variable
154         if (getenv("DYNINSTAPI_RT_LIB") != NULL) {
155             dyninstRT_name = getenv("DYNINSTAPI_RT_LIB");
156         }
157         else {
158            std::string msg;
159            process *proc;
160            if ((proc = dynamic_cast<process *>(this)) != NULL) {
161               msg = std::string("Environment variable ") +
162                  std::string("DYNINSTAPI_RT_LIB") +
163                  std::string(" has not been defined for process ") +
164                  utos(proc->getPid());
165            }
166            else {
167               msg = std::string("Environment variable ") +
168                  std::string("DYNINSTAPI_RT_LIB") +
169                  std::string(" has not been defined");
170            }           
171            showErrorCallback(101, msg);
172            return false;
173         }
174     }
175
176     // Automatically choose 32-bit library if necessary.
177     const char *modifier = "_m32";
178     const char *name = dyninstRT_name.c_str();
179
180     const char *split = P_strrchr(name, '/');
181     if ( !split ) split = name;
182     split = P_strchr(split, '.');
183     if ( !split || P_strlen(split) <= 1 ) {
184         // We should probably print some error here.
185         // Then, of course, the user will find out soon enough.
186         startup_printf("Invalid Dyninst RT lib name: %s\n", 
187                 dyninstRT_name.c_str());
188         return false;
189     }
190
191     if ( getAddressWidth() == sizeof(void *) || P_strstr(name, modifier) ) {
192         modifier = "";
193     }
194
195     const char *suffix = split;
196     if( getAOut()->isStaticExec() ) {
197         suffix = ".a";
198     }else{
199         if( P_strncmp(suffix, ".a", 2) == 0 ) {
200             // This will be incorrect if the RT library's version changes
201             suffix = ".so";
202         }
203     }
204
205     dyninstRT_name = std::string(name, split - name) +
206                      std::string(modifier) +
207                      std::string(suffix);
208
209     startup_printf("Dyninst RT Library name set to '%s'\n",
210             dyninstRT_name.c_str());
211
212     // Check to see if the library given exists.
213     if (access(dyninstRT_name.c_str(), R_OK)) {
214         std::string msg = std::string("Runtime library ") + dyninstRT_name
215         + std::string(" does not exist or cannot be accessed!");
216         showErrorCallback(101, msg);
217         return false;
218     }
219
220     return true;
221 }
222
223 PCEventHandler::CallbackBreakpointCase
224 PCEventHandler::getCallbackBreakpointCase(EventType et) {
225     // This switch statement can be derived from the EventTypes and Events
226     // table in the ProcControlAPI manual -- it states what Events are
227     // available on each platform
228
229     switch(et.code()) {
230         case EventType::Fork:
231             switch(et.time()) {
232                 case EventType::Pre:
233                     return BreakpointOnly;
234                 case EventType::Post:
235                     return BothCallbackBreakpoint;
236                 default:
237                     break;
238             }
239             break;
240         case EventType::Exit:
241             switch(et.time()) {
242                 case EventType::Pre:
243                     // Using the RT library breakpoint allows us to determine
244                     // the exit code in a uniform way across Unices
245                     return BreakpointOnly;
246                 case EventType::Post:
247                     return CallbackOnly;
248                 default:
249                     break;
250             }
251             break;
252        case EventType::Exec:
253             switch(et.time()) {
254                 case EventType::Post:
255                     return CallbackOnly;
256                 default:
257                     break;
258             }
259             break;
260     }
261
262     return NoCallbackOrBreakpoint;
263 }
264
265 /* START unimplemented functions */
266
267 #define FREEBSD_NOT_IMPLEMENTED "This function is not implemented on FreeBSD"
268
269 void initPrimitiveCost() {
270     assert(!FREEBSD_NOT_IMPLEMENTED);
271 }
272
273 void dyninst_yield() {
274     assert(!FREEBSD_NOT_IMPLEMENTED);
275 }
276
277 bool dyn_lwp::stop_() {
278     assert(!FREEBSD_NOT_IMPLEMENTED);
279     return false;
280 }
281
282 bool syscallNotification::installPostFork() {
283     assert(!FREEBSD_NOT_IMPLEMENTED);
284     return false;
285 }
286
287 bool process::dumpImage(std::string) {
288     assert(!FREEBSD_NOT_IMPLEMENTED);
289     return false;
290 }
291
292 bool dyn_lwp::realLWP_attach_() {
293     assert(!FREEBSD_NOT_IMPLEMENTED);
294     return false;
295 }
296
297 bool process::trapAtEntryPointOfMain(dyn_lwp*, unsigned long) {
298     assert(!FREEBSD_NOT_IMPLEMENTED);
299     return false;
300 }
301
302 bool dynamic_linking::installTracing() {
303     assert(!FREEBSD_NOT_IMPLEMENTED);
304     return false;
305 }
306
307 bool syscallNotification::removePreLwpExit() {
308     assert(!FREEBSD_NOT_IMPLEMENTED);
309     return false;
310 }
311
312 bool dyn_lwp::waitUntilStopped() {
313     assert(!FREEBSD_NOT_IMPLEMENTED);
314     return false;
315 }
316
317 bool process::hasPassedMain() {
318     assert(!FREEBSD_NOT_IMPLEMENTED);
319     return false;
320 }
321
322 bool dyn_lwp::writeTextWord(char*, int) {
323     assert(!FREEBSD_NOT_IMPLEMENTED);
324     return false;
325 }
326
327 bool process::handleTrapAtLibcStartMain(dyn_lwp*) {
328     assert(!FREEBSD_NOT_IMPLEMENTED);
329     return false;
330 }
331
332 bool dyn_lwp::getRegisters_(dyn_saved_regs*, bool) {
333     assert(!FREEBSD_NOT_IMPLEMENTED);
334     return false;
335 }
336
337 bool SignalGenerator::decodeEvents(std::vector<EventRecord, std::allocator<EventRecord> >&) {
338     assert(!FREEBSD_NOT_IMPLEMENTED);
339     return false;
340 }
341
342 bool dynamic_linking::initialize() {
343     assert(!FREEBSD_NOT_IMPLEMENTED);
344     return false;
345 }
346
347 bool dyn_lwp::continueLWP_(int) {
348     assert(!FREEBSD_NOT_IMPLEMENTED);
349     return false;
350 }
351
352 syscallNotification::syscallNotification(syscallNotification*, process*) {
353     assert(!FREEBSD_NOT_IMPLEMENTED);
354 }
355
356 bool dynamic_linking::decodeIfDueToSharedObjectMapping(EventRecord&, unsigned int&) {
357     assert(!FREEBSD_NOT_IMPLEMENTED);
358     return false;
359 }
360
361 bool syscallNotification::installPostExec() {
362     assert(!FREEBSD_NOT_IMPLEMENTED);
363     return false;
364 }
365
366 bool process::loadDYNINSTlibCleanup(dyn_lwp*) {
367     assert(!FREEBSD_NOT_IMPLEMENTED);
368     return false;
369 }
370
371 bool dyn_lwp::changePC(unsigned long, dyn_saved_regs*) {
372     assert(!FREEBSD_NOT_IMPLEMENTED);
373     return false;
374 }
375
376 bool process::insertTrapAtEntryPointOfMain() {
377     assert(!FREEBSD_NOT_IMPLEMENTED);
378     return false;
379 }
380
381 bool dyn_lwp::restoreRegisters_(dyn_saved_regs const&, bool) {
382     assert(!FREEBSD_NOT_IMPLEMENTED);
383     return false;
384 }
385
386 bool dyn_lwp::readDataSpace(void const*, unsigned int, void*) {
387     assert(!FREEBSD_NOT_IMPLEMENTED);
388     return false;
389 }
390
391 Address dyn_lwp::readRegister(unsigned int) {
392     assert(!FREEBSD_NOT_IMPLEMENTED);
393     return false;
394 }
395
396 bool process::determineLWPs(std::vector<unsigned int, std::allocator<unsigned int> >&) {
397     assert(!FREEBSD_NOT_IMPLEMENTED);
398     return false;
399 }
400
401 bool dyn_lwp::writeTextSpace(void*, unsigned int, void const*) {
402     assert(!FREEBSD_NOT_IMPLEMENTED);
403     return false;
404 }
405
406 void dyn_lwp::realLWP_detach_() {
407     assert(!FREEBSD_NOT_IMPLEMENTED);
408 }
409
410 bool dyn_lwp::writeDataSpace(void*, unsigned int, void const*) {
411     assert(!FREEBSD_NOT_IMPLEMENTED);
412     return false;
413 }
414
415 bool syscallNotification::removePostExec() {
416     assert(!FREEBSD_NOT_IMPLEMENTED);
417     return false;
418 }
419
420 std::string process::tryToFindExecutable(std::string const&, int) {
421     assert(!FREEBSD_NOT_IMPLEMENTED);
422     return std::string("");
423 }
424
425
426 bool process::unsetProcessFlags() {
427     assert(!FREEBSD_NOT_IMPLEMENTED);
428     return false;
429 }
430
431 bool process::decodeStartupSysCalls(EventRecord&) {
432     assert(!FREEBSD_NOT_IMPLEMENTED);
433     return false;
434 }
435
436 bool SignalGeneratorCommon::getExecFileDescriptor(std::string, int, bool, int&, fileDescriptor&) {
437     assert(!FREEBSD_NOT_IMPLEMENTED);
438     return false;
439 }
440
441 bool dynamic_linking::handleIfDueToSharedObjectMapping(EventRecord&, std::vector<mapped_object*, std::allocator<mapped_object*> >&, 
442         std::vector<bool, std::allocator<bool> >&) 
443 {
444     assert(!FREEBSD_NOT_IMPLEMENTED);
445     return false;
446 }
447
448 void OS::osTraceMe() {
449     assert(!FREEBSD_NOT_IMPLEMENTED);
450 }
451
452 bool Frame::setPC(unsigned long) {
453     assert(!FREEBSD_NOT_IMPLEMENTED);
454     return false;
455 }
456
457 bool process::instrumentLibcStartMain() {
458     assert(!FREEBSD_NOT_IMPLEMENTED);
459     return false;
460 }
461
462 void dyn_lwp::representativeLWP_detach_() {
463     assert(!FREEBSD_NOT_IMPLEMENTED);
464 }
465
466 bool process::handleTrapAtEntryPointOfMain(dyn_lwp*) {
467     assert(!FREEBSD_NOT_IMPLEMENTED);
468     return false;
469 }
470
471 bool process::trapDueToDyninstLib(dyn_lwp*) {
472     assert(!FREEBSD_NOT_IMPLEMENTED);
473     return false;
474 }
475
476 bool syscallNotification::removePreExec() {
477     assert(!FREEBSD_NOT_IMPLEMENTED);
478     return false;
479 }
480
481 bool dynamic_linking::processLinkMaps(std::vector<fileDescriptor, std::allocator<fileDescriptor> >&) {
482     assert(!FREEBSD_NOT_IMPLEMENTED);
483     return false;
484 }
485
486 bool syscallNotification::removePostFork() {
487     assert(!FREEBSD_NOT_IMPLEMENTED);
488     return false;
489 }
490
491 bool process::dumpCore_(std::string) {
492     assert(!FREEBSD_NOT_IMPLEMENTED);
493     return false;
494 }
495
496 bool syscallNotification::removePreFork() {
497     assert(!FREEBSD_NOT_IMPLEMENTED);
498     return false;
499 }
500
501 dyn_lwp* process::createRepresentativeLWP() {
502     assert(!FREEBSD_NOT_IMPLEMENTED);
503     return NULL;
504 }
505
506 bool syscallNotification::removePreExit() {
507     assert(!FREEBSD_NOT_IMPLEMENTED);
508     return false;
509 }
510
511 bool syscallNotification::installPreExec() {
512     assert(!FREEBSD_NOT_IMPLEMENTED);
513     return false;
514 }
515
516 bool syscallNotification::installPreFork() {
517     assert(!FREEBSD_NOT_IMPLEMENTED);
518     return false;
519 }
520
521 bool process::loadDYNINSTlib() {
522     assert(!FREEBSD_NOT_IMPLEMENTED);
523     return false;
524 }
525
526 bool SignalHandler::handleProcessExitPlat(EventRecord&, bool&) {
527     assert(!FREEBSD_NOT_IMPLEMENTED);
528     return false;
529 }
530
531 bool syscallNotification::installPreLwpExit() {
532     assert(!FREEBSD_NOT_IMPLEMENTED);
533     return false;
534 }
535
536 bool dyn_lwp::representativeLWP_attach_() {
537     assert(!FREEBSD_NOT_IMPLEMENTED);
538     return false;
539 }
540
541 bool process::isRunning_() const {
542     assert(!FREEBSD_NOT_IMPLEMENTED);
543     return false;
544 }
545
546 bool process::hasBeenBound(Dyninst::SymtabAPI::relocationEntry const&, int_function*&, unsigned long) {
547     assert(!FREEBSD_NOT_IMPLEMENTED);
548     return false;
549 }
550
551 bool syscallNotification::installPreExit() {
552     assert(!FREEBSD_NOT_IMPLEMENTED);
553     return false;
554 }
555
556 bool dyn_lwp::readTextSpace(const void*, unsigned int, void*) {
557     assert(!FREEBSD_NOT_IMPLEMENTED);
558     return false;
559 }
560
561 bool process::setProcessFlags() {
562     assert(!FREEBSD_NOT_IMPLEMENTED);
563     return false;
564 }
565
566 terminateProcStatus_t process::terminateProc_() {
567     assert(!FREEBSD_NOT_IMPLEMENTED);
568     return terminateFailed;
569 }
570
571 // Temporary remote debugger interface.
572 // I assume these will be removed when procControlAPI is complete.
573 bool OS_isConnected(void)
574 {
575     return true;  // We're always connected to the child on this platform.
576 }
577
578 bool OS_connect(BPatch_remoteHost &/*remote*/)
579 {
580     return true;  // We're always connected to the child on this platform.
581 }
582
583 bool OS_getPidList(BPatch_remoteHost &/*remote*/,
584                    BPatch_Vector<unsigned int> &/*tlist*/)
585 {
586     return false;  // Not implemented.
587 }
588
589 bool OS_getPidInfo(BPatch_remoteHost &/*remote*/,
590                    unsigned int /*pid*/, std::string &/*pidStr*/)
591 {
592     return false;  // Not implemented.
593 }
594
595 bool OS_disconnect(BPatch_remoteHost &/*remote*/)
596 {
597     return true;
598 }
599
600 /* END unimplemented functions */