Fix statically linked rewriting crash?
[dyninst.git] / dyninstAPI / src / linux.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: linux.C,v 1.279 2008/09/03 06:08:44 jaw Exp $
32
33 #include "binaryEdit.h"
34 #include "dynProcess.h"
35 #include "image.h"
36 #include "function.h"
37 #include "instPoint.h"
38 #include "baseTramp.h"
39 #include "os.h"
40 #include "debug.h"
41 #include "mapped_object.h"
42 #include "mapped_module.h"
43 #include "linux.h"
44 #include <dlfcn.h>
45
46 #include "boost/shared_ptr.hpp"
47
48 #include "pcEventMuxer.h"
49
50 #include "common/src/headers.h"
51 #include "common/src/linuxKludges.h"
52
53 #include "symtabAPI/h/Symtab.h"
54 using namespace Dyninst::SymtabAPI;
55 using namespace Dyninst::ProcControlAPI;
56
57 using std::string;
58
59 bool get_linux_version(int &major, int &minor, int &subvers)
60 {
61     int subsub;
62     return get_linux_version(major,minor,subvers,subsub); 
63 }
64
65 bool get_linux_version(int &major, int &minor, int &subvers, int &subsubvers)
66 {
67    static int maj = 0, min = 0, sub = 0, subsub = 0;
68    int result;
69    FILE *f;
70    if (maj)
71    {
72       major = maj;
73       minor = min;
74       subvers = sub;
75       subsubvers = subsub;
76       return true;
77    }
78    f = P_fopen("/proc/version", "r");
79    if (!f) goto error;
80    result = fscanf(f, "Linux version %d.%d.%d.%d", &major, &minor, &subvers,
81                     &subsubvers);
82    fclose(f);
83    if (result != 3 && result != 4) goto error;
84
85    maj = major;
86    min = minor;
87    sub = subvers;
88    subsub = subsubvers;
89    return true;
90
91  error:
92    //Assume 2.4, which is the earliest version we support
93    major = maj = 2;
94    minor = min = 4;
95    subvers = sub = 0;
96    subsubvers = subsub = 0;
97    return false;
98 }
99
100 void PCProcess::inferiorMallocConstraints(Address near, Address &lo, Address &hi,
101         inferiorHeapType /* type */ ) 
102 {
103     if (near) {
104 #if !defined(arch_x86_64) && !defined(arch_power)
105         lo = region_lo(near);
106         hi = region_hi(near);
107 #else
108         if (getAddressWidth() == 8) {
109             lo = region_lo_64(near);
110             hi = region_hi_64(near);
111         } else {
112             lo = region_lo(near);
113             hi = region_hi(near);
114         }
115 #endif
116     }
117 }
118
119 inferiorHeapType PCProcess::getDynamicHeapType() const {
120     return anyHeap;
121 }
122
123 void loadNativeDemangler() {}
124
125 bool PCProcess::dumpImage(string) {
126     return false;
127 }
128
129 bool PCProcess::dumpCore(string) {
130     return false;
131 }
132
133 bool PCProcess::skipHeap(const heapDescriptor &) {
134     return false;
135 }
136
137 bool AddressSpace::usesDataLoadAddress() const {
138     return false;
139 }
140
141 bool PCProcess::copyDanglingMemory(PCProcess *) {
142     return true;
143 }
144
145
146 bool PCEventMuxer::useBreakpoint(Dyninst::ProcControlAPI::EventType et)
147 {
148     // This switch statement can be derived from the EventTypes and Events
149     // table in the ProcControlAPI manual -- it states what Events are
150     // available on each platform
151
152    // Pre-events are breakpoint
153    // Post-events are callback
154    if (et.time() == EventType::Pre &&
155        ((et.code() == EventType::Fork) ||
156         (et.code() == EventType::Exec))) return true;
157    return false;
158 }
159
160 bool PCEventMuxer::useCallback(Dyninst::ProcControlAPI::EventType et)
161 {
162     // This switch statement can be derived from the EventTypes and Events
163     // table in the ProcControlAPI manual -- it states what Events are
164     // available on each platform
165
166    // Pre-events are breakpoint
167    // Post-events are callback
168   if(et.code() == EventType::Exit) return true;
169   
170   if (et.time() == EventType::Post &&
171        ((et.code() == EventType::Fork) ||
172         (et.code() == EventType::Exec))) return true;
173   
174    return false;
175 }
176
177 bool BinaryEdit::getResolvedLibraryPath(const string &filename, std::vector<string> &paths) {
178     char *libPathStr, *libPath;
179     std::vector<string> libPaths;
180     struct stat dummy;
181     char buffer[512];
182     char *pos, *key, *val;
183
184     // prefer qualified file paths
185     if (stat(filename.c_str(), &dummy) == 0) {
186         paths.push_back(filename);
187     }
188
189     // For cross-rewriting
190     char *dyn_path = getenv("DYNINST_REWRITER_PATHS");
191     if (dyn_path) { 
192        libPathStr = strdup(dyn_path);
193        libPath = strtok(libPathStr, ":");
194        while (libPath != NULL) {
195           libPaths.push_back(string(libPath));
196           libPath = strtok(NULL, ":");
197        }
198        free(libPathStr);
199     }
200
201     // search paths from environment variables
202     char *ld_path = getenv("LD_LIBRARY_PATH");
203     if (ld_path) { 
204        libPathStr = strdup(ld_path);
205        libPath = strtok(libPathStr, ":");
206        while (libPath != NULL) {
207           libPaths.push_back(string(libPath));
208           libPath = strtok(NULL, ":");
209        }
210        free(libPathStr);
211     }
212
213     //libPaths.push_back(string(getenv("PWD")));
214     for (unsigned int i = 0; i < libPaths.size(); i++) {
215         string str = libPaths[i] + "/" + filename;
216         if (stat(str.c_str(), &dummy) == 0) {
217             paths.push_back(str);
218         }
219     }
220
221     // search ld.so.cache
222     // apparently ubuntu doesn't like pclosing NULL, so a shared pointer custom
223     // destructor is out. Ugh.
224     FILE* ldconfig = popen("/sbin/ldconfig -p", "r");
225     if (ldconfig) {
226         if(!fgets(buffer, 512, ldconfig)) {     // ignore first line
227           return false;
228         }
229         while (fgets(buffer, 512, ldconfig) != NULL) {
230             pos = buffer;
231             while (*pos == ' ' || *pos == '\t') pos++;
232             key = pos;
233             while (*pos != ' ') pos++;
234             *pos = '\0';
235             while (*pos != '=' && *(pos + 1) != '>') pos++;
236             pos += 2;
237             while (*pos == ' ' || *pos == '\t') pos++;
238             val = pos;
239             while (*pos != '\n' && *pos != '\0') pos++;
240             *pos = '\0';
241             if (strcmp(key, filename.c_str()) == 0) {
242                 paths.push_back(val);
243             }
244         }
245         pclose(ldconfig);
246     }
247
248     // search hard-coded system paths
249     libPaths.clear();
250     libPaths.push_back("/usr/local/lib");
251     libPaths.push_back("/usr/share/lib");
252     libPaths.push_back("/usr/lib");
253     libPaths.push_back("/usr/lib64");
254     libPaths.push_back("/usr/lib/x86_64-linux-gnu");
255     libPaths.push_back("/lib");
256     libPaths.push_back("/lib64");
257     libPaths.push_back("/lib/x86_64-linux-gnu");
258     libPaths.push_back("/usr/lib/i386-linux-gnu");
259     libPaths.push_back("/usr/lib32");
260     for (unsigned int i = 0; i < libPaths.size(); i++) {
261         string str = libPaths[i] + "/" + filename;
262         if (stat(str.c_str(), &dummy) == 0) {
263             paths.push_back(str);
264         }
265     }
266
267     return ( 0 < paths.size() );
268 }
269
270 bool BinaryEdit::archSpecificMultithreadCapable() {
271     /*
272      * The heuristic for this check on Linux is that some symbols provided by
273      * pthreads are only defined when the binary contains pthreads. Therefore,
274      * check for these symbols, and if they are defined in the binary, then
275      * conclude that the binary is multithread capable.
276      */
277     const int NUM_PTHREAD_SYMS = 4;
278     const char *pthreadSyms[NUM_PTHREAD_SYMS] = 
279         { "pthread_cancel", "pthread_once", 
280           "pthread_mutex_unlock", "pthread_mutex_lock" 
281         };
282     if( mobj->isStaticExec() ) {
283         int numSymsFound = 0;
284         for(int i = 0; i < NUM_PTHREAD_SYMS; ++i) {
285             const pdvector<func_instance *> *tmpFuncs = 
286                 mobj->findFuncVectorByPretty(pthreadSyms[i]);
287             if( tmpFuncs != NULL && tmpFuncs->size() ) numSymsFound++;
288         }
289
290         if( numSymsFound == NUM_PTHREAD_SYMS ) return true;
291     }
292
293     return false;
294 }
295
296 // Temporary remote debugger interface.
297 // I assume these will be removed when procControlAPI is complete.
298 bool OS_isConnected(void)
299 {
300     return true;  // We're always connected to the child on this platform.
301 }
302
303 bool OS_connect(BPatch_remoteHost &/*remote*/)
304 {
305     return true;  // We're always connected to the child on this platform.
306 }
307
308 bool OS_getPidList(BPatch_remoteHost &/*remote*/,
309                    BPatch_Vector<unsigned int> &/*tlist*/)
310 {
311     return false;  // Not implemented.
312 }
313
314 bool OS_getPidInfo(BPatch_remoteHost &/*remote*/,
315                    unsigned int /*pid*/, std::string &/*pidStr*/)
316 {
317     return false;  // Not implemented.
318 }
319
320 bool OS_disconnect(BPatch_remoteHost &/*remote*/)
321 {
322     return true;
323 }