Build fixes for NewInstpoint merge on FreeBSD.
[dyninst.git] / dyninstAPI / src / freebsd.C
1 /*
2  * Copyright (c) 1996-2011 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 #include <dlfcn.h>
34 #include <cstdlib>
35
36 #include "binaryEdit.h"
37 #include "pcProcess.h"
38 #include "symtab.h"
39 #include "function.h"
40 #include "instPoint.h"
41 #include "baseTramp.h"
42 #include "os.h"
43 #include "debug.h"
44 #include "mapped_object.h"
45 #include "mapped_module.h"
46 #include "freebsd.h"
47
48 #include "common/h/headers.h"
49 #include "common/h/freebsdKludges.h"
50 #include "common/h/pathName.h"
51
52 #include "symtabAPI/h/Symtab.h"
53 using namespace Dyninst::SymtabAPI;
54 using namespace Dyninst::ProcControlAPI;
55
56 using std::string;
57
58 void loadNativeDemangler() {}
59
60 bool BinaryEdit::getResolvedLibraryPath(const std::string &filename, std::vector<std::string> &paths) {
61     char *libPathStr, *libPath;
62     std::vector<std::string> libPaths;
63     struct stat dummy;
64     FILE *ldconfig;
65     char buffer[512];
66
67     // prefer qualified file paths
68     if (stat(filename.c_str(), &dummy) == 0) {
69         paths.push_back(filename);
70     }
71
72     // search paths from environment variables
73     libPathStr = strdup(getenv("LD_LIBRARY_PATH"));
74     libPath = strtok(libPathStr, ":");
75     while (libPath != NULL) {
76         libPaths.push_back(std::string(libPath));
77         libPath = strtok(NULL, ":");
78     }
79     free(libPathStr);
80
81     for (unsigned int i = 0; i < libPaths.size(); i++) {
82         std::string str = libPaths[i] + "/" + filename;
83         if (stat(str.c_str(), &dummy) == 0) {
84             paths.push_back(str);
85         }
86     }
87
88     // search ld.so hints file
89     ldconfig = popen("/sbin/ldconfig -r", "r");
90     if( ldconfig ) {
91         // ignore first and second line
92         fgets(buffer, 512, ldconfig);
93         fgets(buffer, 512, ldconfig);
94
95         // Here is the expected format:
96         // [^/]* => (path)/(filename)
97         while(fgets(buffer, 512, ldconfig) != NULL) {
98             size_t fileBegin, pathBegin;
99
100             // Remove any whitespace at the end
101             std::string strBuf(buffer);
102             strBuf = strBuf.substr(0, strBuf.find_last_not_of(" \t\n\r")+1);
103
104             // Locate the filename
105             fileBegin = strBuf.rfind("/");
106             if( fileBegin == std::string::npos ||
107                 fileBegin+1 >= strBuf.length() ) continue;
108
109             if( strBuf.substr(fileBegin+1) == filename ) {
110                 // Locate the path
111                 pathBegin = strBuf.find("/");
112                 if( pathBegin == std::string::npos ) continue;
113                 paths.push_back(strBuf.substr(pathBegin));
114             }
115         }
116
117         pclose(ldconfig);
118     }
119
120     // search hard-coded system paths
121     libPaths.clear();
122     libPaths.push_back("/lib");
123     libPaths.push_back("/usr/lib");
124     libPaths.push_back("/usr/local/lib");
125     for (unsigned int i = 0; i < libPaths.size(); i++) {
126         std::string str = libPaths[i] + "/" + filename;
127         if (stat(str.c_str(), &dummy) == 0) {
128             paths.push_back(str);
129         }
130     }
131
132     return ( 0 < paths.size() );
133 }
134
135 bool BinaryEdit::archSpecificMultithreadCapable() {
136     /*
137      * The heuristic on FreeBSD is to check for some symbols that are
138      * only included in a binary when pthreads has been linked into the
139      * binary. If the binary contains these symbols, it is multithread
140      * capable.
141      */
142     const int NUM_PTHREAD_SYMS = 6;
143     const char *pthreadSyms[NUM_PTHREAD_SYMS] =
144     { "pthread_attr_get_np", "pthread_attr_getaffinity_np",
145       "pthread_attr_getstack", "pthread_attr_setaffinity_np",
146       "pthread_attr_setcreatesuspend_np", "pthread_attr_setstack"
147     };
148
149     if( mobj->isStaticExec() ) {
150         int numSymsFound = 0;
151         for(int i = 0; i < NUM_PTHREAD_SYMS; ++i) {
152             const pdvector<func_instance *> *tmpFuncs = 
153                 mobj->findFuncVectorByPretty(pthreadSyms[i]);
154             if( tmpFuncs != NULL && tmpFuncs->size() ) numSymsFound++;
155         }
156
157         if( numSymsFound == NUM_PTHREAD_SYMS ) return true;
158     }
159
160     return false;
161 }
162
163 bool AddressSpace::getDyninstRTLibName() {
164    startup_printf("dyninstRT_name: %s\n", dyninstRT_name.c_str());
165     if (dyninstRT_name.length() == 0) {
166         // Get env variable
167         if (getenv("DYNINSTAPI_RT_LIB") != NULL) {
168             dyninstRT_name = getenv("DYNINSTAPI_RT_LIB");
169         }
170         else {
171            std::string msg;
172            PCProcess *proc;
173            if ((proc = dynamic_cast<PCProcess *>(this)) != NULL) {
174               msg = std::string("Environment variable ") +
175                  std::string("DYNINSTAPI_RT_LIB") +
176                  std::string(" has not been defined for process ") +
177                  utos(proc->getPid());
178            }
179            else {
180               msg = std::string("Environment variable ") +
181                  std::string("DYNINSTAPI_RT_LIB") +
182                  std::string(" has not been defined");
183            }           
184            showErrorCallback(101, msg);
185            return false;
186         }
187     }
188
189     // Automatically choose 32-bit library if necessary.
190     const char *modifier = "_m32";
191     const char *name = dyninstRT_name.c_str();
192
193     const char *split = P_strrchr(name, '/');
194     if ( !split ) split = name;
195     split = P_strchr(split, '.');
196     if ( !split || P_strlen(split) <= 1 ) {
197         // We should probably print some error here.
198         // Then, of course, the user will find out soon enough.
199         startup_printf("Invalid Dyninst RT lib name: %s\n", 
200                 dyninstRT_name.c_str());
201         return false;
202     }
203
204     if ( getAddressWidth() == sizeof(void *) || P_strstr(name, modifier) ) {
205         modifier = "";
206     }
207
208     const char *suffix = split;
209     if( getAOut()->isStaticExec() ) {
210         suffix = ".a";
211     }else{
212         if( P_strncmp(suffix, ".a", 2) == 0 ) {
213             // This will be incorrect if the RT library's version changes
214             suffix = ".so";
215         }
216     }
217
218     dyninstRT_name = std::string(name, split - name) +
219                      std::string(modifier) +
220                      std::string(suffix);
221
222     dyninstRT_name = resolve_file_path(dyninstRT_name.c_str());
223
224     startup_printf("Dyninst RT Library name set to '%s'\n",
225             dyninstRT_name.c_str());
226
227     // Check to see if the library given exists.
228     if (access(dyninstRT_name.c_str(), R_OK)) {
229         std::string msg = std::string("Runtime library ") + dyninstRT_name
230         + std::string(" does not exist or cannot be accessed!");
231         showErrorCallback(101, msg);
232         return false;
233     }
234
235     return true;
236 }
237
238 /* dynamic instrumentation support */
239
240 PCEventHandler::CallbackBreakpointCase
241 PCEventHandler::getCallbackBreakpointCase(EventType et) {
242     // This switch statement can be derived from the EventTypes and Events
243     // table in the ProcControlAPI manual -- it states what Events are
244     // available on each platform
245
246     switch(et.code()) {
247         case EventType::Fork:
248             switch(et.time()) {
249                 case EventType::Pre:
250                     return BreakpointOnly;
251                 case EventType::Post:
252                     return BothCallbackBreakpoint;
253                 default:
254                     break;
255             }
256             break;
257         case EventType::Exit:
258             switch(et.time()) {
259                 case EventType::Pre:
260                     // Using the RT library breakpoint allows us to determine
261                     // the exit code in a uniform way across Unices
262                     return BreakpointOnly;
263                 case EventType::Post:
264                     return CallbackOnly;
265                 default:
266                     break;
267             }
268             break;
269        case EventType::Exec:
270             switch(et.time()) {
271                 case EventType::Pre:
272                     return BreakpointOnly;
273                 case EventType::Post:
274                     return CallbackOnly;
275                 default:
276                     break;
277             }
278             break;
279     }
280
281     return NoCallbackOrBreakpoint;
282 }
283
284 void PCProcess::inferiorMallocConstraints(Address near, Address &lo, Address &hi,
285         inferiorHeapType /* type */ )
286 {
287     if(near) {
288 #if !defined(arch_x86_64) && !defined(arch_power)
289         lo = region_lo(near);
290         hi = region_hi(near);
291 #else
292         if( getAddressWidth() == 8 ) {
293             lo = region_lo_64(near);
294             hi = region_hi_64(near);
295         }else{
296             lo = region_lo(near);
297             hi = region_hi(near);
298         }
299 #endif
300     }
301 }
302
303 inferiorHeapType PCProcess::getDynamicHeapType() const {
304     return anyHeap;
305 }
306
307 bool PCProcess::dumpImage(string) {
308     return false;
309 }
310
311 bool PCProcess::dumpCore(string) {
312     return false;
313 }
314
315 bool PCProcess::skipHeap(const heapDescriptor &) {
316     return false;
317 }
318
319 bool PCProcess::usesDataLoadAddress() const {
320     return false;
321 }
322
323 bool PCProcess::copyDanglingMemory(PCProcess *) {
324     return true;
325 }
326
327 const unsigned int N_DYNINST_LOAD_HIJACK_FUNCTIONS = 4;
328 const char DYNINST_LOAD_HIJACK_FUNCTIONS[][20] = {
329   "__libc_start_main",
330   "_init",
331   "_start",
332   "main"
333 };
334
335 /**
336  * Returns an address that we can use to write the code that executes
337  * dlopen on the runtime library.
338  **/
339 Address PCProcess::findFunctionToHijack()
340 {
341    Address codeBase = 0;
342    unsigned i;
343    for(i = 0; i < N_DYNINST_LOAD_HIJACK_FUNCTIONS; i++ ) {
344       const char *func_name = DYNINST_LOAD_HIJACK_FUNCTIONS[i];
345
346       pdvector<func_instance *> hijacks;
347       if (!findFuncsByAll(func_name, hijacks)) continue;
348       codeBase = hijacks[0]->addr();
349
350       if (codeBase)
351           break;
352    }
353    if( codeBase != 0 ) {
354      proccontrol_printf("%s[%d]: found hijack function %s = 0x%lx\n",
355            FILE__, __LINE__, DYNINST_LOAD_HIJACK_FUNCTIONS[i], codeBase);
356    }
357
358   return codeBase;
359 } /* end findFunctionToHijack() */
360
361 const int DLOPEN_MODE = RTLD_NOW | RTLD_GLOBAL;
362
363 const char *DL_OPEN_FUNC_USER = NULL;
364 const char *DL_OPEN_FUNC_EXPORTED = "dlopen";
365
366 bool PCProcess::postRTLoadCleanup() {
367     if( rtLibLoadHeap_ ) {
368         if( !pcProc_->freeMemory(rtLibLoadHeap_) ) {
369             startup_printf("%s[%d]: failed to free memory used for RT library load\n",
370                     FILE__, __LINE__);
371             return false;
372         }
373     }
374     return true;
375 }
376
377 AstNodePtr PCProcess::createLoadRTAST() {
378     vector<func_instance *> dlopen_funcs;
379
380     // allow user to override default dlopen func names with env. var
381
382     DL_OPEN_FUNC_USER = getenv("DYNINST_DLOPEN_FUNC");
383
384     if( DL_OPEN_FUNC_USER ) {
385         findFuncsByAll(DL_OPEN_FUNC_USER, dlopen_funcs);
386     }
387
388     if( dlopen_funcs.size() == 0 ) {
389         if( !findFuncsByAll(DL_OPEN_FUNC_EXPORTED, dlopen_funcs) ) {
390             startup_printf("%s[%d]: failed to find dlopen function to load RT lib\n",
391                     FILE__, __LINE__);
392             return AstNodePtr();
393         }
394     }
395
396     // We need to make sure that the correct dlopen function is being used -- the
397     // dlopen in the runtime linker. A symbol for dlopen exists in ld.so even
398     // when it is stripped so we should always find that version of dlopen
399     const char *runtimeLdPath = 
400         getAOut()->parse_img()->getObject()->getInterpreterName();
401     std::string derefRuntimeLdPath = resolve_file_path(runtimeLdPath);
402
403     func_instance *dlopen_func = NULL;
404     for(vector<func_instance *>::iterator i = dlopen_funcs.begin();
405             i != dlopen_funcs.end(); ++i)
406     {
407         func_instance *tmpFunc = *i;
408         std::string derefPath = resolve_file_path(tmpFunc->obj()->fullName().c_str());
409         if( derefPath == derefRuntimeLdPath ) {
410             dlopen_func = tmpFunc;
411             break;
412         }
413     }
414
415     if( dlopen_func == NULL ) {
416         startup_printf("%s[%d]: failed to find correct dlopen function\n",
417                 FILE__, __LINE__);
418         return AstNodePtr();
419     }
420     
421     rtLibLoadHeap_ = pcProc_->mallocMemory(dyninstRT_name.length());
422     if( !rtLibLoadHeap_ ) {
423         startup_printf("%s[%d]: failed to allocate memory for RT library load\n",
424                 FILE__, __LINE__);
425         return AstNodePtr();
426     }
427
428     if( !writeDataSpace((char *)rtLibLoadHeap_, dyninstRT_name.length(), dyninstRT_name.c_str()) ) {
429         startup_printf("%s[%d]: failed to write RT lib name into mutatee\n",
430                 FILE__, __LINE__);
431         return AstNodePtr();
432     }
433
434     pdvector<AstNodePtr> args;
435     args.push_back(AstNode::operandNode(AstNode::Constant, (void *)rtLibLoadHeap_));
436     args.push_back(AstNode::operandNode(AstNode::Constant, (void *)DLOPEN_MODE));
437
438     return AstNode::funcCallNode(dlopen_func, args);
439 }
440
441 Address PCProcess::getTOCoffsetInfo(Address) {
442     assert(!"This function is unimplemented");
443     return 0;
444 }
445
446 Address PCProcess::getTOCoffsetInfo(func_instance *) {
447     assert(!"This function is unimplemented");
448     return 0;
449 }
450
451 /* START unimplemented functions */
452
453 #define FREEBSD_NOT_IMPLEMENTED "This function is not implemented on FreeBSD"
454
455 void initPrimitiveCost() {
456     assert(!FREEBSD_NOT_IMPLEMENTED);
457 }
458
459 // Temporary remote debugger interface.
460 // I assume these will be removed when procControlAPI is complete.
461 bool OS_isConnected(void)
462 {
463     return true;  // We're always connected to the child on this platform.
464 }
465
466 bool OS_connect(BPatch_remoteHost &/*remote*/)
467 {
468     return true;  // We're always connected to the child on this platform.
469 }
470
471 bool OS_getPidList(BPatch_remoteHost &/*remote*/,
472                    BPatch_Vector<unsigned int> &/*tlist*/)
473 {
474     return false;  // Not implemented.
475 }
476
477 bool OS_getPidInfo(BPatch_remoteHost &/*remote*/,
478                    unsigned int /*pid*/, std::string &/*pidStr*/)
479 {
480     return false;  // Not implemented.
481 }
482
483 bool OS_disconnect(BPatch_remoteHost &/*remote*/)
484 {
485     return true;
486 }
487
488 /* END unimplemented functions */