Determine the architecture of an ELF by looking at the file header instead of the...
[dyninst.git] / parseAPI / src / SymLiteCodeSource.C
1 /*
2  * Copyright (c) 1996-2011 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 #include <vector>
32 #include <map>
33
34 #include <boost/assign/list_of.hpp>
35
36 #include "common/src/stats.h"
37 #include "dyntypes.h"
38
39 #include "common/h/SymReader.h"
40
41 #include "SymLiteCodeSource.h"
42 #include "debug_parse.h"
43 #include "util.h"
44
45 #include "symlite/h/SymLite-elf.h"
46
47 using namespace std;
48 using namespace Dyninst;
49 using namespace Dyninst::ParseAPI;
50
51 /** SymReaderCodeRegion **/
52
53 SymbolReaderFactory* getSymReaderFactory()
54 {
55   static SymbolReaderFactory* se(NULL);
56   if(se == NULL) se = new SymElfFactory();
57   return se;
58 }
59
60
61 SymReaderCodeRegion::~SymReaderCodeRegion()
62 {
63   if(rawData && (rawData != MAP_FAILED))
64     munmap(rawData, _region->mem_size);
65
66 }
67
68 SymReaderCodeRegion::SymReaderCodeRegion(
69         SymReader * st,
70         SymSegment * reg) :
71     _symtab(st),
72     _region(reg),
73     rawData(NULL)
74 {
75   rawData = mmap(NULL, _region->mem_size, PROT_READ,
76                  MAP_PRIVATE, _symtab->getFD(), _region->file_offset);
77   if(rawData == MAP_FAILED)
78   {
79     rawData = NULL;
80   }
81 }
82
83 void
84 SymReaderCodeRegion::names(Address entry, vector<string> & names)
85 {
86   Symbol_t func = _symtab->getContainingSymbol(entry);
87   std::string mangledName, prettyName;
88   mangledName = _symtab->getSymbolName(func);
89   prettyName = _symtab->getDemangledName(func);
90   if(!mangledName.empty()) names.push_back(mangledName);
91   if(!prettyName.empty()) names.push_back(prettyName);
92 }
93
94 bool
95 SymReaderCodeRegion::findCatchBlock(Address, Address &)
96 {
97   // SymLite doesn't support catch blocks at all.
98   return false;
99 }
100
101 bool
102 SymReaderCodeRegion::isValidAddress(const Address addr) const
103 {
104     if(!contains(addr)) return false;
105
106     return isAligned(addr) && (isCode(addr) || isData(addr));
107 }
108
109 void *
110 SymReaderCodeRegion::getPtrToInstruction(const Address addr) const
111 {
112     if(!contains(addr)) return NULL;
113
114     if(isCode(addr))
115         return (void*)((Address)rawData + 
116                        addr - _region->mem_addr);
117     else if(isData(addr))
118         return getPtrToData(addr);
119     else
120         return NULL;
121 }
122
123 void *
124 SymReaderCodeRegion::getPtrToData(const Address addr) const
125 {
126     if(!contains(addr)) return NULL;
127
128     if(isData(addr))
129         return (void*)((Address)rawData +
130                         addr - _region->mem_addr);
131     else
132         return NULL;
133 }
134
135 unsigned int
136 SymReaderCodeRegion::getAddressWidth() const
137 {
138     return _symtab->getAddressWidth();
139 }
140
141 Architecture
142 SymReaderCodeRegion::getArch() const
143 {
144     return _symtab->getArchitecture();
145 }
146
147 bool
148 SymReaderCodeRegion::isCode(const Address addr) const
149 {
150     if(!contains(addr)) return false;
151     return true;
152     
153     /*
154     // XXX this is the predicate from SymReader::isCode(a) +
155     //     the condition by which SymReader::codeRegions_ is filled
156     return !_region->isBSS() && 
157            (_region->type == SymSegment::RT_TEXT ||
158             _region->type == SymSegment::RT_TEXTDATA);
159     */
160 }
161
162 bool
163 SymReaderCodeRegion::isData(const Address addr) const
164 {
165     if(!contains(addr)) return false;
166     return true;
167     
168
169     /*
170     // XXX SymReader::isData(a) tests both RT_DATA (Region::isData(a))
171     //     and RT_TEXTDATA. Mimicking that behavior
172     return _region->isData() || 
173            _region->type==SymSegment::RT_TEXTDATA;
174     */
175 }
176
177 Address
178 SymReaderCodeRegion::offset() const
179 {
180     return _region->mem_addr;
181 }
182
183 Address
184 SymReaderCodeRegion::length() const
185 {
186     return _region->file_size;
187 }
188
189 /** SymReaderCodeSource **/
190
191 SymReaderCodeSource::~SymReaderCodeSource()
192 {
193     _have_stats = false;
194     free(stats_parse);
195     if(owns_symtab && _symtab)
196       getSymReaderFactory()->closeSymbolReader(_symtab);
197     for(unsigned i=0;i<_regions.size();++i)
198         delete _regions[i];
199 }
200
201 SymReaderCodeSource::SymReaderCodeSource(SymReader * st) : 
202     _symtab(st),
203     owns_symtab(false),
204     _lookup_cache(NULL),
205     stats_parse(new ::StatContainer()),
206     _have_stats(false)
207 {
208   init_regions();
209   init_stats();
210 }
211
212 bool shouldAddRegion(SymSegment* sr)
213 {
214   // First: text, data, or textdata only
215   switch(sr->type)
216   {
217   case SHT_PROGBITS: return true;
218   default: return false;
219   }
220   // Second: memsize > 0
221   return sr->mem_size > 0;
222 }
223
224
225 void SymReaderCodeSource::init_regions()
226 {
227   for(unsigned i = 0; i < _symtab->numSegments(); i++)
228   {
229     SymSegment reg;
230     
231     if(_symtab->getSegment(i, reg))
232     {
233       SymSegment* tmp = new SymSegment(reg);
234       
235       CodeRegion* cr = new SymReaderCodeRegion(_symtab, tmp);
236       if(shouldAddRegion(tmp)) 
237       {
238         addRegion(cr);
239       }
240       else
241       {
242         delete cr;
243       }
244     }
245     
246   }
247 }
248
249
250 SymReaderCodeSource::SymReaderCodeSource(const char * file) :
251     _symtab(NULL),
252     owns_symtab(true),
253     _lookup_cache(NULL),
254     stats_parse(new ::StatContainer()),
255     _have_stats(false)
256 {
257   
258   _symtab = getSymReaderFactory()->openSymbolReader(file);
259   if(!_symtab) {
260     fprintf(stderr,"[%s] FATAL: can't create SymReader object for file %s\n",
261             FILE__,file);
262     return;
263   }
264   init_stats();
265   init_regions();
266   
267 }
268
269 bool
270 SymReaderCodeSource::init_stats() {
271     if (getenv("DYNINST_STATS_PARSING")) {
272         parsing_printf("[%s] Enabling ParseAPI parsing statistics\n", FILE__);
273         // General counts
274         stats_parse->add(PARSE_BLOCK_COUNT, CountStat);
275         stats_parse->add(PARSE_FUNCTION_COUNT, CountStat);
276         
277         // Basic block size information
278         stats_parse->add(PARSE_BLOCK_SIZE, CountStat);
279
280         // Function return status counts
281         stats_parse->add(PARSE_NORETURN_COUNT, CountStat);
282         stats_parse->add(PARSE_RETURN_COUNT, CountStat);
283         stats_parse->add(PARSE_UNKNOWN_COUNT, CountStat);
284         stats_parse->add(PARSE_NORETURN_HEURISTIC, CountStat);
285
286         // Heuristic information
287         stats_parse->add(PARSE_JUMPTABLE_COUNT, CountStat);
288         stats_parse->add(PARSE_JUMPTABLE_FAIL, CountStat);
289         stats_parse->add(PARSE_TAILCALL_COUNT, CountStat);
290         stats_parse->add(PARSE_TAILCALL_FAIL, CountStat);
291
292         _have_stats = true;
293     }
294
295     return _have_stats;
296 }
297
298 void
299 SymReaderCodeSource::print_stats() const {
300     
301     if (_have_stats) {
302         fprintf(stderr, "[%s] Printing ParseAPI statistics\n", FILE__);
303         fprintf(stderr, "\t Basic Stats:\n");
304         fprintf(stderr, "\t\t Block Count: %ld\n", (*stats_parse)[PARSE_BLOCK_COUNT]->value());
305         fprintf(stderr, "\t\t Function Count: %ld\n", (*stats_parse)[PARSE_FUNCTION_COUNT]->value());
306         
307         long int blockSize = (*stats_parse)[PARSE_BLOCK_SIZE]->value();
308         if (blockSize) {
309             fprintf(stderr, "\t Basic Block Stats:\n");
310             fprintf(stderr, "\t\t Sum of block sizes (in bytes): %ld\n", blockSize);
311             fprintf(stderr, "\t\t Average block size (in bytes): %lf\n", (double)blockSize/(double)(*stats_parse)[PARSE_BLOCK_COUNT]->value());
312             fprintf(stderr, "\t\t Average blocks per function: %lf\n", 
313                     (double)(*stats_parse)[PARSE_BLOCK_COUNT]->value()/(double)(*stats_parse)[PARSE_FUNCTION_COUNT]->value());
314         } 
315         fprintf(stderr, "\t Function Return Status Stats:\n");
316         fprintf(stderr, "\t\t NORETURN Count: %ld", (*stats_parse)[PARSE_NORETURN_COUNT]->value());
317         long int noretHeuristicCount = (*stats_parse)[PARSE_NORETURN_HEURISTIC]->value();
318         if (noretHeuristicCount) {
319             fprintf(stderr, " (Labled based on heuristic: %ld)", noretHeuristicCount);
320         }
321         fprintf(stderr, "\n");
322         fprintf(stderr, "\t\t RETURN Count: %ld\n", (*stats_parse)[PARSE_RETURN_COUNT]->value());
323         fprintf(stderr, "\t\t UNKNOWN Count: %ld\n", (*stats_parse)[PARSE_UNKNOWN_COUNT]->value());
324
325         fprintf(stderr, "\t Heuristic Stats:\n");
326         fprintf(stderr, "\t\t parseJumpTable attempts: %ld\n", (*stats_parse)[PARSE_JUMPTABLE_COUNT]->value());
327         fprintf(stderr, "\t\t parseJumpTable failures: %ld\n", (*stats_parse)[PARSE_JUMPTABLE_FAIL]->value());
328         fprintf(stderr, "\t\t isTailCall attempts: %ld\n", (*stats_parse)[PARSE_TAILCALL_COUNT]->value());
329         fprintf(stderr, "\t\t isTailCall failures: %ld\n", (*stats_parse)[PARSE_TAILCALL_FAIL]->value());
330
331     }
332 }
333
334 void
335 SymReaderCodeSource::incrementCounter(const std::string& name) const
336 {
337     if (_have_stats) {
338         stats_parse->incrementCounter(name);
339     }
340 }
341
342 void 
343 SymReaderCodeSource::addCounter(const std::string& name, int num) const
344 {
345     if (_have_stats) {
346         stats_parse->addCounter(name, num);
347     }
348 }
349
350 void
351 SymReaderCodeSource::decrementCounter(const std::string& name) const
352 {
353     if (_have_stats) {
354         stats_parse->decrementCounter(name);
355     }
356 }
357
358 bool
359 SymReaderCodeSource::nonReturning(Address addr)
360 {
361   Symbol_t func = _symtab->getContainingSymbol(addr);
362   string func_name = _symtab->getSymbolName(func);
363   return CodeSource::nonReturning(func_name);
364 }
365
366 bool
367 SymReaderCodeSource::nonReturningSyscall(int num)
368 {
369   parsing_printf("Checking non-returning (SymLite) for %d\n", num);
370   Architecture arch = getArch();
371   switch(arch) {
372     case(Arch_x86):
373       return non_returning_syscalls_x86.find(num) != non_returning_syscalls_x86.end();
374     case(Arch_x86_64):
375       return non_returning_syscalls_x86_64.find(num) != non_returning_syscalls_x86_64.end();
376     default:
377       return false;
378   }
379 }
380
381 inline CodeRegion *
382 SymReaderCodeSource::lookup_region(const Address addr) const
383 {
384     CodeRegion * ret = NULL;
385     if(_lookup_cache && _lookup_cache->contains(addr))
386         ret = _lookup_cache;
387     else {
388         set<CodeRegion *> stab;
389         int rcnt = findRegions(addr,stab);
390     
391         assert(rcnt <= 1 || regionsOverlap());
392
393         if(rcnt) {
394             ret = *stab.begin();
395             _lookup_cache = ret;
396         } 
397     }
398     return ret;
399 }
400
401 inline void 
402 SymReaderCodeSource::overlapping_warn(const char * file, unsigned line) const
403 {
404     if(regionsOverlap()) {
405         fprintf(stderr,"Invocation of routine at %s:%d is ambiguous for "
406                        "binaries with overlapping code regions\n",
407             file,line);
408     }
409 }
410
411 bool
412 SymReaderCodeSource::isValidAddress(const Address addr) const
413 {
414     overlapping_warn(FILE__,__LINE__);
415     
416
417     CodeRegion * cr = lookup_region(addr);
418     if(cr) 
419     {
420         return cr->isValidAddress(addr);
421     }
422     else
423     {
424         return false;
425     }
426     
427 }
428
429 void *
430 SymReaderCodeSource::getPtrToInstruction(const Address addr) const
431 {
432     overlapping_warn(FILE__,__LINE__);
433
434     CodeRegion * cr = lookup_region(addr);
435     if(cr)
436         return cr->getPtrToInstruction(addr);
437     else
438         return NULL;
439 }
440
441 void *
442 SymReaderCodeSource::getPtrToData(const Address addr) const
443 {
444     overlapping_warn(FILE__,__LINE__);
445
446     CodeRegion * cr = lookup_region(addr);
447     if(cr)
448         return cr->getPtrToData(addr);
449     else
450         return NULL;
451 }
452
453 unsigned int
454 SymReaderCodeSource::getAddressWidth() const
455 {
456     return _symtab->getAddressWidth();
457 }
458
459 Architecture
460 SymReaderCodeSource::getArch() const
461 {
462     return _symtab->getArchitecture();
463 }
464
465 bool
466 SymReaderCodeSource::isCode(const Address addr) const
467 {
468     overlapping_warn(FILE__,__LINE__);
469
470     CodeRegion * cr = lookup_region(addr);
471     if(cr)
472         return cr->isCode(addr);
473     else
474         return false;
475 }
476
477 bool
478 SymReaderCodeSource::isData(const Address addr) const
479 {
480     overlapping_warn(FILE__,__LINE__);
481
482     CodeRegion * cr = lookup_region(addr);
483     if(cr)
484         return cr->isData(addr);
485     else
486         return false;
487 }
488
489 Address
490 SymReaderCodeSource::offset() const
491 {
492     return _symtab->imageOffset();
493 }
494
495 Address
496 SymReaderCodeSource::length() const
497 {
498   return 0;//_symtab->imageLength();
499 }
500
501
502 void 
503 SymReaderCodeSource::removeRegion(CodeRegion &cr)
504 {
505     _region_tree.remove( &cr );
506
507     for (vector<CodeRegion*>::iterator rit = _regions.begin(); 
508          rit != _regions.end(); rit++) 
509     {
510         if ( &cr == *rit ) {
511             _regions.erase( rit );
512             break;
513         }
514     }
515 }
516
517 // fails and returns false if it can't find a CodeRegion
518 // to match the region
519 // has to remove the region before modifying the region's size, 
520 // otherwise the region can't be found
521 bool
522 SymReaderCodeSource::resizeRegion(SymSegment *sr, Address newDiskSize)
523 {
524     // find region
525     std::set<CodeRegion*> regions;
526     findRegions(sr->mem_addr, regions);
527     bool found_it = false;
528     set<CodeRegion*>::iterator rit = regions.begin();
529     for (; rit != regions.end(); rit++) {
530         if (sr == ((SymReaderCodeRegion*)(*rit))->symRegion()) {
531             found_it = true;
532             break;
533         }
534     }
535
536     if (!found_it) {
537         return false;
538     }
539
540     // remove, resize, reinsert
541     removeRegion( **rit );
542     sr->file_size = newDiskSize;
543     addRegion( *rit );
544     return true;
545 }
546
547 void
548 SymReaderCodeSource::addNonReturning(std::string func_name)
549 {
550     non_returning_funcs[func_name] = true;
551 }
552