Update copyright to LGPL on all files
[dyninst.git] / symtabAPI / src / addrtranslate-aix.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 "symtabAPI/src/addrtranslate.h"
33 #include "common/h/headers.h"
34
35 #include "symtabAPI/h/Symtab.h"
36 #include "symtabAPI/h/Archive.h"
37
38 #include <sys/procfs.h>
39 #include <string.h>
40 #include <string>
41 #include <vector>
42 #include <map>
43
44 namespace Dyninst {
45 namespace SymtabAPI {
46
47 class AddressTranslateAIX : public AddressTranslate
48 {
49 public:
50    AddressTranslateAIX();
51    AddressTranslateAIX(PID pid);
52
53    virtual bool refresh();
54    virtual ~AddressTranslateAIX();
55    Address getLibraryTrapAddrSysV();
56 };
57
58 class LoadedLibAIX : public LoadedLib {
59 protected:
60    string object;
61
62    Address real_codeBase;
63    Address real_dataBase;
64    Address imageOffset;
65    Address dataOffset;
66    
67    bool reals_set;
68    void setReals();
69 public:
70    LoadedLibAIX(string name, Address load_addr, string object);
71    
72    virtual Symtab *getSymtab();
73    virtual ~LoadedLibAIX();
74
75    virtual Address symToAddress(Symbol *sym);
76    virtual Address offToAddress(Offset off);
77    virtual Offset addrToOffset(Address addr);
78
79    virtual Address getCodeLoadAddr();
80    virtual Address getDataLoadAddr();
81    virtual void getOutputs(string &filename, Address &code, Address &data);
82 };
83
84 static int open_map_fd(PID pid)
85 {
86    char file[64];
87    snprintf(file, 64, "/proc/%d/map", pid);
88    int fd = P_open(file, O_RDONLY, pid);
89    return fd;
90 }
91
92 static char *deref_link(char *path)
93 {
94    static char buffer[PATH_MAX], *p;
95    buffer[PATH_MAX-1] = '\0';
96    p = realpath(path, buffer);
97    if (p)
98       return p;
99    return path;
100 }
101
102 bool AddressTranslateAIX::refresh()
103 {
104    unsigned iter = 0;
105    bool is_aout = true;
106    int map_fd = -1;
107    int result;
108    if (!pid)
109       return true;
110    
111    for (unsigned i=0; i<libs.size(); i++) {
112       if (libs[i])
113          delete libs[i];
114    }
115    libs.clear();
116    
117    map_fd = open_map_fd(pid);
118    if (map_fd == -1)
119       return false;
120
121    prmap_t mapEntry;
122
123    for (;;) {
124       result = pread(map_fd, &mapEntry, sizeof(prmap_t), iter * sizeof(prmap_t));
125       if (result != sizeof(prmap_t))
126          break;
127       if (mapEntry.pr_size == 0)
128          break;
129
130       char buf[512];
131       if (mapEntry.pr_pathoff) {
132          pread(map_fd, buf, 512, mapEntry.pr_pathoff);
133       }
134       
135       printf("%lu\n" 
136              "\taddr = %llx +%llu\n"
137              "\tmapname = %s\n"
138              "\toffset = %llu, flags = %d\n"
139              "\tpr_pathoff = %d (%s)\n"
140              "\tobject = %s\n"
141              "\talias = %llx, gp = %llx\n",
142              iter * sizeof(prmap_t), 
143              mapEntry.pr_vaddr, mapEntry.pr_size, 
144              mapEntry.pr_mapname,
145              mapEntry.pr_off, mapEntry.pr_mflags,
146              mapEntry.pr_pathoff, mapEntry.pr_pathoff ? buf : "NONE",
147              mapEntry.pr_pathoff ? buf + strlen(buf) + 1 : "NONE",
148              mapEntry.pr_alias, mapEntry.pr_gp);
149       
150       if (mapEntry.pr_pathoff) {
151          string filename = buf;
152          string object_name = buf + strlen(buf) + 1;
153          LoadedLib *ll = new LoadedLibAIX(filename, 0, object_name);
154          Symtab *s = ll->getSymtab();
155          printf("\timageOffset = %ld, length = %lu\n"
156                 "\tdataOffset = %ld, length = %lu\n",
157                 s->imageOffset(), s->imageLength(),
158                 s->dataOffset(), s->dataLength());
159       }
160
161       printf("\n");
162       iter++;
163    }
164
165    iter = 0;
166
167    for (;;) {
168       result = pread(map_fd, &mapEntry, sizeof(prmap_t), iter * sizeof(prmap_t));
169       if (result != sizeof(prmap_t))
170          break;
171       if (mapEntry.pr_size == 0)
172          break;
173       
174       string filename;
175       string object_name;
176       /*      
177               if (is_aout) {
178                 char buf[128];
179                 sprintf(buf, "/proc/%d/object/a.out", pid);
180                 filename = deref_link(buf);
181               }
182       */
183       if (mapEntry.pr_pathoff) {
184          char buf[512];
185          pread(map_fd, buf, 256, mapEntry.pr_pathoff);
186          filename = deref_link(buf);
187          object_name = buf + strlen(buf) + 1;
188       }
189       else {
190          filename = deref_link(mapEntry.pr_mapname);
191       }
192       is_aout = false;
193       
194       LoadedLib *ll = new LoadedLibAIX(filename, (unsigned long)mapEntry.pr_vaddr, object_name);
195
196       iter++;
197       ll->add_mapped_region((unsigned long)mapEntry.pr_vaddr, mapEntry.pr_size);
198       libs.push_back(ll);
199
200       prmap_t next;
201       result = pread(map_fd, &next, sizeof(prmap_t), iter * sizeof(prmap_t));
202       if (result != sizeof(prmap_t))
203          break;
204       if (strcmp(mapEntry.pr_mapname, next.pr_mapname))
205          continue;
206
207       iter++;
208       ll->add_mapped_region((unsigned long)next.pr_vaddr, next.pr_size);
209       ll->setDataLoadAddr((unsigned long)next.pr_vaddr);
210    }
211    
212    P_close(map_fd);
213    return true;
214 }
215
216 AddressTranslate *AddressTranslate::createAddressTranslator(PID pid_, 
217                                                             ProcessReader *,
218                                                                                                                         PROC_HANDLE)
219 {
220    AddressTranslate *at = new AddressTranslateAIX(pid_);
221    
222    if (!at) {
223       return NULL;
224    }
225    else if (at->creation_error) {
226       delete at;
227       return NULL;
228    }
229    return at;
230 }
231
232 AddressTranslate *AddressTranslate::createAddressTranslator(ProcessReader *)
233 {
234    return createAddressTranslator(getpid());
235 }
236
237 AddressTranslate *AddressTranslate::createAddressTranslator(const std::vector<LoadedLibrary> &name_addrs)
238 {
239    AddressTranslate *at = new AddressTranslateAIX();
240    
241    if (!at) {
242       return NULL;
243    }
244    else if (at->creation_error) {
245       delete at;
246       return NULL;
247    }
248    
249    for (unsigned i=0; i<name_addrs.size(); i++)
250    {
251       string::size_type cpos = name_addrs[i].name.find(':');
252       string archive_name, object_name;
253       if (cpos == string::npos)
254          archive_name = name_addrs[i].name;
255       else
256       {
257          archive_name = name_addrs[i].name.substr(0, cpos);
258          object_name = name_addrs[i].name.substr(cpos+1);
259       }
260
261       LoadedLibAIX *ll = new LoadedLibAIX(archive_name, name_addrs[i].codeAddr,
262                                           object_name);
263       ll->setDataLoadAddr(name_addrs[i].dataAddr);
264       
265       Symtab *st = ll->getSymtab();
266       if (!st)
267          continue;
268       vector<Region *> regs;
269       bool result = st->getMappedRegions(regs);
270       if (!result)
271          continue;
272       
273       ll->add_mapped_region(name_addrs[i].codeAddr, regs[0]->getRegionSize());
274       if (name_addrs[i].dataAddr) {
275          ll->add_mapped_region(name_addrs[i].dataAddr, regs[1]->getRegionSize());
276       }
277       at->libs.push_back(ll);
278    }
279    return at;
280 }
281
282 AddressTranslateAIX::AddressTranslateAIX()
283    : AddressTranslate(0)
284 {
285 }
286
287 AddressTranslateAIX::AddressTranslateAIX(PID pid)
288    : AddressTranslate(pid)
289 {
290    refresh();
291 }
292
293 AddressTranslateAIX::~AddressTranslateAIX()
294 {
295 }
296
297 vector< pair<Address, unsigned long> > *LoadedLib::getMappedRegions()
298 {
299    return &mapped_regions;
300 }
301
302 static map<string, Symtab *> openedFiles;
303 static map<string, Archive *> openedArchives;
304
305 Symtab *LoadedLib::getSymtab()
306 {
307    assert(0);
308    return NULL;
309 }
310
311 Symtab *LoadedLibAIX::getSymtab()
312 {
313    if (symtable)
314       return symtable;
315
316    if (object.length())
317    {
318       string hash_name = name + ":" + object;
319       if (openedFiles.count(hash_name)) {
320          symtable = openedFiles[hash_name];
321          return symtable;
322       }
323
324       Archive *archive;
325       if (openedArchives.count(name))
326       {
327          archive = openedArchives[name];
328       }
329       else
330       {
331          if (!Archive::openArchive(archive, name))
332             return NULL;
333          openedArchives[name] = archive;
334       }
335       
336       bool result = archive->getMember(symtable, object);
337       if (!result || !symtable)
338          return NULL;
339       openedFiles[hash_name] = symtable;
340
341       return symtable;
342    }
343
344    if (openedFiles.count(name)) {
345       symtable = openedFiles[name];
346       return symtable;
347    }
348
349    bool result = Symtab::openFile(symtable, name);
350    if (!result)
351       return NULL;
352    
353    return symtable;
354 }
355
356 LoadedLibAIX::LoadedLibAIX(string name, Address load_addr, string obj)
357    : LoadedLib(name, load_addr),
358      object(obj),
359      real_codeBase(0),
360      real_dataBase(0),
361      imageOffset(0),
362      dataOffset(0),
363      reals_set(false)
364 {
365 }
366
367 LoadedLibAIX::~LoadedLibAIX()
368 {
369 }
370
371 void LoadedLibAIX::setReals()
372 {
373    if (reals_set)
374       return;
375
376    Symtab *sym = getSymtab();
377    if (!sym)
378       return;
379    
380    imageOffset = sym->imageOffset();
381    dataOffset = sym->dataOffset();
382    
383    if (imageOffset > load_addr)
384       real_codeBase = 0;
385    else {
386       real_codeBase = load_addr;
387       if (imageOffset < 0x20000000)
388          real_codeBase -= imageOffset;
389       Region *sec;
390       bool result = sym->findRegion(sec, ".text");
391       if (result && sec)
392          real_codeBase += (Address) sec->getPtrToRawData() - sym->getBaseOffset();
393    }
394
395    if (dataOffset >= data_load_addr)
396       real_dataBase = 0;
397    else if (dataOffset < 0x30000000) {
398       real_dataBase = data_load_addr - dataOffset;
399    }
400
401    reals_set = true;
402 }
403
404 Address LoadedLibAIX::offToAddress(Offset off)
405 {
406    setReals();
407    
408    Address addr = off;
409
410    if ((imageOffset < dataOffset && addr >= imageOffset && addr < dataOffset) ||
411        (imageOffset > dataOffset && addr > imageOffset))
412    {
413       return addr + real_codeBase;
414    }
415    else 
416    {
417       return addr + real_dataBase;
418    }
419 }
420
421 Address LoadedLibAIX::symToAddress(Symbol *sym)
422 {
423    setReals();
424    
425    Address symAddr = sym->getAddr();
426
427    if ((imageOffset < dataOffset && symAddr >= imageOffset && symAddr < dataOffset) ||
428        (imageOffset > dataOffset && symAddr > imageOffset))
429    {
430       return symAddr + real_codeBase;
431    }
432    else 
433    {
434       return symAddr + real_dataBase;
435    }
436 }
437
438 Offset LoadedLibAIX::addrToOffset(Address addr)
439 {
440    setReals();
441
442    if (addr >= mapped_regions[0].first && 
443        addr < mapped_regions[0].first + mapped_regions[0].second)
444       return addr - real_codeBase;
445    else
446       return addr - real_dataBase;  
447 }
448
449 Address LoadedLibAIX::getCodeLoadAddr()
450 {
451    setReals();
452    return real_codeBase;
453 }
454
455 Address LoadedLibAIX::getDataLoadAddr()
456 {
457    setReals();
458    return real_dataBase;
459 }
460
461 void LoadedLibAIX::getOutputs(string &filename, Address &code, Address &data)
462 {
463    if (object.length())
464       filename = name + ":" + object;
465    else
466       filename = name;
467    code = load_addr;
468    data = data_load_addr;
469 }
470
471 Address AddressTranslateAIX::getLibraryTrapAddrSysV()
472 {
473    return 0x0;
474 }
475
476 }
477 }