Rename the symbol reader getRegions to getSegments, since the desired return is an...
[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/h/stats.h"
37 #include "dyntypes.h"
38
39 #include "dynutil/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 #if defined(arch_power)
145     if(getAddressWidth() == 8)
146         return Arch_ppc64;
147     else
148         return Arch_ppc32;
149 #elif defined(arch_x86) || defined(arch_x86_64)
150     if(getAddressWidth() == 8)
151         return Arch_x86_64;
152     else
153         return Arch_x86;
154 #else
155     return Arch_none;
156 #endif
157 }
158
159 bool
160 SymReaderCodeRegion::isCode(const Address addr) const
161 {
162     if(!contains(addr)) return false;
163     return true;
164     
165     /*
166     // XXX this is the predicate from SymReader::isCode(a) +
167     //     the condition by which SymReader::codeRegions_ is filled
168     return !_region->isBSS() && 
169            (_region->type == SymSegment::RT_TEXT ||
170             _region->type == SymSegment::RT_TEXTDATA);
171     */
172 }
173
174 bool
175 SymReaderCodeRegion::isData(const Address addr) const
176 {
177     if(!contains(addr)) return false;
178     return true;
179     
180
181     /*
182     // XXX SymReader::isData(a) tests both RT_DATA (Region::isData(a))
183     //     and RT_TEXTDATA. Mimicking that behavior
184     return _region->isData() || 
185            _region->type==SymSegment::RT_TEXTDATA;
186     */
187 }
188
189 Address
190 SymReaderCodeRegion::offset() const
191 {
192     return _region->mem_addr;
193 }
194
195 Address
196 SymReaderCodeRegion::length() const
197 {
198     return _region->file_size;
199 }
200
201 /** SymReaderCodeSource **/
202
203 SymReaderCodeSource::~SymReaderCodeSource()
204 {
205     _have_stats = false;
206     free(stats_parse);
207     if(owns_symtab && _symtab)
208       getSymReaderFactory()->closeSymbolReader(_symtab);
209     for(unsigned i=0;i<_regions.size();++i)
210         delete _regions[i];
211 }
212
213 SymReaderCodeSource::SymReaderCodeSource(SymReader * st) : 
214     _symtab(st),
215     owns_symtab(false),
216     _lookup_cache(NULL),
217     stats_parse(new ::StatContainer()),
218     _have_stats(false)
219 {
220   init_regions();
221   init_stats();
222 }
223
224 bool shouldAddRegion(SymSegment* sr)
225 {
226   // First: text, data, or textdata only
227   switch(sr->type)
228   {
229   case SHT_PROGBITS: return true;
230   default: return false;
231   }
232   // Second: memsize > 0
233   return sr->mem_size > 0;
234 }
235
236
237 void SymReaderCodeSource::init_regions()
238 {
239   for(unsigned i = 0; i < _symtab->numSegments(); i++)
240   {
241     SymSegment reg;
242     
243     if(_symtab->getSegment(i, reg))
244     {
245       SymSegment* tmp = new SymSegment(reg);
246       
247       CodeRegion* cr = new SymReaderCodeRegion(_symtab, tmp);
248       if(shouldAddRegion(tmp)) 
249       {
250         addRegion(cr);
251       }
252       else
253       {
254         delete cr;
255       }
256     }
257     
258   }
259 }
260
261
262 SymReaderCodeSource::SymReaderCodeSource(const char * file) :
263     _symtab(NULL),
264     owns_symtab(true),
265     _lookup_cache(NULL),
266     stats_parse(new ::StatContainer()),
267     _have_stats(false)
268 {
269   
270   _symtab = getSymReaderFactory()->openSymbolReader(file);
271   if(!_symtab) {
272     fprintf(stderr,"[%s] FATAL: can't create SymReader object for file %s\n",
273             FILE__,file);
274     return;
275   }
276   init_stats();
277   init_regions();
278   
279 }
280
281 bool
282 SymReaderCodeSource::init_stats() {
283     char *p;
284
285     if ((p = getenv("DYNINST_STATS_PARSING"))) {
286         parsing_printf("[%s] Enabling ParseAPI parsing statistics\n", FILE__);
287         // General counts
288         stats_parse->add(PARSE_BLOCK_COUNT, CountStat);
289         stats_parse->add(PARSE_FUNCTION_COUNT, CountStat);
290         
291         // Basic block size information
292         stats_parse->add(PARSE_BLOCK_SIZE, CountStat);
293
294         // Function return status counts
295         stats_parse->add(PARSE_NORETURN_COUNT, CountStat);
296         stats_parse->add(PARSE_RETURN_COUNT, CountStat);
297         stats_parse->add(PARSE_UNKNOWN_COUNT, CountStat);
298         stats_parse->add(PARSE_NORETURN_HEURISTIC, CountStat);
299
300         // Heuristic information
301         stats_parse->add(PARSE_JUMPTABLE_COUNT, CountStat);
302         stats_parse->add(PARSE_JUMPTABLE_FAIL, CountStat);
303         stats_parse->add(PARSE_TAILCALL_COUNT, CountStat);
304         stats_parse->add(PARSE_TAILCALL_FAIL, CountStat);
305
306         _have_stats = true;
307     }
308
309     return _have_stats;
310 }
311
312 void
313 SymReaderCodeSource::print_stats() const {
314     
315     if (_have_stats) {
316         fprintf(stderr, "[%s] Printing ParseAPI statistics\n", FILE__);
317         fprintf(stderr, "\t Basic Stats:\n");
318         fprintf(stderr, "\t\t Block Count: %ld\n", (*stats_parse)[PARSE_BLOCK_COUNT]->value());
319         fprintf(stderr, "\t\t Function Count: %ld\n", (*stats_parse)[PARSE_FUNCTION_COUNT]->value());
320         
321         long int blockSize = (*stats_parse)[PARSE_BLOCK_SIZE]->value();
322         if (blockSize) {
323             fprintf(stderr, "\t Basic Block Stats:\n");
324             fprintf(stderr, "\t\t Sum of block sizes (in bytes): %ld\n", blockSize);
325             fprintf(stderr, "\t\t Average block size (in bytes): %lf\n", (double)blockSize/(double)(*stats_parse)[PARSE_BLOCK_COUNT]->value());
326             fprintf(stderr, "\t\t Average blocks per function: %lf\n", 
327                     (double)(*stats_parse)[PARSE_BLOCK_COUNT]->value()/(double)(*stats_parse)[PARSE_FUNCTION_COUNT]->value());
328         } 
329         fprintf(stderr, "\t Function Return Status Stats:\n");
330         fprintf(stderr, "\t\t NORETURN Count: %ld", (*stats_parse)[PARSE_NORETURN_COUNT]->value());
331         long int noretHeuristicCount = (*stats_parse)[PARSE_NORETURN_HEURISTIC]->value();
332         if (noretHeuristicCount) {
333             fprintf(stderr, " (Labled based on heuristic: %ld)", noretHeuristicCount);
334         }
335         fprintf(stderr, "\n");
336         fprintf(stderr, "\t\t RETURN Count: %ld\n", (*stats_parse)[PARSE_RETURN_COUNT]->value());
337         fprintf(stderr, "\t\t UNKNOWN Count: %ld\n", (*stats_parse)[PARSE_UNKNOWN_COUNT]->value());
338
339         fprintf(stderr, "\t Heuristic Stats:\n");
340         fprintf(stderr, "\t\t parseJumpTable attempts: %ld\n", (*stats_parse)[PARSE_JUMPTABLE_COUNT]->value());
341         fprintf(stderr, "\t\t parseJumpTable failures: %ld\n", (*stats_parse)[PARSE_JUMPTABLE_FAIL]->value());
342         fprintf(stderr, "\t\t isTailCall attempts: %ld\n", (*stats_parse)[PARSE_TAILCALL_COUNT]->value());
343         fprintf(stderr, "\t\t isTailCall failures: %ld\n", (*stats_parse)[PARSE_TAILCALL_FAIL]->value());
344
345     }
346 }
347
348 void
349 SymReaderCodeSource::incrementCounter(std::string name) const
350 {
351     if (_have_stats) {
352         stats_parse->incrementCounter(name);
353     }
354 }
355
356 void 
357 SymReaderCodeSource::addCounter(std::string name, int num) const
358 {
359     if (_have_stats) {
360         stats_parse->addCounter(name, num);
361     }
362 }
363
364 void
365 SymReaderCodeSource::decrementCounter(std::string name) const
366 {
367     if (_have_stats) {
368         stats_parse->decrementCounter(name);
369     }
370 }
371
372 bool
373 SymReaderCodeSource::nonReturning(Address addr)
374 {
375   Symbol_t func = _symtab->getContainingSymbol(addr);
376   string func_name = _symtab->getSymbolName(func);
377   return nonReturning(func_name);
378 }
379
380 dyn_hash_map<std::string, bool>
381 SymReaderCodeSource::non_returning_funcs =
382     boost::assign::map_list_of
383         ("exit",true)
384         ("abort",true)
385         ("__f90_stop",true)
386         ("fancy_abort",true)
387         ("__stack_chk_fail",true)
388         ("__assert_fail",true)
389         ("ExitProcess",true)
390         ("_ZSt17__throw_bad_allocv",true)
391         ("_ZSt20__throw_length_errorPKc",true)
392         ("_Unwind_Resume",true)
393         ("longjmp",true)
394         ("siglongjmp",true)
395         ("_ZSt16__throw_bad_castv",true)
396         ("_ZSt19__throw_logic_errorPKc",true)
397         ("_ZSt20__throw_out_of_rangePKc",true)
398         ("__cxa_rethrow",true)
399         ("__cxa_throw",true)
400         ("_ZSt21__throw_runtime_errorPKc",true)
401         ("_gfortran_os_error",true)
402         ("_gfortran_runtime_error",true)
403         ("_gfortran_stop_numeric", true)
404    ("for_stop_core", true);
405
406 bool
407 SymReaderCodeSource::nonReturning(string name)
408 {
409   parsing_printf("Checking non-returning (SymLite) for %s\n", name.c_str());
410     return non_returning_funcs.find(name) != non_returning_funcs.end();
411 }
412
413 inline CodeRegion *
414 SymReaderCodeSource::lookup_region(const Address addr) const
415 {
416     CodeRegion * ret = NULL;
417     if(_lookup_cache && _lookup_cache->contains(addr))
418         ret = _lookup_cache;
419     else {
420         set<CodeRegion *> stab;
421         int rcnt = findRegions(addr,stab);
422     
423         assert(rcnt <= 1 || regionsOverlap());
424
425         if(rcnt) {
426             ret = *stab.begin();
427             _lookup_cache = ret;
428         } 
429     }
430     return ret;
431 }
432
433 inline void 
434 SymReaderCodeSource::overlapping_warn(const char * file, unsigned line) const
435 {
436     if(regionsOverlap()) {
437         fprintf(stderr,"Invocation of routine at %s:%d is ambiguous for "
438                        "binaries with overlapping code regions\n",
439             file,line);
440     }
441 }
442
443 bool
444 SymReaderCodeSource::isValidAddress(const Address addr) const
445 {
446     overlapping_warn(FILE__,__LINE__);
447     
448
449     CodeRegion * cr = lookup_region(addr);
450     if(cr) 
451     {
452         return cr->isValidAddress(addr);
453     }
454     else
455     {
456         return false;
457     }
458     
459 }
460
461 void *
462 SymReaderCodeSource::getPtrToInstruction(const Address addr) const
463 {
464     overlapping_warn(FILE__,__LINE__);
465
466     CodeRegion * cr = lookup_region(addr);
467     if(cr)
468         return cr->getPtrToInstruction(addr);
469     else
470         return NULL;
471 }
472
473 void *
474 SymReaderCodeSource::getPtrToData(const Address addr) const
475 {
476     overlapping_warn(FILE__,__LINE__);
477
478     CodeRegion * cr = lookup_region(addr);
479     if(cr)
480         return cr->getPtrToData(addr);
481     else
482         return NULL;
483 }
484
485 unsigned int
486 SymReaderCodeSource::getAddressWidth() const
487 {
488     return _symtab->getAddressWidth();
489 }
490
491 Architecture
492 SymReaderCodeSource::getArch() const
493 {
494 #if defined(arch_power)
495     if(getAddressWidth() == 8)
496         return Arch_ppc64;
497     else
498         return Arch_ppc32;
499 #elif defined(arch_x86) || defined(arch_x86_64)
500     if(getAddressWidth() == 8)
501         return Arch_x86_64;
502     else
503         return Arch_x86;
504 #else
505     return Arch_none;
506 #endif
507 }
508
509 bool
510 SymReaderCodeSource::isCode(const Address addr) const
511 {
512     overlapping_warn(FILE__,__LINE__);
513
514     CodeRegion * cr = lookup_region(addr);
515     if(cr)
516         return cr->isCode(addr);
517     else
518         return false;
519 }
520
521 bool
522 SymReaderCodeSource::isData(const Address addr) const
523 {
524     overlapping_warn(FILE__,__LINE__);
525
526     CodeRegion * cr = lookup_region(addr);
527     if(cr)
528         return cr->isData(addr);
529     else
530         return false;
531 }
532
533 Address
534 SymReaderCodeSource::offset() const
535 {
536     return _symtab->imageOffset();
537 }
538
539 Address
540 SymReaderCodeSource::length() const
541 {
542   return 0;//_symtab->imageLength();
543 }
544
545
546 void 
547 SymReaderCodeSource::removeRegion(CodeRegion &cr)
548 {
549     _region_tree.remove( &cr );
550
551     for (vector<CodeRegion*>::iterator rit = _regions.begin(); 
552          rit != _regions.end(); rit++) 
553     {
554         if ( &cr == *rit ) {
555             _regions.erase( rit );
556             break;
557         }
558     }
559 }
560
561 // fails and returns false if it can't find a CodeRegion
562 // to match the region
563 // has to remove the region before modifying the region's size, 
564 // otherwise the region can't be found
565 bool
566 SymReaderCodeSource::resizeRegion(SymSegment *sr, Address newDiskSize)
567 {
568     // find region
569     std::set<CodeRegion*> regions;
570     findRegions(sr->mem_addr, regions);
571     bool found_it = false;
572     set<CodeRegion*>::iterator rit = regions.begin();
573     for (; rit != regions.end(); rit++) {
574         if (sr == ((SymReaderCodeRegion*)(*rit))->symRegion()) {
575             found_it = true;
576             break;
577         }
578     }
579
580     if (!found_it) {
581         return false;
582     }
583
584     // remove, resize, reinsert
585     removeRegion( **rit );
586     sr->file_size = newDiskSize;
587     addRegion( *rit );
588     return true;
589 }
590
591 void
592 SymReaderCodeSource::addNonReturning(std::string func_name)
593 {
594     non_returning_funcs[func_name] = true;
595 }
596