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