Updated READMEs
[dyninst.git] / stackwalk / src / libstate.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 #include "stackwalk/src/libstate.h"
32
33 #include "stackwalk/h/swk_errors.h"
34 #include "stackwalk/h/steppergroup.h"
35 #include "stackwalk/h/walker.h"
36
37 #include <set>
38 #include <algorithm>
39 #include <iterator>
40
41 #include <string.h>
42
43 using namespace Dyninst;
44 using namespace Stackwalker;
45 using namespace std;
46
47 SymbolReaderFactory *TrackLibState::symfactory = NULL;
48
49 TrackLibState::TrackLibState(ProcessState *parent, std::string executable_) : 
50    LibraryState(parent),
51    needs_update(true),
52    has_updated(false),
53    translate(NULL),
54    procreader(parent, executable_)
55 {
56    PID pid = procstate->getProcessId();
57    
58    sw_printf("[%s:%u] - Creating a TrackLibState on pid %d\n",
59              FILE__, __LINE__, pid);
60    if (!symfactory)
61       symfactory = Walker::getSymbolReader();
62
63    if (procstate->isFirstParty()) {
64       translate = AddressTranslate::createAddressTranslator(&procreader, symfactory, executable_);
65    }
66    else {
67       translate = AddressTranslate::createAddressTranslator(pid, &procreader, symfactory, INVALID_HANDLE_VALUE, executable_);
68    }
69    if (!translate) {
70       sw_printf("[%s:%u] - Creation of AddressTranslate failed "
71                 "on pid %d!\n", FILE__, __LINE__, pid);
72    }
73    assert(translate);
74 }
75
76 void TrackLibState::getCurList(std::set<LibAddrPair> &list)
77 {
78    vector<LoadedLib *> libs;
79    bool result = translate->getLibs(libs);
80    if (!result) {
81       return;
82    }
83    vector<LoadedLib *>::iterator i;
84    for (i = libs.begin(); i != libs.end(); i++) {
85       LibAddrPair o;
86       o.first = (*i)->getName();
87       o.second = (*i)->getCodeLoadAddr();
88       list.insert(o);
89    }
90 }
91
92 bool TrackLibState::updateLibs()
93 {
94    if (!needs_update)
95       return true;
96    needs_update = false;
97
98    std::set<LibAddrPair> pre, post, diff;
99    if (has_updated) {
100       getCurList(pre);
101    }
102    has_updated = true;
103
104    PID pid = procstate->getProcessId();
105    bool result = translate->refresh();
106    if (!result) {
107       sw_printf("[%s:%u] - Could not get load addresses out of SymtabAPI for %d."
108                 "This may happen during process create before libs have be set up\n",
109                  FILE__, __LINE__, pid);
110       needs_update = true;
111    }
112
113    vector<pair<LibAddrPair, unsigned int> > arch_libs;
114    if (!updateLibsArch(arch_libs)) {
115 #if !defined(os_linux) && !defined(arch_x86_64)
116       sw_printf("[%s:%u] - updateLibsArch failed\n",  FILE__, __LINE__);
117 #endif
118    }
119
120    getCurList(post);
121    
122    StepperGroup *group = procstate->getWalker()->getStepperGroup();
123    set_difference(pre.begin(), pre.end(),
124                  post.begin(), post.end(), 
125                  inserter(diff, diff.begin()));
126    for (set<LibAddrPair>::iterator i = diff.begin(); i != diff.end(); i++) {
127       LibAddrPair la = *i;
128       group->newLibraryNotification(&la, library_unload);
129    }
130    diff.clear();
131
132    set_difference(post.begin(), post.end(),
133                  pre.begin(), pre.end(), 
134                  inserter(diff, diff.begin()));
135    for (set<LibAddrPair>::iterator i = diff.begin(); i != diff.end(); i++) {
136       LibAddrPair la = *i;
137       group->newLibraryNotification(&la, library_load);
138    }
139                  
140    return true;
141 }
142
143 bool TrackLibState::getLibraryAtAddr(Address addr, LibAddrPair &olib)
144 {
145    bool result = refresh();
146    if (!result) {
147       sw_printf("[%s:%u] - Failed to refresh library.\n", FILE__, __LINE__);
148       setLastError(err_symtab, "Failed to refresh library list");
149       return false;
150    }
151    
152    Address load_addr;
153    
154    std::vector<std::pair<LibAddrPair, unsigned> >::iterator i;
155    for (i = arch_libs.begin(); i != arch_libs.end(); i++) {
156       load_addr = (*i).first.second;
157       unsigned size = (*i).second;
158       if ((addr >= load_addr) && (addr < load_addr + size)) {
159          olib = (*i).first;
160          return true;
161       }
162    }
163
164    LoadedLib *ll;
165    result = translate->getLibAtAddress(addr, ll);
166    if (!result) {
167       sw_printf("[%s:%u] - no file loaded at %lx\n", FILE__, __LINE__, addr);
168       setLastError(err_nofile, "No file loaded at specified address");
169       return false;
170    }
171
172    olib.first = ll->getName();
173    olib.second = ll->getCodeLoadAddr();
174    
175    return true;
176 }
177
178 bool TrackLibState::getLibraries(std::vector<LibAddrPair> &olibs, bool allow_refresh)
179 {
180    bool result;
181    if (allow_refresh) {
182       result = refresh();
183       if (!result) {
184          setLastError(err_symtab, "Failed to refresh library list");
185          return false;
186       }
187    }
188
189    vector<LoadedLib *> libs;
190    result = translate->getLibs(libs);
191    if (!result) {
192       setLastError(err_symtab, "No objects in process");
193       return false;
194    }
195    
196    olibs.clear();
197    vector<LoadedLib *>::iterator i;
198    for (i = libs.begin(); i != libs.end(); i++) {
199       LibAddrPair o;
200       o.first = (*i)->getName();
201       o.second = (*i)->getCodeLoadAddr();
202       olibs.push_back(o);
203    }
204    return true;
205 }
206
207 bool TrackLibState::refresh()
208 {
209    bool result = updateLibs();
210    if (!result)
211       return false;
212    //TODO: Determine difference, notify steppergroup of diff
213    return true;
214 }
215
216 Address TrackLibState::getLibTrapAddress() {
217    return translate->getLibraryTrapAddrSysV();
218 }
219
220 TrackLibState::~TrackLibState() {
221   delete translate;
222   
223 }
224
225 void TrackLibState::notifyOfUpdate() {
226    //This may be called under a signal handler, keep simple
227    needs_update = true;
228 }
229
230 static bool libNameMatch(const char *s, const char *libname)
231 {
232    // A poor-man's regex match for */lib<s>[0123456789-.]*.so*
233    const char *filestart = strrchr(libname, '/');
234    if (!filestart)
235       filestart = libname;
236    const char *lib_start = strstr(filestart, "lib");
237    if (lib_start != filestart+1)
238       return false;
239    const char *libname_start = lib_start+3;
240    int s_len = strlen(s);
241    if (strncmp(s, libname_start, s_len) != 0) {
242       return false;
243    }
244
245    const char *cur = libname_start + s_len;
246    const char *valid_chars = "0123456789-.";
247    while (*cur) {
248       if (!strchr(valid_chars, *cur)) {
249          cur--;
250          if (strstr(cur, ".so") == cur) {
251             return true;
252          }
253          return false;
254       }
255       cur++;
256    }
257    return false;
258 }
259
260 bool LibraryState::getLibc(LibAddrPair &addr_pair)
261 {
262    std::vector<LibAddrPair> libs;
263    getLibraries(libs, false);
264    if (libs.size() == 1) {
265       //Static binary.
266       addr_pair = libs[0];
267       return true;
268    }
269    for (std::vector<LibAddrPair>::iterator i = libs.begin(); i != libs.end(); i++)
270    {
271       if (libNameMatch("c", i->first.c_str())) {
272          addr_pair = *i;
273          return true;
274       }
275    }
276    return false;
277 }
278
279 bool LibraryState::getLibthread(LibAddrPair &addr_pair)
280 {
281    std::vector<LibAddrPair> libs;
282    getLibraries(libs, false);
283    if (libs.size() == 1) {
284       //Static binary.
285       addr_pair = libs[0];
286       return true;
287    }
288    for (std::vector<LibAddrPair>::iterator i = libs.begin(); i != libs.end(); i++)
289    {
290       if (libNameMatch("pthread", i->first.c_str()) || libNameMatch("thr", i->first.c_str()))  {
291          addr_pair = *i;
292          return true;
293       }
294    }
295    return false;
296 }
297
298 bool TrackLibState::getAOut(LibAddrPair &addr_pair)
299 {
300    LoadedLib *aout;
301    updateLibs();
302    aout = translate->getExecutable();
303    if (!aout) {
304       sw_printf("[%s:%u] - Error.  SymtabAPI getAOut failed\n",
305                 FILE__, __LINE__);
306       return false;
307    }
308    addr_pair = LibAddrPair(aout->getName(), aout->getCodeLoadAddr());
309    return true;
310 }
311
312 swkProcessReader::swkProcessReader(ProcessState *pstate, std::string /*executable*/) :
313    procstate(pstate)
314 {
315 }
316
317 bool swkProcessReader::ReadMem(Address inTraced, void *inSelf, unsigned amount)
318 {
319   return procstate->readMem(inSelf, inTraced, amount);
320 }
321
322 swkProcessReader::~swkProcessReader()
323 {
324 }
325
326 bool swkProcessReader::start()
327 {
328    return true;
329 }
330
331 bool swkProcessReader::done()
332 {
333    return true;
334 }
335
336 static LibraryWrapper libs;
337
338 SymReader *LibraryWrapper::getLibrary(std::string filename)
339 {
340    std::map<std::string, SymReader *>::iterator i = libs.file_map.find(filename);
341    if (i != libs.file_map.end()) {
342       return i->second;
343    }
344    
345    SymbolReaderFactory *fact = Walker::getSymbolReader();
346    SymReader *reader = fact->openSymbolReader(filename);
347    if (!reader)
348       return NULL;
349    libs.file_map[filename] = reader;
350    return reader;
351 }
352
353 void LibraryWrapper::registerLibrary(SymReader *reader, std::string filename)
354 {
355    libs.file_map[filename] = reader;
356 }
357  
358 SymReader *LibraryWrapper::testLibrary(std::string filename)
359 {
360    std::map<std::string, SymReader *>::iterator i = libs.file_map.find(filename);
361    if (i != libs.file_map.end()) {
362       return i->second;
363    }
364    return NULL;
365 }
366
367 StaticBinaryLibState::StaticBinaryLibState(ProcessState *parent, std::string executable) :
368    LibraryState(parent)
369 {
370    the_exe.first = executable;
371    the_exe.second = 0x0;
372 }
373
374 StaticBinaryLibState::~StaticBinaryLibState()
375 {
376 }
377
378 bool StaticBinaryLibState::getLibraryAtAddr(Address /*addr*/, LibAddrPair &olib)
379 {
380    olib = the_exe;
381    return true;
382 }
383
384 bool StaticBinaryLibState::getLibraries(std::vector<LibAddrPair> &olibs, bool /*allow_refresh*/)
385 {
386    olibs.push_back(the_exe);
387    return true;
388 }
389
390 bool StaticBinaryLibState::getLibc(LibAddrPair &lc)
391 {
392    lc = the_exe;
393    return true;
394 }
395
396 bool StaticBinaryLibState::getLibthread(LibAddrPair &lt)
397 {
398    lt = the_exe;
399    return true;
400 }
401
402 bool StaticBinaryLibState::getAOut(LibAddrPair &ao)
403 {
404    ao = the_exe;
405    return true;
406 }
407
408 void StaticBinaryLibState::notifyOfUpdate()
409 {
410 }
411
412 Address StaticBinaryLibState::getLibTrapAddress()
413 {
414    return 0x0;
415 }