Compile fix after removing deprecated SymtabAPI methods.
[dyninst.git] / dyninstAPI / src / unix.C
1 /*
2  * See the dyninst/COPYRIGHT file for copyright information.
3  * 
4  * We provide the Paradyn Tools (below described as "Paradyn")
5  * on an AS IS basis, and do not warrant its validity or performance.
6  * We reserve the right to update, modify, or discontinue this
7  * software at any time.  We shall have no obligation to supply such
8  * updates or modifications or any other form of support to you.
9  * 
10  * By your use of Paradyn, you understand and agree that we (or any
11  * other person or entity with proprietary rights in Paradyn) are
12  * under no obligation to provide either maintenance services,
13  * update services, notices of latent defects, or correction of
14  * defects for Paradyn.
15  * 
16  * This library is free software; you can redistribute it and/or
17  * modify it under the terms of the GNU Lesser General Public
18  * License as published by the Free Software Foundation; either
19  * version 2.1 of the License, or (at your option) any later version.
20  * 
21  * This library is distributed in the hope that it will be useful,
22  * but WITHOUT ANY WARRANTY; without even the implied warranty of
23  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
24  * Lesser General Public License for more details.
25  * 
26  * You should have received a copy of the GNU Lesser General Public
27  * License along with this library; if not, write to the Free Software
28  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
29  */
30
31 // $Id: unix.C,v 1.243 2008/06/30 17:33:31 legendre Exp $
32
33 #include "os.h"
34 #include "debug.h"
35 #include "mapped_object.h"
36 #include "mapped_module.h"
37 #include "dynProcess.h"
38 #include "dynThread.h"
39 #include "function.h"
40
41 #include "common/h/pathName.h"
42
43 #include <sstream>
44
45 extern char **environ;
46
47 using namespace Dyninst::ProcControlAPI;
48
49 // Functions for all Unices //
50
51 bool PCProcess::hideDebugger()
52 {
53     return false;
54 }
55
56 bool OS::executableExists(const std::string &file) 
57 {
58    struct stat file_stat;
59    int stat_result;
60
61    const char *fn = file.c_str();
62    stat_result = stat(fn, &file_stat);
63    return (stat_result != -1);
64 }
65
66 void OS::get_sigaction_names(std::vector<std::string> &names)
67 {
68    names.push_back(string("sigaction"));
69    names.push_back(string("signal"));
70 }
71
72
73
74 std::string PCProcess::createExecPath(const std::string &file, const std::string &dir) {
75     std::string ret = file;
76     if (dir.length() > 0) {
77         if (!(file[0] == ('/'))) {
78             // file does not start  with a '/', so it is a relative pathname
79             // we modify it to prepend the given directory
80             if (dir[dir.length()-1 ] == ('/') ) {
81                 // the dir already has a trailing '/', so we can
82                 // just concatenate them to get an absolute path
83                 ret =  dir + file;
84             } else {
85                 // the dir does not have a trailing '/', so we must
86                 // add a '/' to get the absolute path
87                 ret =  dir + "/" + file;
88             }
89         } else {
90             // file starts with a '/', so it is an absolute pathname
91             // DO NOT prepend the directory, regardless of what the
92             // directory variable holds.
93             // nothing to do in this case
94         }
95
96     }
97     return ret;
98 }
99
100 // If true is passed for ignore_if_mt_not_set, then an error won't be
101 // initiated if we're unable to determine if the program is multi-threaded.
102 // We are unable to determine this if the daemon hasn't yet figured out what
103 // libraries are linked against the application.  Currently, we identify an
104 // application as being multi-threaded if it is linked against a thread
105 // library (eg. libpthreads.a on AIX).  There are cases where we are querying
106 // whether the app is multi-threaded, but it can't be determined yet but it
107 // also isn't necessary to know.
108 bool PCProcess::multithread_capable(bool ignoreIfMtNotSet) {
109 #if !defined(cap_threads)
110     return false;
111 #endif
112
113     if( mt_cache_result_ != not_cached ) {
114         if( mt_cache_result_ == cached_mt_true) return true;
115         else return false;
116     }
117
118     if( mapped_objects.size() <= 1 ) {
119         assert( ignoreIfMtNotSet && "Can't query MT state" );
120         return false;
121     }
122
123     if(    findObject("libthread.so*", true) // Solaris
124         || findObject("libpthreads.*", true) // AIX
125         || findObject("libpthread.so*", true) // Linux
126         || findObject("libpthread-*.so", true) // Linux
127         || findObject("libthr.*", true) ) // FreeBSD
128     {
129         mt_cache_result_ = cached_mt_true;
130         return true;
131     }
132
133     mt_cache_result_ = cached_mt_false;
134     return false;
135 }
136
137 /**
138  * Searches for function in order, with preference given first
139  * to libpthread, then to libc, then to the process.
140  **/
141 static void findThreadFuncs(PCProcess *p, std::string func,
142                             pdvector<func_instance *> &result) {
143     bool found = false;
144     mapped_module *lpthread = p->findModule("libpthread*", true);
145     if (lpthread)
146         found = lpthread->findFuncVectorByPretty(func, result);
147     if (found)
148         return;
149
150     mapped_module *lc = p->findModule("libc.so*", true);
151     if (lc)
152         found = lc->findFuncVectorByPretty(func, result);
153     if (found)
154         return;
155
156     p->findFuncsByPretty(func, result);
157 }
158
159 bool PCProcess::instrumentMTFuncs() {
160     bool res;
161
162 #if !defined(cap_threads)
163     return true;
164 #endif
165
166     /**
167      * Have dyn_pthread_self call the actual pthread_self
168      **/
169     //Find dyn_pthread_self
170     pdvector<int_variable *> ptself_syms;
171     res = findVarsByAll("DYNINST_pthread_self", ptself_syms);
172     if (!res) {
173         fprintf(stderr, "[%s:%d] - Couldn't find any dyn_pthread_self, expected 1\n",
174                 __FILE__, __LINE__);
175     }
176     assert(ptself_syms.size() == 1);
177     Address dyn_pthread_self = ptself_syms[0]->getAddress();
178     //Find pthread_self
179     pdvector<func_instance *> pthread_self_funcs;
180     findThreadFuncs(this, "pthread_self", pthread_self_funcs);
181     if (pthread_self_funcs.size() != 1) {
182         fprintf(stderr, "[%s:%d] - Found %ld pthread_self functions, expected 1\n",
183                 __FILE__, __LINE__, (long) pthread_self_funcs.size());
184         for (unsigned j=0; j<pthread_self_funcs.size(); j++) {
185             func_instance *ps = pthread_self_funcs[j];
186             fprintf(stderr, "[%s:%u] - %s in module %s at %lx\n", __FILE__, __LINE__,
187                     ps->prettyName().c_str(), ps->mod()->fullName().c_str(),
188                     ps->addr());
189         }
190         return false;
191     }
192     //Replace
193     res = writeFunctionPtr(this, dyn_pthread_self, pthread_self_funcs[0]);
194     if (!res) {
195         fprintf(stderr, "[%s:%d] - Couldn't update dyn_pthread_self\n",
196                 __FILE__, __LINE__);
197         return false;
198     }
199
200     return true;
201 }
202
203 bool PCEventHandler::shouldStopForSignal(int signal) {
204     if( signal == SIGSTOP || signal == SIGINT ) return true;
205     return false;
206 }
207
208 bool PCEventHandler::isCrashSignal(int signal) {
209     switch(signal) {
210         case SIGBUS:
211         case SIGSEGV:
212         case SIGABRT:
213         case SIGILL:
214         case SIGFPE:
215         case SIGTRAP:
216             return true;
217         default:
218             return false;
219     }
220 }
221
222 bool PCEventHandler::isKillSignal(int signal) {
223     switch(signal) {
224         case SIGKILL:
225         case SIGTERM:
226             return true;
227         default:
228             return false;
229     }
230 }
231
232 bool PCEventHandler::isValidRTSignal(int signal, RTBreakpointVal breakpointVal, 
233         Address arg1, int status)
234 {
235     /* Okay... we use both DYNINST_BREAKPOINT_SIGNUM and sigstop,
236      * depending on what we're trying to stop. So we have to check the
237      *flags against the signal
238      */
239     if( signal == SIGSTOP ) {
240         if( breakpointVal == SoftRTBreakpoint ) {
241             if( status == DSE_forkExit ) {
242                 if( arg1 == 0 ) return true;
243
244                 proccontrol_printf("%s[%d]: parent process received SIGSTOP\n",
245                         FILE__, __LINE__);
246             }else{
247                 proccontrol_printf("%s[%d]: SIGSTOP wasn't due to fork exit\n",
248                         FILE__, __LINE__);
249             }
250         }else{
251             proccontrol_printf("%s[%d]: mismatch in signal for breakpoint type\n",
252                     FILE__, __LINE__);
253         }
254     }else if( signal == DYNINST_BREAKPOINT_SIGNUM ) {
255         if( breakpointVal == NormalRTBreakpoint ) {
256             if( (status != DSE_forkExit) || (arg1 != 0) ) return true;
257
258             proccontrol_printf("%s[%d]: child received signal %d\n",
259                     FILE__, __LINE__, DYNINST_BREAKPOINT_SIGNUM);
260         }else{
261             proccontrol_printf("%s[%d]: mismatch in signal for breakpoint type\n",
262                     FILE__, __LINE__);
263         }
264     }else{
265         proccontrol_printf("%s[%d]: signal wasn't sent by RT library\n",
266                 FILE__, __LINE__);
267     }
268
269     return false;
270 }
271
272 mapped_object *PCProcess::createObjectNoFile(Address) {
273     assert(0); // not implemented on UNIX
274     return NULL;
275 }
276
277 bool PCProcess::setMemoryAccessRights(Address start, Address size, int rights) {
278     mal_printf("setMemoryAccessRights to %d [%lx %lx]\n", rights, start, start+size);
279     assert(!"Not implemented yet");
280     return false;
281 }
282
283 bool PCProcess::getMemoryAccessRights(Address start, Address size, int rights) {
284     mal_printf("getMemoryAccessRights to %d [%lx %lx]\n", rights, start, start+size);
285     assert(!"Not implemented yet");
286     return false;
287 }
288
289 void PCProcess::redirectFds(int stdin_fd, int stdout_fd, int stderr_fd,
290         std::map<int, int> &fds)
291 {
292     if( stdin_fd != 0 ) fds.insert(std::make_pair(stdin_fd, 0));
293     if( stdout_fd != 1 ) fds.insert(std::make_pair(stdout_fd, 1));
294     if( stderr_fd != 2 ) fds.insert(std::make_pair(stderr_fd, 2));
295 }
296
297 bool PCProcess::setEnvPreload(std::vector<std::string> &envp, std::string fileName) {
298     const unsigned int ERROR_CODE = 101;
299     bool use_abi_rt = false;
300
301 #if defined(arch_64bit)
302     SymtabAPI::Symtab *symt_obj;
303     bool result = SymtabAPI::Symtab::openFile(symt_obj, fileName);
304     if( !result ) return false;
305
306     use_abi_rt = (symt_obj->getAddressWidth() == 4);
307 #endif
308
309     const char *rt_lib_name = getenv("DYNINSTAPI_RT_LIB");
310     if( rt_lib_name == NULL ) {
311         showErrorCallback(ERROR_CODE, std::string("setEnvPreload: DYNINSTAPI_RT_LIB is undefined"));
312         proccontrol_printf("%s[%d]: DYNINSTAPI_RT_LIB is undefined\n");
313         return false;
314     }
315
316     std::string full_name;
317     if (use_abi_rt) {
318         const char *slash = P_strrchr(rt_lib_name, '/');
319         if (!slash)
320             slash = P_strrchr(rt_lib_name, '\\');
321         if (!slash)
322             return false;
323         const char *dot = P_strchr(slash, '.');
324         if (!dot)
325             return false;
326         full_name = std::string(rt_lib_name, dot - rt_lib_name) +
327                     std::string("_m32") +
328                     std::string(dot);
329         rt_lib_name = full_name.c_str();
330     }
331
332     // Check to see if the library given exists.
333     if (access(rt_lib_name, R_OK)) {
334         std::string msg = std::string("Runtime library ") + std::string(rt_lib_name) +
335                           std::string(" does not exist or cannot be accessed!");
336         cerr << msg << endl;
337         showErrorCallback(ERROR_CODE, msg);
338         return false;
339     }
340
341     const char *var_name = "LD_PRELOAD";
342     if (envp.size()) {
343         // Check if some LD_PRELOAD is already part of the environment.
344         std::vector<std::string>::iterator ldPreloadVal =  envp.end();
345         for(std::vector<std::string>::iterator i = envp.begin();
346                 i != envp.end(); ++i)
347         {
348             if( (*i) == var_name ) {
349                 ldPreloadVal = i;
350                 break;
351             }
352         }
353
354         if (ldPreloadVal == envp.end()) {
355             // Not found, append an entry
356             std::string ld_preload = std::string(var_name) + std::string("=") +
357                                      std::string(rt_lib_name);
358             startup_printf("LD_PRELOAD=%s\n", ld_preload.c_str());
359             envp.push_back(ld_preload);
360         } else {
361             // Found, modify envs in-place
362             std::string ld_preload = *ldPreloadVal + std::string(":") +
363                                      std::string(rt_lib_name);
364             startup_printf("LD_PRELOAD=%s\n", ld_preload.c_str());
365             *ldPreloadVal = ld_preload;
366         }
367     } else {
368         // Environment inherited from this process, copy the current
369         // environment to envp, modifying/adding LD_PRELOAD
370         char *ld_preload_orig = NULL;
371         int i = 0;
372         while( environ[i] != NULL ) {
373             std::string envVar(environ[i]);
374             if( envVar.find("LD_PRELOAD=") == 0 ) {
375                 ld_preload_orig = environ[i];
376             }else{
377                 envp.push_back(envVar);
378             }
379             i++;
380         }
381
382         std::string ld_preload;
383         if (ld_preload_orig) {
384             // Append to existing var
385             ld_preload = std::string(var_name) + std::string("=") +
386                          std::string(ld_preload_orig) + std::string(":") +
387                          std::string(rt_lib_name);
388         } else {
389             // Define a new var
390             ld_preload = std::string(var_name) + std::string("=") +
391                          std::string(rt_lib_name);
392         }
393         envp.push_back(ld_preload);
394     }
395
396     return true;
397 }
398
399
400 bool PCProcess::getExecFileDescriptor(string filename,
401         bool, fileDescriptor &desc)
402 {
403    Address base = 0;
404
405     desc = fileDescriptor(filename.c_str(),
406                           base, // code
407                           base, // data
408                           false); // a.out
409     return true;
410 }
411
412 /**
413  * Strategy:  The program entry point is in /lib/ld-2.x.x at the 
414  * _start function.  Get the current PC, parse /lib/ld-2.x.x, and 
415  * compare the two points.
416  **/
417 bool PCProcess::hasPassedMain() 
418 {
419    using namespace SymtabAPI;
420    Symtab *ld_file = NULL;
421    Address entry_addr, ldso_start_addr = 0;
422
423    //Get current PC
424    Frame active_frame = initialThread_->getActiveFrame();
425    Address current_pc = active_frame.getPC();
426
427    // Get the interpreter name from SymtabAPI
428    const char *path = getAOut()->parse_img()->getObject()->getInterpreterName();
429
430    if (!path) {
431       //Strange... This shouldn't happen on a normal linux system
432       startup_printf("[%s:%u] - Couldn't find /lib/ld-x.x.x in hasPassedMain\n",
433                      FILE__, __LINE__);
434       return true;
435    }
436
437    std::string derefPath = resolve_file_path(path);
438
439    // Search for the dynamic linker in the loaded libraries
440    const LibraryPool &libraries = pcProc_->libraries();
441    bool foundDynLinker = false;
442    for(LibraryPool::const_iterator i = libraries.begin(); i != libraries.end();
443            ++i)
444    {
445        if( (*i)->getName() == derefPath ) {
446            foundDynLinker = true;
447            ldso_start_addr = (*i)->getLoadAddress();
448        }
449    }
450
451    if( !foundDynLinker ) {
452        // This means that libraries haven't been loaded yet which implies
453        // that main hasn't been reached yet
454        return false;
455    }
456
457    //Open /lib/ld-x.x.x and find the entry point
458    if (!Symtab::openFile(ld_file, derefPath)) {
459       startup_printf("[%s:%u] - Unable to open %s in hasPassedMain\n", 
460                      FILE__, __LINE__, path);
461       return true;
462    }
463
464    entry_addr = ld_file->getEntryOffset();
465    if (!entry_addr) {
466       startup_printf("[%s:%u] - No entry addr for %s\n", 
467                      FILE__, __LINE__, path);
468       return true;
469    }
470
471    entry_addr += ldso_start_addr;
472
473    if( !getOPDFunctionAddr(entry_addr) ) {
474        startup_printf("[%s:%u] - failed to read entry addr function pointer\n",
475                FILE__, __LINE__);
476        return false;
477    }
478
479    if( entry_addr < ldso_start_addr ) {
480        entry_addr += ldso_start_addr;
481    }
482    
483    bool result = (entry_addr != current_pc);
484    startup_printf("[%s:%u] - hasPassedMain returning %d (%lx %lx)\n",
485                   FILE__, __LINE__, (int) result, entry_addr, current_pc);
486
487    return result;
488 }
489
490 bool PCProcess::startDebugger() {
491     std::stringstream pidStr;
492     pidStr << getPid();
493
494     const char *args[4];
495     args[0] = dyn_debug_crash_debugger;
496     args[1] = file_.c_str();
497     args[2] = pidStr.str().c_str();
498     args[3] = NULL;
499
500     proccontrol_printf("%s[%d]: Launching %s %s %s\n", FILE__, __LINE__,
501             args[0], args[1], args[2]);
502     if( execv(args[0], const_cast<char **>(args)) == -1 ) {
503         perror("execv");
504         return false;
505     }
506
507     return true;
508 }
509
510 // The following functions are only implemented on some Unices //
511
512 #if defined(os_linux) || defined(os_freebsd)
513
514 #include "dyninstAPI/src/binaryEdit.h"
515 #include "symtabAPI/h/Archive.h"
516
517 using namespace Dyninst::SymtabAPI;
518
519
520 mapped_object *BinaryEdit::openResolvedLibraryName(std::string filename,
521                                                    std::map<std::string, BinaryEdit*> &retMap) {
522     std::vector<std::string> paths;
523     std::vector<std::string>::iterator pathIter;
524
525     // First, find the specified library file
526     bool resolved = getResolvedLibraryPath(filename, paths);
527
528     // Second, create a set of BinaryEdits for the found library
529     if ( resolved ) {
530         startup_printf("[%s:%u] - Opening dependent file %s\n",
531                        FILE__, __LINE__, filename.c_str());
532
533         Symtab *origSymtab = getMappedObject()->parse_img()->getObject();
534         assert(mgr());
535         // Dynamic case
536         if ( !origSymtab->isStaticBinary() ) {
537             for(pathIter = paths.begin(); pathIter != paths.end(); ++pathIter) {
538                BinaryEdit *temp = BinaryEdit::openFile(*pathIter, mgr(), patcher());
539
540                 if (temp && temp->getAddressWidth() == getAddressWidth()) {
541                     retMap.insert(std::make_pair(*pathIter, temp));
542                     return temp->getMappedObject();
543                 }
544                 delete temp;
545             }
546         } else {
547             // Static executable case
548
549             /* 
550              * Alright, this is a kludge, but even though the Archive is opened
551              * twice (once here and once by the image class later on), it is
552              * only parsed once because the Archive class keeps track of all
553              * open Archives.
554              *
555              * This is partly due to the fact that Archives are collections of
556              * Symtab objects and their is one Symtab for each BinaryEdit. In
557              * some sense, an Archive is a collection of BinaryEdits.
558              */
559             for(pathIter = paths.begin(); pathIter != paths.end(); ++pathIter) {
560                 Archive *library;
561                 Symtab *singleObject;
562                 if (Archive::openArchive(library, *pathIter)) {
563                     std::vector<Symtab *> members;
564                     if (library->getAllMembers(members)) {
565                         std::vector <Symtab *>::iterator member_it;
566                         for (member_it = members.begin(); member_it != members.end();
567                              ++member_it) 
568                         {
569                            BinaryEdit *temp = BinaryEdit::openFile(*pathIter, 
570                                                                    mgr(), patcher(), (*member_it)->memberName());
571
572                             if (temp && temp->getAddressWidth() == getAddressWidth()) {
573                                 std::string mapName = *pathIter + string(":") +
574                                     (*member_it)->memberName();
575                                 retMap.insert(std::make_pair(mapName, temp));
576                             }else{
577                                 if(temp) delete temp;
578                                 retMap.clear();
579                                 break;
580                             }
581                         }
582
583                         if (retMap.size() > 0) {
584                             origSymtab->addLinkingResource(library);
585                             // So we tried loading "libc.a", and got back a swarm of individual members. 
586                             // Lovely. 
587                             // Just return the first thing...
588                             return retMap.begin()->second->getMappedObject();
589                         }
590                         //if( library ) delete library;
591                     }
592                 } else if (Symtab::openFile(singleObject, *pathIter)) {
593                    BinaryEdit *temp = BinaryEdit::openFile(*pathIter, mgr(), patcher());
594
595
596                     if (temp && temp->getAddressWidth() == getAddressWidth()) {
597                         if( singleObject->getObjectType() == obj_SharedLib ||
598                             singleObject->getObjectType() == obj_Executable ) 
599                         {
600                           startup_printf("%s[%d]: cannot load dynamic object(%s) when rewriting a static binary\n", 
601                                   FILE__, __LINE__, pathIter->c_str());
602                           std::string msg = std::string("Cannot load a dynamic object when rewriting a static binary");
603                           showErrorCallback(71, msg.c_str());
604
605                           delete singleObject;
606                         }else{
607                             retMap.insert(std::make_pair(*pathIter, temp));
608                             return temp->getMappedObject();
609                         }
610                     }
611                     if(temp) delete temp;
612                 }
613             }
614         }
615     }
616
617     startup_printf("[%s:%u] - Creation error opening %s\n",
618                    FILE__, __LINE__, filename.c_str());
619     return NULL;
620 }
621
622 #endif
623
624 #if defined(os_linux) || defined(os_freebsd)
625
626 #include "dyninstAPI/src/instPoint.h"
627 #include "dyninstAPI/src/parse-cfg.h"
628 #include "dyninstAPI/src/function.h"
629 #include "dyninstAPI/src/addressSpace.h"
630 #include "symtabAPI/h/Symtab.h"
631 #include "dyninstAPI/src/mapped_object.h"
632 #include "dyninstAPI/src/binaryEdit.h"
633 #include "dyninstAPI/src/debug.h"
634 #include "boost/tuple/tuple.hpp"
635 #include <elf.h>
636
637 #if defined(os_linux)
638 #include "dyninstAPI/src/linux.h"
639 #else
640 #include "dyninstAPI/src/freebsd.h"
641 #endif
642
643 // The following functions were factored from linux.C to be used
644 // on both Linux and FreeBSD
645
646 // findCallee: finds the function called by the instruction corresponding
647 // to the instPoint "instr". If the function call has been bound to an
648 // address, then the callee function is returned in "target" and the 
649 // instPoint "callee" data member is set to pt to callee's func_instance.  
650 // If the function has not yet been bound, then "target" is set to the 
651 // func_instance associated with the name of the target function (this is 
652 // obtained by the PLT and relocation entries in the image), and the instPoint
653 // callee is not set.  If the callee function cannot be found, (ex. function
654 // pointers, or other indirect calls), it returns false.
655 // Returns false on error (ex. process doesn't contain this instPoint).
656 //
657 // HACK: made an func_instance method to remove from instPoint class...
658 // FURTHER HACK: made a block_instance method so we can share blocks
659 func_instance *block_instance::callee() {
660    // Check 1: pre-computed callee via PLT
661    func_instance *ret = obj()->getCallee(this);
662    if (ret) return ret;
663
664    // See if we've already done this
665    edge_instance *tEdge = getTarget();
666    if (!tEdge) {
667       return NULL;
668    }
669
670    if (!tEdge->sinkEdge()) {
671       func_instance *tmp = obj()->findFuncByEntry(tEdge->trg());
672       if (tmp && !(tmp->ifunc()->isPLTFunction())) {
673          return tmp;
674       }
675    }
676
677    
678
679    // Do this the hard way - an inter-module jump
680    // get the target address of this function
681    Address target_addr; bool success;
682    boost::tie(success, target_addr) = llb()->callTarget();
683    if(!success) {
684       // this is either not a call instruction or an indirect call instr
685       // that we can't get the target address
686       //fprintf(stderr, "%s[%d]:  returning NULL\n", FILE__, __LINE__);
687       return NULL;
688    }
689    
690    // get the relocation information for this image
691    Symtab *sym = obj()->parse_img()->getObject();
692    pdvector<relocationEntry> fbt;
693    vector <relocationEntry> fbtvector;
694    if (!sym->getFuncBindingTable(fbtvector)) {
695       //fprintf(stderr, "%s[%d]:  returning NULL\n", FILE__, __LINE__);
696       return NULL;
697    }
698
699
700    /**
701     * Object files and static binaries will not have a function binding table
702     * because the function binding table holds relocations used by the dynamic
703     * linker
704     */
705    if (!fbtvector.size() && !sym->isStaticBinary() && 
706            sym->getObjectType() != obj_RelocatableFile ) 
707    {
708       fprintf(stderr, "%s[%d]:  WARN:  zero func bindings\n", FILE__, __LINE__);
709    }
710
711    for (unsigned index=0; index< fbtvector.size();index++)
712       fbt.push_back(fbtvector[index]);
713    
714    Address base_addr = obj()->codeBase();
715    
716    std::map<Address, std::string> pltFuncs;
717    obj()->parse_img()->getPltFuncs(pltFuncs);
718
719    // find the target address in the list of relocationEntries
720    if (pltFuncs.find(target_addr) != pltFuncs.end()) {
721       for (u_int i=0; i < fbt.size(); i++) {
722          if (fbt[i].target_addr() == target_addr) 
723          {
724             // check to see if this function has been bound yet...if the
725             // PLT entry for this function has been modified by the runtime
726             // linker
727             func_instance *target_pdf = 0;
728             if (proc()->hasBeenBound(fbt[i], target_pdf, base_addr)) {
729                updateCallTarget(target_pdf);
730                obj()->setCalleeName(this, target_pdf->symTabName());
731                obj()->setCallee(this, target_pdf);
732                return target_pdf;
733             }
734          }
735       }
736       const char *target_name = pltFuncs[target_addr].c_str();
737       PCProcess *dproc = dynamic_cast<PCProcess *>(proc());
738
739       BinaryEdit *bedit = dynamic_cast<BinaryEdit *>(proc());
740       obj()->setCalleeName(this, std::string(target_name));
741       pdvector<func_instance *> pdfv;
742
743       // See if we can name lookup
744       if (dproc) {
745          if (proc()->findFuncsByMangled(target_name, pdfv)) {
746             obj()->setCallee(this, pdfv[0]);
747             updateCallTarget(pdfv[0]);
748             return pdfv[0];
749          }
750       }
751       else if (bedit) {
752          std::vector<BinaryEdit *>::iterator i;
753          for (i = bedit->getSiblings().begin(); i != bedit->getSiblings().end(); i++)
754          {
755             if ((*i)->findFuncsByMangled(target_name, pdfv)) {
756                obj()->setCallee(this, pdfv[0]);
757                updateCallTarget(pdfv[0]);
758                return pdfv[0];
759             }
760          }
761       }
762       else 
763          assert(0);
764    }
765    
766    //fprintf(stderr, "%s[%d]:  returning NULL: target addr = %p\n", FILE__, __LINE__, (void *)target_addr);
767    return NULL;
768 }
769
770 void BinaryEdit::makeInitAndFiniIfNeeded()
771 {
772     using namespace Dyninst::SymtabAPI;
773
774     Symtab* linkedFile = getAOut()->parse_img()->getObject();
775
776     // Disable this for .o's and static binaries
777     if( linkedFile->isStaticBinary() || 
778         linkedFile->getObjectType() == obj_RelocatableFile ) 
779     {
780         return;
781     }
782
783     bool foundInit = false;
784     bool foundFini = false;
785     vector <Function *> funcs;
786     if (linkedFile->findFunctionsByName(funcs, "_init")) {
787         foundInit = true;
788     }
789     if (linkedFile->findFunctionsByName(funcs, "_fini")) {
790         foundFini = true;
791     }
792     if( !foundInit )
793     {
794         Offset initOffset = linkedFile->getInitOffset();
795         Region *initsec = linkedFile->findEnclosingRegion(initOffset);
796         if(!initOffset || !initsec)
797         {
798             unsigned char* emptyFunction = NULL;
799             int emptyFuncSize = 0;
800 #if defined(arch_x86) || defined(arch_x86_64)
801             static unsigned char empty_32[] = { 0x55, 0x89, 0xe5, 0xc9, 0xc3 };
802             static unsigned char empty_64[] = { 0x55, 0x48, 0x89, 0xe5, 0xc9, 0xc3 };
803             if(linkedFile->getAddressWidth() == 8)
804             {
805                 emptyFunction = empty_64;
806                 emptyFuncSize = 6;
807             }
808             else
809             {
810                 emptyFunction = empty_32;
811                 emptyFuncSize = 5;
812             }
813 #elif defined (arch_power)
814             static unsigned char empty[] = { 0x4e, 0x80, 0x00, 0x20};
815              emptyFunction = empty;
816              emptyFuncSize = 4;
817 #endif //defined(arch_x86) || defined(arch_x86_64)
818             linkedFile->addRegion(highWaterMark_, (void*)(emptyFunction), emptyFuncSize, ".init.dyninst",
819                                   Dyninst::SymtabAPI::Region::RT_TEXT, true);
820             highWaterMark_ += emptyFuncSize;
821             lowWaterMark_ += emptyFuncSize;
822             linkedFile->findRegion(initsec, ".init.dyninst");
823             assert(initsec);
824             linkedFile->addSysVDynamic(DT_INIT, initsec->getMemOffset());
825             startup_printf("%s[%d]: creating .init.dyninst region, region addr 0x%lx\n",
826                            FILE__, __LINE__, initsec->getMemOffset());
827         }
828         startup_printf("%s[%d]: ADDING _init at 0x%lx\n", FILE__, __LINE__, initsec->getMemOffset());
829         Symbol *initSym = new Symbol( "_init",
830                                       Symbol::ST_FUNCTION,
831                                       Symbol::SL_GLOBAL,
832                                       Symbol::SV_DEFAULT,
833                                       initsec->getMemOffset(),
834                                       linkedFile->getDefaultModule(),
835                                       initsec,
836                                       UINT_MAX );
837         linkedFile->addSymbol(initSym);
838     }
839     if( !foundFini )
840     {
841         Offset finiOffset = linkedFile->getFiniOffset();
842         Region *finisec = linkedFile->findEnclosingRegion(finiOffset);
843         if(!finiOffset || !finisec)
844         {
845             unsigned char* emptyFunction = NULL;
846             int emptyFuncSize = 0;
847 #if defined(arch_x86) || defined(arch_x86_64)
848             static unsigned char empty_32[] = { 0x55, 0x89, 0xe5, 0xc9, 0xc3 };
849             static unsigned char empty_64[] = { 0x55, 0x48, 0x89, 0xe5, 0xc9, 0xc3 };
850             if(linkedFile->getAddressWidth() == 8)
851             {
852                 emptyFunction = empty_64;
853                 emptyFuncSize = 6;
854             }
855             else
856             {
857                 emptyFunction = empty_32;
858                 emptyFuncSize = 5;
859             }
860
861 #elif defined (arch_power)
862             static unsigned char empty[] = { 0x4e, 0x80, 0x00, 0x20};
863              emptyFunction = empty;
864              emptyFuncSize = 4;
865 #endif //defined(arch_x86) || defined(arch_x86_64)
866             linkedFile->addRegion(highWaterMark_, (void*)(emptyFunction), emptyFuncSize, ".fini.dyninst",
867                                   Dyninst::SymtabAPI::Region::RT_TEXT, true);
868             highWaterMark_ += emptyFuncSize;
869             lowWaterMark_ += emptyFuncSize;
870             linkedFile->findRegion(finisec, ".fini.dyninst");
871             assert(finisec);
872             linkedFile->addSysVDynamic(DT_FINI, finisec->getMemOffset());
873             startup_printf("%s[%d]: creating .fini.dyninst region, region addr 0x%lx\n",
874                            FILE__, __LINE__, finisec->getMemOffset());
875
876         }
877         startup_printf("%s[%d]: ADDING _fini at 0x%lx\n", FILE__, __LINE__, finisec->getMemOffset());
878         Symbol *finiSym = new Symbol( "_fini",
879                                       Symbol::ST_FUNCTION,
880                                       Symbol::SL_GLOBAL,
881                                       Symbol::SV_DEFAULT,
882                                       finisec->getMemOffset(),
883                                       linkedFile->getDefaultModule(),
884                                       finisec,
885                                       UINT_MAX );
886         linkedFile->addSymbol(finiSym);
887     }
888 }
889
890 Address PCProcess::setAOutLoadAddress(fileDescriptor &desc) {
891    //The load address of the a.out isn't correct.  We can't read a
892    // correct one out of ld-x.x.x.so because it may not be initialized yet,
893    // and it won't be initialized until we reach main.  But we need the load
894    // address to find main.  Darn.
895    //
896    //Instead we'll read the entry out of /proc/pid/maps, and try to make a good
897    // effort to correctly match the fileDescriptor to an entry.  Unfortunately,
898    // symlinks can complicate this, so we'll stat the files and compare inodes
899
900    struct stat aout, maps_entry;
901    map_entries *maps = NULL;
902    unsigned maps_size = 0, i;
903    char proc_path[128];
904    int result;
905    Address loadAddr = 0;
906
907    //Get the inode for the a.out
908    startup_printf("[%s:%u] - a.out is a shared library, computing load addr\n",
909                   FILE__, __LINE__);
910    memset(&aout, 0, sizeof(aout));
911    result = stat(pcProc_->libraries().getExecutable()->getName().c_str(), &aout);
912    if (result == -1) {
913       startup_printf("[%s:%u] - setAOutLoadAddress couldn't stat %s: %s\n",
914                      FILE__, __LINE__, proc_path, strerror(errno));
915       goto done;
916    }
917                     
918    //Get the maps
919    maps = getVMMaps(getPid(), maps_size);
920    if (!maps) {
921       startup_printf("[%s:%u] - setAOutLoadAddress, getVMMaps return NULL\n",
922                      FILE__, __LINE__);
923       goto done;
924    }
925    
926    //Compare the inode of each map entry to the a.out's
927    for (i=0; i<maps_size; i++) {
928       memset(&maps_entry, 0, sizeof(maps_entry));
929       result = stat(maps[i].path, &maps_entry);
930       if (result == -1) {
931          startup_printf("[%s:%u] - setAOutLoadAddress couldn't stat %s: %s\n",
932                         FILE__, __LINE__, maps[i].path, strerror(errno));
933          continue;
934       }
935       if (maps_entry.st_dev == aout.st_dev && maps_entry.st_ino == aout.st_ino)
936       {
937          //We have a match
938          
939          desc.setLoadAddr(maps[i].start);
940          loadAddr = maps[i].start;
941       }
942    }
943         
944  done:
945    if (maps)
946       free(maps);
947
948    return loadAddr;
949 }
950
951 #endif
952