Update copyright to LGPL on all files
[dyninst.git] / dyninstAPI / src / aixDL.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: aixDL.C,v 1.79 2008/06/19 19:53:05 legendre Exp $
33
34 #include "dyninstAPI/src/mapped_object.h"
35 #include "dyninstAPI/src/dynamiclinking.h"
36 #include "dyninstAPI/src/process.h"
37 #include "dyninstAPI/src/dyn_lwp.h"
38 #include "dyninstAPI/src/instPoint.h"
39 #include "dyninstAPI/src/symtab.h"
40 #include "dyninstAPI/src/arch.h"
41 #include "dyninstAPI/src/inst-power.h"
42 #include "dyninstAPI/src/InstrucIter.h"
43 #include "dyninstAPI/src/miniTramp.h"
44 #include "common/h/debugOstream.h"
45 #include <sys/ptrace.h>
46 #include <sys/ldr.h>
47
48 #include "dyninstAPI/src/ast.h"
49
50
51 bool dynamic_linking::initialize() {
52     // Since we read out of /proc/.../map, there is nothing to do here
53
54     dynlinked = true;
55     return true;
56 }
57
58 bool dynamic_linking::installTracing() {
59     // We capture dlopen/dlclose by overwriting the return address
60     // of their worker functions (load1 for dlopen, dlclose is TODO).
61     // We get this from the (already-parsed) listing of libc.
62
63   // Should check only libc.a...
64
65   AstNodePtr retval = AstNode::operandNode(AstNode::ReturnVal, (void *)0);
66   
67   const char *loadfunc = NULL;
68   switch (proc->getAddressWidth()) {
69     case 4: loadfunc = "load1"; break;
70     case 8: loadfunc = "uload"; break;
71     default: assert(0 && "Unknown process address width");
72   }
73
74   instMapping *loadInst = new instMapping(loadfunc, "DYNINST_instLoadLibrary",
75                                           FUNC_EXIT | FUNC_ARG,
76                                           retval);
77   instMapping *unloadInst = new instMapping("unload", "DYNINST_instLoadLibrary",
78                                             FUNC_EXIT | FUNC_ARG,
79                                             retval);
80   loadInst->dontUseTrampGuard();
81   unloadInst->dontUseTrampGuard();
82
83   pdvector<instMapping *>instReqs;
84   instReqs.push_back(loadInst);
85   instReqs.push_back(unloadInst);
86   proc->installInstrRequests(instReqs);
87   if (loadInst->miniTramps.size()) {
88       sharedLibHook *sharedHook = new sharedLibHook(proc, SLH_UNKNOWN,
89                                                     loadInst);
90       sharedLibHooks_.push_back(sharedHook);
91       instru_based = true;
92   }
93   if (unloadInst->miniTramps.size()) {
94       sharedLibHook *sharedHook = new sharedLibHook(proc, SLH_UNKNOWN,
95                                                     unloadInst);
96       sharedLibHooks_.push_back(sharedHook);
97       instru_based = true;
98   }
99
100   if (sharedLibHooks_.size())
101       return true;
102   else
103       return false;
104 }
105
106 // If result has entries, use them as a base (don't double-create)
107 bool dynamic_linking::processLinkMaps(pdvector<fileDescriptor> &result)
108 {
109     // First things first, get a list of all loader info structures.
110     int pid;
111
112     pid = proc->getPid();
113     prmap_t mapEntry;
114     int iter = 0; // Starting with the a.out is _just fine_.
115
116     bool is_aout = true;
117     
118     // We want to fill in this vector.
119
120     int mapfd = proc->getRepresentativeLWP()->map_fd();
121     do {
122         if (sizeof(prmap_t) != pread(mapfd, &mapEntry, sizeof(prmap_t), iter*sizeof(prmap_t)))
123            fprintf(stderr, "%s[%d]:  pread: %s\n", FILE__, __LINE__, strerror(errno));
124         if (mapEntry.pr_size != 0) {
125             prmap_t next;
126             if (sizeof(prmap_t) != pread(mapfd, &next, sizeof(prmap_t), (iter+1)*sizeof(prmap_t)))
127                fprintf(stderr, "%s[%d]:  pread: %s\n", FILE__, __LINE__, strerror(errno));
128             if (strcmp(mapEntry.pr_mapname, next.pr_mapname)) {
129                 // Must only have a text segment (?)
130                 next.pr_vaddr = 0;
131                 iter++;
132             }
133             else {
134                 iter += 2;
135             }
136             
137             char objname[256];
138             objname[0] = '\0';
139             if (mapEntry.pr_pathoff) {
140                pread(mapfd, objname, 256,
141                      mapEntry.pr_pathoff);
142                if (objname[0] == '\0')
143                   fprintf(stderr, "%s[%d]:  pread: %s\n", FILE__, __LINE__, 
144                         strerror(errno));
145             }
146             else {
147                 objname[0] = objname[1] = objname[2] = 0;
148             }
149
150             Address textOrg = (Address) mapEntry.pr_vaddr;
151             Address dataOrg = (Address) next.pr_vaddr;
152             
153             // Round up to next multiple of wordsize;
154             
155             if (textOrg % sizeof(unsigned))
156                 textOrg += sizeof(unsigned) - (textOrg % sizeof(unsigned));
157             if (dataOrg % sizeof(unsigned))
158                 dataOrg += sizeof(unsigned) - (dataOrg % sizeof(unsigned));
159             
160             fileDescriptor fda;
161             /* a.out is already added by setAout */
162 #if 0
163             if(is_aout)
164             {
165                                 //fda = fileDescriptor(objname, textOrg, dataOrg, false);
166                                 //fda.setMember(objname+1);
167                                 //result.push_back(fda);
168             }
169 #endif
170
171             if (!is_aout) {
172                         fda = fileDescriptor(objname, 
173                                      textOrg, dataOrg,
174                                      true);
175                         fda.setMember(objname+strlen(objname)+1);
176                         result.push_back(fda);
177             }
178             is_aout = false;
179             //fda.setPid(pid);
180         }
181         
182     } while (mapEntry.pr_size != 0);
183
184     return true;
185 }
186
187 /* Return true if the exception was caused by the hook in the linker
188  * code, we'll worry about whether or not any libraries were
189  * added/removed later on when we handle the exception
190  */
191 bool dynamic_linking::decodeIfDueToSharedObjectMapping(EventRecord &ev,
192                                                        unsigned int & /* change_type */) 
193 {
194     assert(ev.lwp);
195     dyn_lwp *brk_lwp = ev.lwp;
196     sharedLibHook *hook = NULL;
197     
198     Frame brk_frame = brk_lwp->getActiveFrame();
199     hook = reachedLibHook(brk_frame.getPC());
200    
201     return (bool) hook;
202 }
203
204 // handleIfDueToSharedObjectMapping: returns true if the trap was caused
205 // by a change to the link maps
206 // p - process we're dealing with
207 // changed_objects -- set to list of new objects
208 // change_type -- set to 1 if added, 2 if removed
209 // error_occurred -- duh
210 // return value: true if there was a change to the link map,
211 // false otherwise
212 bool dynamic_linking::handleIfDueToSharedObjectMapping(EventRecord &ev,
213                                 pdvector<mapped_object *> &changed_objects,
214                                 pdvector<bool> &is_new_object)
215 {
216     // We discover it by comparing sizes
217     dyn_lwp *brk_lwp = instru_based ? NULL : ev.lwp;
218     sharedLibHook *hook = NULL;
219
220     if (!instru_based && brk_lwp) {
221        Frame brk_frame = brk_lwp->getActiveFrame();
222        hook = reachedLibHook(brk_frame.getPC());
223     }
224
225     if (force_library_load || hook || instru_based) {
226         
227         if (!findChangeToLinkMaps(changed_objects, is_new_object))
228             return false;
229         if (brk_lwp) {
230           // Now we need to fix the PC. We overwrote the return instruction,
231           // so grab the value in the link register and set the PC to it.
232           dyn_saved_regs regs;
233           bool status = brk_lwp->getRegisters(&regs);
234           assert(status == true);
235           brk_lwp->changePC(regs.theIntRegs.__lr, NULL);
236           return true;
237    }
238         else
239       return true;
240     }
241     return false;
242 }
243
244 sharedLibHook::sharedLibHook(process *p, sharedLibHookType t, Address b) 
245         : proc_(p), type_(t), breakAddr_(b), loadinst_(NULL) {
246
247     // Before putting in the breakpoint, save what is currently at the
248     // location that will be overwritten.
249     proc_->readDataSpace((void *)breakAddr_, SLH_SAVE_BUFFER_SIZE,
250                          (void *)saved_, true);
251
252     codeGen gen(instruction::size());
253     instruction::generateTrap(gen);
254     
255     if (!proc_->writeDataSpace((caddr_t)breakAddr_,
256                           gen.used(),
257                           gen.start_ptr()))
258         fprintf(stderr, "%s[%d]:  writeDataSpace failed\n", FILE__, __LINE__);
259     
260 }
261
262 sharedLibHook::sharedLibHook(process *p, sharedLibHookType t, instMapping *inst) 
263         : proc_(p), type_(t), breakAddr_(0), loadinst_(inst) {
264 }
265
266 sharedLibHook::~sharedLibHook() {
267     if (!proc_->isAttached() || proc_->execing())
268         return;
269     
270     if (breakAddr_)
271         if (!proc_->writeDataSpace((void *)breakAddr_, SLH_SAVE_BUFFER_SIZE, saved_))
272           fprintf(stderr, "%s[%d]:  writeDataSpace failed\n", FILE__, __LINE__);
273     else if (loadinst_) {
274         miniTramp *handle;
275         for (unsigned i = 0; i < loadinst_->miniTramps.size(); i++) {
276             handle = loadinst_->miniTramps[i];
277             handle->uninstrument();
278         }
279         delete loadinst_;
280     }
281 }
282