Update copyright to LGPL on all files
[dyninst.git] / dyninstAPI / src / dynamiclinking.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: dynamiclinking.C,v 1.22 2007/12/12 22:20:42 roundy Exp $
33
34 // Cross-platform dynamic linking functions
35
36 #include "dyninstAPI/src/dynamiclinking.h"
37 #include "dyninstAPI/src/process.h"
38 #include "mapped_object.h"
39 #include "dyn_thread.h"
40
41 dynamic_linking::dynamic_linking(process *p): proc(p), dynlinked(false),
42                                               dlopen_addr(0), 
43                                               instru_based(false),
44                                               force_library_load(false), 
45                                               lowestSObaseaddr(0),
46                                               dlopenUsed(false) 
47
48 }
49
50 dynamic_linking::dynamic_linking(const dynamic_linking *pDL,
51                                  process *child): proc(child),
52                                                   dynlinked(pDL->dynlinked),
53                                                   dlopen_addr(pDL->dlopen_addr),
54                                                   instru_based(pDL->instru_based),
55                                                   force_library_load(pDL->force_library_load),
56                                                   lowestSObaseaddr(pDL->lowestSObaseaddr),
57                                                   dlopenUsed(pDL->dlopenUsed)
58 {
59 #if defined(os_linux)
60     r_debug_addr = pDL->r_debug_addr;
61     r_brk_target_addr = pDL->r_brk_target_addr;
62     previous_r_state = pDL->previous_r_state;
63 #endif
64 #if defined(os_solaris)
65     r_debug_addr = pDL->r_debug_addr;
66     r_state = pDL->r_state;
67 #endif
68     for (unsigned i = 0; i < pDL->sharedLibHooks_.size(); i++) {
69         sharedLibHooks_.push_back(new sharedLibHook(pDL->sharedLibHooks_[i],
70                                                     child));
71     }
72 }
73
74
75 dynamic_linking::~dynamic_linking() {
76     uninstallTracing();
77 }
78
79
80
81 // And unload the tracing breakpoints inserted
82 bool dynamic_linking::uninstallTracing() 
83 {
84     for (unsigned i= 0; i < sharedLibHooks_.size(); i++)
85         delete sharedLibHooks_[i];
86     sharedLibHooks_.resize(0);
87     return true;
88 }
89
90 sharedLibHook *dynamic_linking::reachedLibHook(Address a) {
91     for (unsigned i = 0; i < sharedLibHooks_.size(); i++)
92         if (sharedLibHooks_[i]->reachedBreakAddr(a))
93             return sharedLibHooks_[i];
94     return NULL;
95 }
96
97 dyn_lwp *dynamic_linking::findLwpAtLibHook(process *proc, sharedLibHook **hook_handle)
98 {
99   pdvector<dyn_thread *>::iterator iter = proc->threads.begin();
100
101   dyn_lwp *brk_lwp = NULL;
102   sharedLibHook *hook = NULL;
103
104   while (iter != proc->threads.end()) {
105     dyn_thread *thr = *(iter);
106     dyn_lwp *cur_lwp = thr->get_lwp();
107
108     if(cur_lwp->status() == running) {
109       iter++;
110       continue;  // if lwp is running couldn't have hit load library trap
111     }
112
113     Frame lwp_frame = cur_lwp->getActiveFrame();
114     hook = reachedLibHook(lwp_frame.getPC());
115     if (hook) {
116       brk_lwp = cur_lwp;
117       if (hook_handle)
118         *hook_handle = hook;
119       break;
120     }
121
122     iter++;
123   }
124   return brk_lwp;
125 }
126
127
128 bool sharedLibHook::reachedBreakAddr(Address b) const {
129     if (breakAddr_ == 0) return false;
130
131 #if defined(arch_x86) || defined(arch_x86_64)
132     return ((b-1) == breakAddr_);
133 #else
134     return (b == breakAddr_); 
135 #endif
136 };
137
138 sharedLibHook::sharedLibHook(const sharedLibHook *pSLH, process *child) :
139     proc_(child),
140     type_(pSLH->type_),
141     breakAddr_(pSLH->breakAddr_),
142     loadinst_(NULL)
143 {
144     // FIXME
145     if (pSLH->loadinst_) {
146         loadinst_ = new instMapping(pSLH->loadinst_, child);
147     }
148     memcpy(saved_, pSLH->saved_, SLH_SAVE_BUFFER_SIZE);
149 }
150
151 // getSharedObjects: gets a complete list of shared objects in the
152 // process. Normally used to initialize the process-level shared
153 // objects list.  This function is only called once, and creates
154 // mapped objects for all shared libraries
155 bool dynamic_linking::getSharedObjects(pdvector<mapped_object *> &mapped_objects) 
156 {
157     pdvector<fileDescriptor> descs;
158     
159     if (!processLinkMaps(descs))
160         return false;
161
162     // Skip entries that have already been added
163     for (unsigned i = 0; i < descs.size(); i++) {
164          if (!proc->findObject(descs[i]) && 
165              !strstr(descs[i].file().c_str(),"ld.so.cache")) {
166 #if 0
167             fprintf(stderr, "DEBUG: match pattern %d, %d, %d, %d, %d\n",
168                     descs[i].file() == proc->getAOut()->getFileDesc().file(),
169                     descs[i].code() == proc->getAOut()->getFileDesc().code(),
170                     descs[i].data() == proc->getAOut()->getFileDesc().data(),
171                     descs[i].member() == proc->getAOut()->getFileDesc().member(),
172                     descs[i].pid() == proc->getAOut()->getFileDesc().pid());
173 #endif
174             mapped_object *newobj = 
175                mapped_object::createMappedObject(descs[i], proc);
176             if (newobj == NULL) continue;
177             mapped_objects.push_back(newobj);
178 #if defined(cap_save_the_world)
179             setlowestSObaseaddr(descs[i].code());
180 #endif
181         }           
182     }
183     return true;
184 } /* end getSharedObjects() */
185
186
187 #if !defined(os_windows) // Where we don't need it and the compiler complains...
188
189 // findChangeToLinkMaps: This routine returns a vector of shared
190 // objects that have been added or deleted to the link maps
191 // corresponding to a true or false entry in is_new_object.  
192 //
193 // Return false only if there was some problem processing the link maps
194 bool dynamic_linking::findChangeToLinkMaps(pdvector<mapped_object *> &changed_objects,
195                                            pdvector<bool> &is_new_object) 
196 {
197   const pdvector<mapped_object *> &curr_list = proc->mappedObjects();
198   pdvector<fileDescriptor> new_descs;
199   if (!processLinkMaps(new_descs)) {
200       return false;
201   }
202
203   // match up objects between the two lists, "consumed" tracks objects
204   // in new_descs that we've matched against curr_list
205   unsigned curr_size = curr_list.size();
206   unsigned descs_size = new_descs.size();
207   bool consumed [descs_size];
208   memset(consumed, 0, sizeof(bool) * descs_size);
209   for (unsigned int i = 0; i < curr_size; i++) {
210      if (curr_list[i] == proc->getAOut()) {
211          continue; // a.out is not listed in the link maps
212      }
213      bool found = false;
214      for (unsigned int j=0; !found && j < descs_size; j++) {
215          if (!consumed[j] && new_descs[j] == curr_list[i]->getFileDesc()) {
216              found = true;
217              consumed[j] = true;
218          }
219      }
220      if (!found) {
221         changed_objects.push_back(curr_list[i]);
222         is_new_object.push_back(false);
223      }
224   }
225   for (unsigned int i=0; i < descs_size; i++) {
226      if (consumed[i] == false 
227          && new_descs[i] != proc->getAOut()->getFileDesc()) {
228          mapped_object *newobj = 
229              mapped_object::createMappedObject(new_descs[i], proc);
230          if (newobj != NULL) {
231              changed_objects.push_back(newobj);
232              is_new_object.push_back(true);
233          }
234      }
235   }
236   return true;
237 }
238
239 #else
240 bool dynamic_linking::findChangeToLinkMaps(pdvector<mapped_object *> &,
241                                            pdvector<bool> &) 
242 {
243     return true;
244 }
245
246 #endif // defined(os_windows)
247