Merge branch 'dyn_pc_integration' of ssh://wasabi.cs.wisc.edu/p/paradyn/development...
[dyninst.git] / dyninstAPI / src / linux-x86.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 // $Id: linux-x86.C,v 1.142 2008/08/01 17:55:12 roundy Exp $
33
34 #include <fstream>
35 #include <string>
36
37 #include <fcntl.h>
38 #include <sys/user.h>
39 #include <sys/time.h>
40 #include <sys/resource.h>
41 #include <math.h> // for floor()
42 #include <unistd.h> // for sysconf()
43 #include <elf.h>
44 #include <libelf.h>
45
46 #include "dyninstAPI/src/miniTramp.h"
47 #include "dyninstAPI/src/baseTramp.h"
48 #include "dyninstAPI/src/symtab.h"
49 #include "dyninstAPI/src/function.h"
50 #include "dyninstAPI/src/instPoint.h"
51 #include "common/h/headers.h"
52 #include "dyninstAPI/src/os.h"
53 #include "common/h/stats.h"
54 #include "common/h/Types.h"
55 #include "dyninstAPI/src/debug.h"
56 #include "dyninstAPI/src/util.h" // getCurrWallTime
57 #include "common/h/pathName.h"
58 #include "dyninstAPI/src/inst-x86.h"
59 #include "dyninstAPI/src/emit-x86.h"
60
61 #include "dyninstAPI/src/mapped_object.h" 
62
63 #include "dyninstAPI/src/linux.h"
64
65 #include "dyninstAPI/src/registerSpace.h"
66
67 #include <sstream>
68
69 #include "dyninstAPI/src/ast.h"
70 #include "dyninstAPI/src/binaryEdit.h"
71 #include "dyninstAPI/src/pcThread.h"
72 #include "dyninstAPI/src/pcProcess.h"
73 #include "common/h/linuxKludges.h"
74
75 #include "instructionAPI/h/InstructionDecoder.h"
76 #include "instructionAPI/h/Instruction.h"
77
78 using namespace Dyninst;
79 using namespace Dyninst::SymtabAPI;
80 using namespace Dyninst::ProcControlAPI;
81
82 Address PCProcess::getLibcStartMainParam(PCThread *trappingThread) {
83    Address mainaddr = 0;
84    unsigned addrWidth = getAddressWidth();
85
86    RegisterPool regs;
87    trappingThread->getRegisters(regs);
88
89    Address targetAddr = 0;
90    if( getArch() == Arch_x86_64 ) {
91        if( addrWidth == 4 ) {
92            targetAddr = regs[x86_64::rsp] + addrWidth;
93        }else{
94            targetAddr = regs[x86_64::rdi];
95        }
96    }else{
97        targetAddr = regs[x86::esp] + addrWidth;
98    }
99
100    if( !readDataSpace((const void *)targetAddr, addrWidth, (void *)&mainaddr, false) ) {
101        proccontrol_printf("%s[%d]: failed to read address of main out of libc\n",
102                FILE__, __LINE__);
103    }
104
105    return mainaddr;
106 }
107
108 Address PCProcess::getTOCoffsetInfo(Address) {
109     assert(!"This function is unimplemented");
110     return 0;
111 }
112
113 Address PCProcess::getTOCoffsetInfo(int_function *) {
114     assert(!"This function is unimplemented");
115     return 0;
116 }
117
118 bool PCProcess::getOPDFunctionAddr(Address &) {
119     return true;
120 }
121
122 AstNodePtr PCProcess::createUnprotectStackAST() {
123     // Since we are punching our way down to an internal function, we
124     // may run into problems due to stack execute protection. Basically,
125     // glibc knows that it needs to be able to execute on the stack in
126     // in order to load libraries with dl_open(). It has code in
127     // _dl_map_object_from_fd (the workhorse of dynamic library loading)
128     // that unprotects a global, exported variable (__stack_prot), sets
129     // the execute flag, and reprotects it. This only happens, however,
130     // when the higher-level dl_open() functions (which we skip) are called,
131     // as they append an undocumented flag to the library open mode. Otherwise,
132     // assignment to the variable happens without protection, which will
133     // cause a fault.
134     //
135     // Instead of chasing the value of the undocumented flag, we will
136     // unprotect the __stack_prot variable ourselves (if we can find it).
137
138     startup_printf("%s[%d]: creating AST to call mprotect to unprotect libc stack protection variable\n",
139             FILE__, __LINE__);
140
141     // find variable __stack_prot
142
143     // mprotect READ/WRITE __stack_prot
144     pdvector<int_variable *> vars;
145     pdvector<int_function *> funcs;
146
147     Address var_addr;
148     int size;
149     int pagesize;
150     Address page_start;
151     bool ret;
152
153     ret = findVarsByAll("__stack_prot", vars);
154
155     if(!ret || vars.size() == 0) {
156         return AstNodePtr();
157     } else if(vars.size() > 1) {
158         startup_printf("%s[%d]: Warning: found more than one __stack_prot variable\n",
159                 FILE__, __LINE__);
160     }
161
162     pagesize = getpagesize();
163
164     var_addr = vars[0]->getAddress();
165     page_start = var_addr & ~(pagesize -1);
166     size = var_addr - page_start +sizeof(int);
167
168     ret = findFuncsByAll("mprotect",funcs);
169
170     if(!ret || funcs.size() == 0) {
171         startup_printf("%s[%d]: Couldn't find mprotect\n",
172                 FILE__, __LINE__);
173         return AstNodePtr();
174     }
175
176     // mprotect: int mprotect(const void *addr, size_t len, int prot);
177     int_function *mprot = funcs[0];
178     
179     pdvector<AstNodePtr> args;
180     args.push_back(AstNode::operandNode(AstNode::Constant, (void *)page_start));
181     args.push_back(AstNode::operandNode(AstNode::Constant, (void *)size));
182     // prot = READ|WRITE|EXECUTE
183     args.push_back(AstNode::operandNode(AstNode::Constant, (void *)7));
184
185     return AstNode::funcCallNode(mprot, args);
186 }
187
188 // For now, this isn't defined
189 #if 0 
190 /* Find libc and add it as a shared object
191  * Search for __libc_start_main
192  * Save old code at beginning of __libc_start_main
193  * Insert trap
194  * Signal thread to continue
195  */
196 bool PCProcess::instrumentLibcStartMain() 
197 {
198     unsigned int maps_size =0;
199     map_entries *maps = getVMMaps(getPid(), maps_size);
200     unsigned int libcIdx=0;
201     while (libcIdx < maps_size &&
202            ! (strstr(maps[libcIdx].path,"/libc")
203               && strstr(maps[libcIdx].path,".so"))) {
204        libcIdx++;
205     }
206     assert(libcIdx != maps_size);
207     //KEVINTODO: address code and data are not always 0,0: need to fix this
208     fileDescriptor libcFD = fileDescriptor(maps[libcIdx].path,0,0,true);
209     mapped_object *libc = mapped_object::createMappedObject(libcFD, this);
210     addASharedObject(libc);
211
212     // find __libc_startmain
213     const pdvector<int_function*> *funcs;
214     funcs = libc->findFuncVectorByPretty("__libc_start_main");
215     if(funcs->size() == 0 || (*funcs)[0] == NULL) {
216         logLine( "Couldn't find __libc_start_main\n");
217         return false;
218     } else if (funcs->size() > 1) {
219        startup_printf("[%s:%u] - Found %d functions called __libc_start_main, weird\n",
220                       FILE__, __LINE__, funcs->size());
221     }
222     if (!(*funcs)[0]->isInstrumentable()) {
223         logLine( "__libc_start_main is not instrumentable\n");
224         return false;
225     }
226     Address addr = (*funcs)[0]->getAddress();
227     startup_printf("%s[%d]: Instrumenting libc.so:__libc_start_main() at 0x%x\n", 
228                    FILE__, __LINE__, (int)addr);
229
230     // save original code at beginning of function
231     if (!readDataSpace((void *)addr, sizeof(savedCodeBuffer),savedCodeBuffer,true)) {
232         fprintf(stderr, "%s[%d]:  readDataSpace\n", __FILE__, __LINE__);
233         fprintf(stderr, "%s[%d][%s]:  failing instrumentLibcStartMain\n",
234             __FILE__, __LINE__, getThreadStr(getExecThreadID()));
235       fprintf(stderr, "Failed to read at address 0x%lx\n", addr);
236       return false;
237    }
238    startup_printf("%s[%d]: Saved %d bytes from entry of __libc_start_main\n", 
239          FILE__, __LINE__, sizeof(savedCodeBuffer));
240    // insert trap
241    codeGen gen(1);
242    insnCodeGen::generateTrap(gen);
243    if (!writeDataSpace((void *)addr, gen.used(), gen.start_ptr())) {
244       fprintf(stderr, "%s[%d][%s]:  failing instrumentLibcStartMain\n",
245             __FILE__, __LINE__, getThreadStr(getExecThreadID()));
246       return false;
247    }
248    libcstartmain_brk_addr = addr;
249    // TODO continueProc(); // signal process to continue
250    return true;
251 }// end instrumentLibcStartMain
252 #endif
253
254 bool AddressSpace::getDyninstRTLibName() {
255    startup_printf("dyninstRT_name: %s\n", dyninstRT_name.c_str());
256     if (dyninstRT_name.length() == 0) {
257         // Get env variable
258         if (getenv("DYNINSTAPI_RT_LIB") != NULL) {
259             dyninstRT_name = getenv("DYNINSTAPI_RT_LIB");
260         }
261         else {
262            std::string msg;
263            PCProcess *proc;
264            if ((proc = dynamic_cast<PCProcess *>(this)) != NULL) {
265               msg = std::string("Environment variable ") +
266                  std::string("DYNINSTAPI_RT_LIB") +
267                  std::string(" has not been defined for process ") +
268                  utos(proc->getPid());
269            }
270            else {
271               msg = std::string("Environment variable ") +
272                  std::string("DYNINSTAPI_RT_LIB") +
273                  std::string(" has not been defined");
274            }           
275            showErrorCallback(101, msg);
276            return false;
277         }
278     }
279
280     // Automatically choose 32-bit library if necessary.
281     const char *modifier = "_m32";
282     const char *name = dyninstRT_name.c_str();
283
284     const char *split = P_strrchr(name, '/');
285     if ( !split ) split = name;
286     split = P_strchr(split, '.');
287     if ( !split || P_strlen(split) <= 1 ) {
288         // We should probably print some error here.
289         // Then, of course, the user will find out soon enough.
290         startup_printf("Invalid Dyninst RT lib name: %s\n", 
291                 dyninstRT_name.c_str());
292         return false;
293     }
294
295     if ( getAddressWidth() == sizeof(void *) || P_strstr(name, modifier) ) {
296         modifier = "";
297     }
298
299     const char *suffix = split;
300     if( getAOut()->isStaticExec() ) {
301         suffix = ".a";
302     }else{
303         if( P_strncmp(suffix, ".a", 2) == 0 ) {
304           // Add symlinks in makefiles as follows:
305           // (lib).so => lib.so.(major)
306           // lib.so.major => lib.so.major.minor
307           // lib.so.major.minor => lib.so.major.minor.maintenance
308           suffix = ".so";
309         }
310     }
311
312     dyninstRT_name = std::string(name, split - name) +
313                      std::string(modifier) +
314                      std::string(suffix);
315
316     startup_printf("Dyninst RT Library name set to '%s'\n",
317             dyninstRT_name.c_str());
318
319     // Check to see if the library given exists.
320     if (access(dyninstRT_name.c_str(), R_OK)) {
321         std::string msg = std::string("Runtime library ") + dyninstRT_name
322         + std::string(" does not exist or cannot be accessed!");
323         showErrorCallback(101, msg);
324         return false;
325     }
326
327     return true;
328 }