Refactoring some DWARF parsing to be accessible to StackwalkerAPI
[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       sw_printf("[%s:%u] - updateLibsArch failed\n",  __FILE__, __LINE__);
111    }
112
113    getCurList(post);
114    
115    StepperGroup *group = procstate->getWalker()->getStepperGroup();
116    set_difference(pre.begin(), pre.end(),
117                  post.begin(), post.end(), 
118                  inserter(diff, diff.begin()));
119    for (set<LibAddrPair>::iterator i = diff.begin(); i != diff.end(); i++) {
120       LibAddrPair la = *i;
121       group->newLibraryNotification(&la, library_unload);
122    }
123    diff.clear();
124
125    set_difference(post.begin(), post.end(),
126                  pre.begin(), pre.end(), 
127                  inserter(diff, diff.begin()));
128    for (set<LibAddrPair>::iterator i = diff.begin(); i != diff.end(); i++) {
129       LibAddrPair la = *i;
130       group->newLibraryNotification(&la, library_load);
131    }
132                  
133    return true;
134 }
135
136 bool TrackLibState::getLibraryAtAddr(Address addr, LibAddrPair &olib)
137 {
138    bool result = refresh();
139    if (!result) {
140       sw_printf("[%s:%u] - Failed to refresh library.\n", __FILE__, __LINE__);
141       setLastError(err_symtab, "Failed to refresh library list");
142       return false;
143    }
144    
145    Address load_addr;
146    
147    std::vector<std::pair<LibAddrPair, unsigned> >::iterator i;
148    for (i = arch_libs.begin(); i != arch_libs.end(); i++) {
149       load_addr = (*i).first.second;
150       unsigned size = (*i).second;
151       if ((addr >= load_addr) && (addr < load_addr + size)) {
152          olib = (*i).first;
153          return true;
154       }
155    }
156
157    LoadedLib *ll;
158    result = translate->getLibAtAddress(addr, ll);
159    if (!result) {
160       sw_printf("[%s:%u] - no file loaded at %lx\n", __FILE__, __LINE__, addr);
161       setLastError(err_nofile, "No file loaded at specified address");
162       return false;
163    }
164
165    olib.first = ll->getName();
166    olib.second = ll->getCodeLoadAddr();
167    
168    return true;
169 }
170
171 bool TrackLibState::getLibraries(std::vector<LibAddrPair> &olibs)
172 {
173    bool result = refresh();
174    if (!result) {
175       setLastError(err_symtab, "Failed to refresh library list");
176       return false;
177    }
178    
179    vector<LoadedLib *> libs;
180    result = translate->getLibs(libs);
181    if (!result) {
182       setLastError(err_symtab, "No objects in process");
183       return false;
184    }
185    
186    olibs.clear();
187    vector<LoadedLib *>::iterator i;
188    for (i = libs.begin(); i != libs.end(); i++) {
189       LibAddrPair o;
190       o.first = (*i)->getName();
191       o.second = (*i)->getCodeLoadAddr();
192       olibs.push_back(o);
193    }
194    return true;
195 }
196
197 bool TrackLibState::refresh()
198 {
199    bool result = updateLibs();
200    if (!result)
201       return false;
202    //TODO: Determine difference, notify steppergroup of diff
203    return true;
204 }
205
206 Address TrackLibState::getLibTrapAddress() {
207    return translate->getLibraryTrapAddrSysV();
208 }
209
210 TrackLibState::~TrackLibState() {
211 }
212
213 void TrackLibState::notifyOfUpdate() {
214    //This may be called under a signal handler, keep simple
215    needs_update = true;
216 }
217
218 static bool libNameMatch(const char *s, const char *libname)
219 {
220    // A poor-man's regex match for */lib<s>[0123456789-.]*.so*
221    const char *filestart = strrchr(libname, '/');
222    if (!filestart)
223       filestart = libname;
224    const char *lib_start = strstr(filestart, "lib");
225    if (lib_start != filestart+1)
226       return false;
227    const char *libname_start = lib_start+3;
228    int s_len = strlen(s);
229    if (strncmp(s, libname_start, s_len) != 0) {
230       return false;
231    }
232
233    const char *cur = libname_start + s_len;
234    const char *valid_chars = "0123456789-.";
235    while (*cur) {
236       if (!strchr(valid_chars, *cur)) {
237          cur--;
238          if (strstr(cur, ".so") == cur) {
239             return true;
240          }
241          return false;
242       }
243       cur++;
244    }
245    return false;
246 }
247
248 bool TrackLibState::getLibc(LibAddrPair &addr_pair)
249 {
250    std::vector<LibAddrPair> libs;
251    getLibraries(libs);
252    if (libs.size() == 1) {
253       //Static binary.
254       addr_pair = libs[0];
255       return true;
256    }
257    for (std::vector<LibAddrPair>::iterator i = libs.begin(); i != libs.end(); i++)
258    {
259       if (libNameMatch("c", i->first.c_str())) {
260          addr_pair = *i;
261          return true;
262       }
263    }
264    return false;
265 }
266
267 bool TrackLibState::getLibthread(LibAddrPair &addr_pair)
268 {
269    std::vector<LibAddrPair> libs;
270    getLibraries(libs);
271    if (libs.size() == 1) {
272       //Static binary.
273       addr_pair = libs[0];
274       return true;
275    }
276    for (std::vector<LibAddrPair>::iterator i = libs.begin(); i != libs.end(); i++)
277    {
278       if (libNameMatch("pthread", i->first.c_str())) {
279          addr_pair = *i;
280          return true;
281       }
282    }
283    return false;
284 }
285
286 bool TrackLibState::getAOut(LibAddrPair &addr_pair)
287 {
288    LoadedLib *aout;
289    updateLibs();
290    aout = translate->getExecutable();
291    if (!aout) {
292       sw_printf("[%s:%u] - Error.  SymtabAPI getAOut failed\n",
293                 __FILE__, __LINE__);
294       return false;
295    }
296    addr_pair = LibAddrPair(aout->getName(), aout->getCodeLoadAddr());
297    return true;
298 }
299
300 swkProcessReader::swkProcessReader(ProcessState *pstate, const std::string& executable) :
301    procstate(pstate)
302 {
303 }
304
305 bool swkProcessReader::ReadMem(Address inTraced, void *inSelf, unsigned amount)
306 {
307   return procstate->readMem(inSelf, inTraced, amount);
308 }
309
310 swkProcessReader::~swkProcessReader()
311 {
312 }
313
314 bool swkProcessReader::start()
315 {
316    return true;
317 }
318
319 bool swkProcessReader::done()
320 {
321    return true;
322 }