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