Merge branch 'master' into new-parallel-parsing
[dyninst.git] / parseAPI / src / SymtabCodeSource.C
1 /*
2  * See the dyninst/COPYRIGHT file for copyright information.
3  * 
4  * We provide the Paradyn Tools (below described as "Paradyn")
5  * on an AS IS basis, and do not warrant its validity or performance.
6  * We reserve the right to update, modify, or discontinue this
7  * software at any time.  We shall have no obligation to supply such
8  * updates or modifications or any other form of support to you.
9  * 
10  * By your use of Paradyn, you understand and agree that we (or any
11  * other person or entity with proprietary rights in Paradyn) are
12  * under no obligation to provide either maintenance services,
13  * update services, notices of latent defects, or correction of
14  * defects for Paradyn.
15  * 
16  * This library is free software; you can redistribute it and/or
17  * modify it under the terms of the GNU Lesser General Public
18  * License as published by the Free Software Foundation; either
19  * version 2.1 of the License, or (at your option) any later version.
20  * 
21  * This library is distributed in the hope that it will be useful,
22  * but WITHOUT ANY WARRANTY; without even the implied warranty of
23  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
24  * Lesser General Public License for more details.
25  * 
26  * You should have received a copy of the GNU Lesser General Public
27  * License along with this library; if not, write to the Free Software
28  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
29  */
30 #include <vector>
31 #include <map>
32
33 #include <boost/assign/list_of.hpp>
34
35 #include "common/src/stats.h"
36 #include "dyntypes.h"
37
38 #include "symtabAPI/h/Symtab.h"
39 #include "symtabAPI/h/Function.h"
40 #include "symtabAPI/h/Symbol.h"
41
42 #include "CodeSource.h"
43 #include "debug_parse.h"
44 #include "util.h"
45 #include "race-detector-annotations.h"
46
47
48 #ifdef ENABLE_RACE_DETECTION
49 #include <cilk/cilk.h>
50 #include <cilk/cilk_api.h>
51 #endif
52
53 using namespace std;
54 using namespace Dyninst;
55 using namespace Dyninst::ParseAPI;
56
57 typedef tbb::concurrent_hash_map<Address, bool> SeenMap;
58
59 static const vector<std::string> skipped_symbols = {
60           "_non_rtti_object::`vftable'",
61           "bad_cast::`vftable'",
62           "exception::`vftable'",
63           "bad_typeid::`vftable'" ,
64           "sys_errlist",
65           "std::_non_rtti_object::`vftable'",
66           "std::__non_rtti_object::`vftable'",
67           "std::bad_cast::`vftable'",
68           "std::exception::`vftable'",
69           "std::bad_typeid::`vftable'" };
70
71
72 /** SymtabCodeRegion **/
73
74 SymtabCodeRegion::~SymtabCodeRegion()
75 {
76
77 }
78
79 SymtabCodeRegion::SymtabCodeRegion(
80         SymtabAPI::Symtab * st,
81         SymtabAPI::Region * reg) :
82     _symtab(st),
83     _region(reg)
84 {
85     vector<SymtabAPI::Symbol*> symbols;
86     st->getAllSymbols(symbols);
87     for (auto sit = symbols.begin(); sit != symbols.end(); ++sit)
88         if ( (*sit)->getRegion() == reg && (*sit)->getType() != SymtabAPI::Symbol::ST_FUNCTION && (*sit)->getType() != SymtabAPI::Symbol::ST_INDIRECT) {
89             knownData[(*sit)->getOffset()] = (*sit)->getOffset() + (*sit)->getSize();
90         }
91 }
92
93
94 SymtabCodeRegion::SymtabCodeRegion(
95         SymtabAPI::Symtab * st,
96         SymtabAPI::Region * reg,
97         vector<SymtabAPI::Symbol*> &symbols) :
98     _symtab(st),
99     _region(reg)
100 {
101     for (auto sit = symbols.begin(); sit != symbols.end(); ++sit)
102         if ( (*sit)->getRegion() == reg && (*sit)->getType() != SymtabAPI::Symbol::ST_FUNCTION && (*sit)->getType() != SymtabAPI::Symbol::ST_INDIRECT) {
103             knownData[(*sit)->getOffset()] = (*sit)->getOffset() + (*sit)->getSize();
104         }
105 }
106
107 void
108 SymtabCodeRegion::names(Address entry, vector<string> & names)
109 {
110     // FIXME SymtabAPI currently doesn't handle ambiguous
111     //       functions at the same linear address within
112     //       two address spaces. That error is reflected
113     //       here.
114     SymtabAPI::Function * f = NULL;
115     bool found = _symtab->findFuncByEntryOffset(f,entry);
116     if(found) {
117         // just pretty names?
118         names.insert(names.begin(),f->pretty_names_begin(),
119                      f->pretty_names_end());
120     }
121         else {
122                 cerr << "\t Failed to find name" << endl;
123         }
124 }
125
126 bool
127 SymtabCodeRegion::findCatchBlock(Address addr, Address & catchStart)
128 {
129     if(!contains(addr)) return false;
130
131     // FIXME SymtabAPI doesn't handle per-region catch block
132     //       lookups either, so faking it for now.
133     SymtabAPI::ExceptionBlock e;
134     if(_symtab->findCatchBlock(e,addr)) {
135         catchStart = e.catchStart();
136         return true;
137     }
138     return false;
139 }
140
141 bool
142 SymtabCodeRegion::isValidAddress(const Address addr) const
143 {
144     if(!contains(addr)) return false;
145
146     return isAligned(addr) && (isCode(addr) || isData(addr));
147 }
148
149 void *
150 SymtabCodeRegion::getPtrToInstruction(const Address addr) const
151 {
152     if(!contains(addr)) return NULL;
153
154     return (void*)((Address)_region->getPtrToRawData() +
155                    addr - _region->getMemOffset());
156 }
157
158 void *
159 SymtabCodeRegion::getPtrToData(const Address addr) const
160 {
161     if(!contains(addr)) return NULL;
162
163     return (void*)((Address)_region->getPtrToRawData() +
164                     addr - _region->getMemOffset());
165 }
166
167 unsigned int
168 SymtabCodeRegion::getAddressWidth() const
169 {
170     return _symtab->getAddressWidth();
171 }
172
173 Architecture
174 SymtabCodeRegion::getArch() const
175 {
176     return _symtab->getArchitecture();
177 }
178
179 bool
180 SymtabCodeRegion::isCode(const Address addr) const
181 {
182     if(!contains(addr)) return false;
183     map<Address, Address>::const_iterator dit = knownData.upper_bound(addr);
184     if (dit != knownData.begin()) {
185         --dit;
186         if (dit->first <= addr && dit->second > addr) return false;
187     }
188     // XXX this is the predicate from Symtab::isCode(a) +
189     //     the condition by which Symtab::codeRegions_ is filled
190     return !_region->isBSS() && 
191            (_region->getRegionType() == SymtabAPI::Region::RT_TEXT ||
192             _region->getRegionType() == SymtabAPI::Region::RT_TEXTDATA ||
193             (_symtab->isDefensiveBinary() && _region->isLoadable()) );
194 }
195
196 bool
197 SymtabCodeRegion::isData(const Address addr) const
198 {
199     if(!contains(addr)) return false;
200
201     // XXX Symtab::isData(a) tests both RT_DATA (Region::isData(a))
202     //     and RT_TEXTDATA. Mimicking that behavior
203     return _region->isData() || 
204            _region->getRegionType()==SymtabAPI::Region::RT_TEXTDATA;
205 }
206
207 bool
208 SymtabCodeRegion::isReadOnly(const Address addr) const
209 {
210     if(!contains(addr)) return false;
211     if (_region->getRegionName() == ".data.rel.ro") return true;
212 //    parsing_printf("Region name %s, permission %d\n", _region->getRegionName().c_str(), _region->getRegionPermissions());
213     return _region->getRegionPermissions() == SymtabAPI::Region::RP_R ||
214            _region->getRegionPermissions() == SymtabAPI::Region::RP_RX;
215 }
216
217 Address
218 SymtabCodeRegion::offset() const
219 {
220     return _region->getMemOffset();
221 }
222
223 Address
224 SymtabCodeRegion::length() const
225 {
226     return _region->getDiskSize();
227 }
228
229 /** SymtabCodeSource **/
230
231 SymtabCodeSource::~SymtabCodeSource()
232 {
233     _have_stats = false;
234     delete stats_parse;
235     if(owns_symtab && _symtab)
236         SymtabAPI::Symtab::closeSymtab(_symtab);
237     for(unsigned i=0;i<_regions.size();++i)
238         delete _regions[i];
239 }
240
241 SymtabCodeSource::SymtabCodeSource(SymtabAPI::Symtab * st, 
242                                    hint_filt * filt,
243                                    bool allLoadedRegions) : 
244     _symtab(st),
245     owns_symtab(false),
246     _lookup_cache(NULL),
247     stats_parse(new ::StatContainer()),
248     _have_stats(false)
249 {
250     init_stats();
251     init(filt,allLoadedRegions);
252 }
253
254 SymtabCodeSource::SymtabCodeSource(SymtabAPI::Symtab * st) : 
255     _symtab(st),
256     owns_symtab(false),
257     _lookup_cache(NULL),
258     stats_parse(new ::StatContainer()),
259     _have_stats(false)
260 {
261     init_stats();
262     init(NULL,false);
263 }
264
265 SymtabCodeSource::SymtabCodeSource(char * file) :
266     _symtab(NULL),
267     owns_symtab(true),
268     _lookup_cache(NULL),
269     stats_parse(new ::StatContainer()),
270     _have_stats(false)
271 {
272     init_stats();
273     
274     bool valid;
275
276     valid = SymtabAPI::Symtab::openFile(_symtab,file);
277     if(!valid) {
278         fprintf(stderr,"[%s] FATAL: can't create Symtab object for file %s\n",
279             FILE__,file);
280         _symtab = NULL;
281         return;
282     }
283     init(NULL,false);
284 }
285
286 bool
287 SymtabCodeSource::init_stats() {
288     if ((getenv("DYNINST_STATS_PARSING"))) {
289         parsing_printf("[%s] Enabling ParseAPI parsing statistics\n", FILE__);
290         // General counts
291         stats_parse->add(PARSE_BLOCK_COUNT, CountStat);
292         stats_parse->add(PARSE_FUNCTION_COUNT, CountStat);
293         
294         // Basic block size information
295         stats_parse->add(PARSE_BLOCK_SIZE, CountStat);
296
297         // Function return status counts
298         stats_parse->add(PARSE_NORETURN_COUNT, CountStat);
299         stats_parse->add(PARSE_RETURN_COUNT, CountStat);
300         stats_parse->add(PARSE_UNKNOWN_COUNT, CountStat);
301         stats_parse->add(PARSE_NORETURN_HEURISTIC, CountStat);
302
303         // Heuristic information
304         stats_parse->add(PARSE_JUMPTABLE_COUNT, CountStat);
305         stats_parse->add(PARSE_JUMPTABLE_FAIL, CountStat);
306         stats_parse->add(PARSE_TAILCALL_COUNT, CountStat);
307         stats_parse->add(PARSE_TAILCALL_FAIL, CountStat);
308
309         stats_parse->add(PARSE_JUMPTABLE_TIME, TimerStat);
310         stats_parse->add(PARSE_TOTAL_TIME, TimerStat);
311
312
313         _have_stats = true;
314     }
315
316     return _have_stats;
317 }
318
319 void
320 SymtabCodeSource::print_stats() const {
321     
322     if (_have_stats) {
323         fprintf(stderr, "[%s] Printing ParseAPI statistics\n", FILE__);
324         fprintf(stderr, "\t Basic Stats:\n");
325         fprintf(stderr, "\t\t Block Count: %ld\n", (*stats_parse)[PARSE_BLOCK_COUNT]->value());
326         fprintf(stderr, "\t\t Function Count: %ld\n", (*stats_parse)[PARSE_FUNCTION_COUNT]->value());
327         
328         long int blockSize = (*stats_parse)[PARSE_BLOCK_SIZE]->value();
329         if (blockSize) {
330             fprintf(stderr, "\t Basic Block Stats:\n");
331             fprintf(stderr, "\t\t Sum of block sizes (in bytes): %ld\n", blockSize);
332             fprintf(stderr, "\t\t Average block size (in bytes): %lf\n", (double)blockSize/(double)(*stats_parse)[PARSE_BLOCK_COUNT]->value());
333             fprintf(stderr, "\t\t Average blocks per function: %lf\n", 
334                     (double)(*stats_parse)[PARSE_BLOCK_COUNT]->value()/(double)(*stats_parse)[PARSE_FUNCTION_COUNT]->value());
335         } 
336         fprintf(stderr, "\t Function Return Status Stats:\n");
337         fprintf(stderr, "\t\t NORETURN Count: %ld", (*stats_parse)[PARSE_NORETURN_COUNT]->value());
338         long int noretHeuristicCount = (*stats_parse)[PARSE_NORETURN_HEURISTIC]->value();
339         if (noretHeuristicCount) {
340             fprintf(stderr, " (Labled based on heuristic: %ld)", noretHeuristicCount);
341         }
342         fprintf(stderr, "\n");
343         fprintf(stderr, "\t\t RETURN Count: %ld\n", (*stats_parse)[PARSE_RETURN_COUNT]->value());
344         fprintf(stderr, "\t\t UNKNOWN Count: %ld\n", (*stats_parse)[PARSE_UNKNOWN_COUNT]->value());
345
346         fprintf(stderr, "\t Heuristic Stats:\n");
347         fprintf(stderr, "\t\t parseJumpTable attempts: %ld\n", (*stats_parse)[PARSE_JUMPTABLE_COUNT]->value());
348         fprintf(stderr, "\t\t parseJumpTable failures: %ld\n", (*stats_parse)[PARSE_JUMPTABLE_FAIL]->value());
349         fprintf(stderr, "\t\t isTailCall attempts: %ld\n", (*stats_parse)[PARSE_TAILCALL_COUNT]->value());
350         fprintf(stderr, "\t\t isTailCall failures: %ld\n", (*stats_parse)[PARSE_TAILCALL_FAIL]->value());
351
352         fprintf(stderr, "\t Parsing total time: %.2lf\n", (*stats_parse)[PARSE_TOTAL_TIME]->usecs());
353         fprintf(stderr, "\t Parsing jump table time: %.2lf\n", (*stats_parse)[PARSE_JUMPTABLE_TIME]->usecs());
354
355     }
356 }
357
358 void
359 SymtabCodeSource::incrementCounter(const std::string& name) const
360 {
361     if (_have_stats) {
362         stats_parse->incrementCounter(name);
363     }
364 }
365
366 void 
367 SymtabCodeSource::addCounter(const std::string& name, int num) const
368 {
369     if (_have_stats) {
370         stats_parse->addCounter(name, num);
371     }
372 }
373
374 void
375 SymtabCodeSource::decrementCounter(const std::string& name) const
376 {
377     if (_have_stats) {
378         stats_parse->decrementCounter(name);
379     }
380 }
381
382 void
383 SymtabCodeSource::startTimer(const std::string & name) const
384 {
385     if (_have_stats) {
386         stats_parse->startTimer(name);
387     }
388 }
389
390 void
391 SymtabCodeSource::stopTimer(const std::string & name) const
392 {
393     if (_have_stats) {
394         stats_parse->stopTimer(name);
395     }
396 }
397
398 void
399 SymtabCodeSource::init(hint_filt * filt , bool allLoadedRegions)
400 {
401     // regions (and hints)
402     init_regions(filt, allLoadedRegions);
403
404     // external linkage
405     init_linkage();
406
407     // Fetch and sort exception blocks
408     init_try_blocks();
409
410     // table of contents (only exists for some binary types)
411     _table_of_contents = _symtab->getTOCoffset();
412 }
413
414 void 
415 SymtabCodeSource::init_regions(hint_filt * filt , bool allLoadedRegions)
416 {
417     RegionMap rmap;
418     vector<SymtabAPI::Region *> regs;
419     vector<SymtabAPI::Region *> dregs;
420     vector<SymtabAPI::Symbol*> symbols;
421     mcs_lock_t reg_lock;
422
423     mcs_init(reg_lock);
424
425     if ( ! allLoadedRegions ) {
426         _symtab->getCodeRegions(regs);
427         _symtab->getDataRegions(dregs);
428         regs.insert(regs.end(),dregs.begin(),dregs.end());
429     }
430     else {
431         _symtab->getMappedRegions(regs);
432     }
433
434     parsing_printf("[%s:%d] processing %d symtab regions in %s\n",
435         FILE__,__LINE__,regs.size(),_symtab->name().c_str());
436
437     _symtab->getAllSymbols(symbols);
438
439 #ifdef ENABLE_RACE_DETECTION
440     cilk_for
441 #else
442 #pragma omp parallel for shared(regs,dregs,symbols,reg_lock) schedule(auto)
443     for
444 #endif
445         (unsigned int i = 0; i < regs.size(); i++) {
446         SymtabAPI::Region *r = regs[i];
447         parsing_printf("   %lx %s",r->getMemOffset(),
448             r->getRegionName().c_str());
449     
450         // XXX only TEXT, DATA, TEXTDATA?
451         SymtabAPI::Region::RegionType rt = r->getRegionType();
452         if(false == allLoadedRegions &&
453            rt != SymtabAPI::Region::RT_TEXT &&
454            rt != SymtabAPI::Region::RT_DATA &&
455            rt != SymtabAPI::Region::RT_TEXTDATA)
456         {
457             parsing_printf(" [skipped]\n");
458             continue;
459         }
460
461         //#if defined(os_vxworks)
462         if(0 == r->getMemSize()) {
463             parsing_printf(" [skipped null region]\n");
464             continue;
465         }
466         //#endif
467         parsing_printf("\n");
468
469         CodeRegion * cr = new SymtabCodeRegion(_symtab,r, symbols);
470         bool already_present = false;
471
472         race_detector_fake_lock_acquire(race_detector_fake_lock(rmap));
473         {
474           RegionMap::accessor a;
475           already_present = rmap.insert(a, std::make_pair(r, cr));
476         }
477         race_detector_fake_lock_release(race_detector_fake_lock(rmap));
478
479         if (already_present) {
480             parsing_printf("[%s:%d] duplicate region at address %lx\n",
481                 FILE__,__LINE__,r->getMemOffset());
482         }
483         mcs_node_t me;
484         mcs_lock(reg_lock, me);
485         addRegion(cr);
486         mcs_unlock(reg_lock, me);
487     }
488
489     // Hints are initialized at the SCS level rather than the SCR level
490     // because there is currently no per-Region lookup of functions in
491     // SymtabAPI.
492     init_hints(rmap,filt);
493 }
494
495 void
496 SymtabCodeSource::init_hints(RegionMap &rmap, hint_filt * filt)
497 {
498     vector<SymtabAPI::Function *> fsyms;
499     SeenMap seen;
500     int dupes = 0;
501
502     if(!_symtab->getAllFunctions(fsyms))
503         return;
504
505     parsing_printf("[%s:%d] processing %d symtab hints\n",FILE__,__LINE__,
506         fsyms.size());
507
508     for (unsigned int i = 0; i < fsyms.size(); i++) {
509         SymtabAPI::Function *f = fsyms[i];
510         string fname_s = f->getFirstSymbol()->getPrettyName();
511         const char *fname = fname_s.c_str();
512         if(filt && (*filt)(f)) {
513             parsing_printf("[%s:%d}  == filtered hint %s [%lx] ==\n",
514                 FILE__,__LINE__,fname, f->getOffset());
515             continue;
516         }
517
518         // Cleaned-up version of a rather ugly series of strcmp's. Is this the
519         // right place to do this? Should these symbols not be filtered by the
520         // loop above?
521         /*Achin added code starts 12/15/2014*/
522         if (std::find(skipped_symbols.begin(), skipped_symbols.end(),
523           fsyms[i]->getFirstSymbol()->getPrettyName()) != skipped_symbols.end()) {
524           continue;
525         }
526         /*Achin added code ends*/
527
528         bool present = false;
529         {
530           SeenMap::accessor a;
531           Offset offset = f->getOffset();
532           present = seen.find(a, offset);
533           if (!present) seen.insert(a, std::make_pair(offset, true));
534         }
535
536         if (present) {
537             // XXX it looks as though symtabapi now does de-duplication
538             //     of function symbols automatically, so this code should
539             //     never be reached, except in the case of overlapping
540             //     regions
541            parsing_printf("[%s:%d] duplicate function at address %lx: %s\n",
542                 FILE__,__LINE__, f->getOffset(), fname);
543             ++dupes;
544         }
545
546         SymtabAPI::Region * sr = f->getRegion();
547         if (!sr) {
548             parsing_printf("[%s:%d] missing Region in function at %lx\n",
549                 FILE__,__LINE__,f->getOffset());
550             continue;
551         }
552
553         CodeRegion * cr = NULL;
554
555         {
556           RegionMap::accessor a;
557           present = rmap.find(a, sr);
558           if (present) cr = a->second;
559         }
560
561         if (!present) {
562             parsing_printf("[%s:%d] unrecognized Region %lx in function %lx\n",
563                 FILE__,__LINE__,sr->getMemOffset(),f->getOffset());
564             continue;
565         }
566
567         if(!cr->isCode(f->getOffset())) {
568             parsing_printf("\t<%lx> skipped non-code, region [%lx,%lx)\n",
569                            f->getOffset(),
570                            sr->getMemOffset(),
571                            sr->getMemOffset()+sr->getDiskSize());
572         } else {
573           _hints.push_back(Hint(f->getOffset(), f->getSize(), cr, fname_s));
574           parsing_printf("\t<%lx,%s,[%lx,%lx)>\n",
575                          f->getOffset(),
576                          fname,
577                          cr->offset(),
578                          cr->offset()+cr->length());
579         }
580     }
581     sort(_hints.begin(), _hints.end());
582 }
583
584 void
585 SymtabCodeSource::init_linkage()
586 {
587     vector<SymtabAPI::relocationEntry> fbt;
588     vector<SymtabAPI::relocationEntry>::iterator fbtit;
589
590     if(!_symtab->getFuncBindingTable(fbt)){
591         fprintf( stderr, "Cannot get function binding table. %s\n", _symtab->file().c_str());
592         return;
593     }
594
595     for(fbtit = fbt.begin(); fbtit != fbt.end(); ++fbtit){
596         //fprintf( stderr, "%lx %s\n", (*fbtit).target_addr(), (*fbtit).name().c_str());
597         _linkage[(*fbtit).target_addr()] = (*fbtit).name(); 
598     }
599 }
600
601 void
602 SymtabCodeSource::init_try_blocks()
603 {
604     vector<SymtabAPI::ExceptionBlock *> exBlks;
605     _symtab->getAllExceptions(exBlks);
606     for (auto bit = exBlks.begin(); bit != exBlks.end(); ++bit) {
607         SymtabAPI::ExceptionBlock* b = *bit;
608         try_blocks.push_back(try_block(b->tryStart(), b->tryEnd(), b->catchStart()));
609     }
610     sort(try_blocks.begin(), try_blocks.end());
611     for (size_t i = 1; i < try_blocks.size(); ++i) {
612         if (try_blocks[i].tryStart < try_blocks[i-1].tryEnd) {
613             assert(!"WARNING: overlapping try blocks\n");
614         }
615     }
616 }
617
618 bool
619 SymtabCodeSource::nonReturning(Address addr)
620 {
621     SymtabAPI::Function * f = NULL;
622    
623     _symtab->findFuncByEntryOffset(f,addr); 
624
625     if(f) {
626       for(auto i = f->mangled_names_begin();
627           i != f->mangled_names_end();
628           ++i)
629       {
630         if(CodeSource::nonReturning(*i)) return true;
631       }
632     }
633     return false;
634 }
635
636 bool
637 SymtabCodeSource::nonReturningSyscall(int num)
638 {
639   parsing_printf("Checking non-returning (Symtab) for %d\n", num);
640   Architecture arch = getArch();
641   switch(arch) {
642     case(Arch_x86):
643       return non_returning_syscalls_x86.find(num) != non_returning_syscalls_x86.end();
644     case(Arch_x86_64):
645       return non_returning_syscalls_x86_64.find(num) != non_returning_syscalls_x86_64.end();
646     default:
647       return false;
648   }
649 }
650
651 Address
652 SymtabCodeSource::baseAddress() const
653 {
654     return _symtab->getBaseOffset();
655 }
656
657 Address
658 SymtabCodeSource::loadAddress() const
659 {
660     return _symtab->getLoadOffset();
661 }
662
663 Address
664 SymtabCodeSource::getTOC(Address addr) const
665 {
666     SymtabAPI::Function *func;
667
668     if (_symtab->getContainingFunction(addr, func)) {
669         return func->getTOCOffset();
670     }
671     return _table_of_contents;
672 }
673
674 inline CodeRegion *
675 SymtabCodeSource::lookup_region(const Address addr) const
676 {
677     CodeRegion * ret = NULL;
678     race_detector_fake_lock_acquire(race_detector_fake_lock(_lookup_cache));
679     CodeRegion * cache = _lookup_cache.load();
680     race_detector_fake_lock_release(race_detector_fake_lock(_lookup_cache));
681     if(cache && cache->contains(addr))
682         ret = cache;
683     else {
684         set<CodeRegion *> stab;
685         int rcnt = findRegions(addr,stab);
686     
687         assert(rcnt <= 1 || regionsOverlap());
688
689         if(rcnt) {
690           ret = *stab.begin();
691           race_detector_fake_lock_acquire(race_detector_fake_lock(_lookup_cache));
692           _lookup_cache.store(ret);
693           race_detector_fake_lock_release(race_detector_fake_lock(_lookup_cache));
694         } 
695     }
696     return ret;
697 }
698
699 inline void 
700 SymtabCodeSource::overlapping_warn(const char * file, unsigned line) const
701 {
702     
703     if(regionsOverlap()) {
704         parsing_printf("Invocation of routine at %s:%d is ambiguous for "
705                        "binaries with overlapping code regions\n",
706             file,line);
707     }
708 }
709
710 bool
711 SymtabCodeSource::isValidAddress(const Address addr) const
712 {
713     overlapping_warn(FILE__,__LINE__);
714
715     CodeRegion * cr = lookup_region(addr);
716     if(cr)
717         return cr->isValidAddress(addr);
718     else
719         return false;
720 }
721
722 void *
723 SymtabCodeSource::getPtrToInstruction(const Address addr) const
724 {
725     overlapping_warn(FILE__,__LINE__);
726
727     CodeRegion * cr = lookup_region(addr);
728     if(cr)
729         return cr->getPtrToInstruction(addr);
730     else
731         return NULL;
732 }
733
734 void *
735 SymtabCodeSource::getPtrToData(const Address addr) const
736 {
737     overlapping_warn(FILE__,__LINE__);
738
739     CodeRegion * cr = lookup_region(addr);
740     if(cr)
741         return cr->getPtrToData(addr);
742     else
743         return NULL;
744 }
745
746 unsigned int
747 SymtabCodeSource::getAddressWidth() const
748 {
749     return _symtab->getAddressWidth();
750 }
751
752 Architecture
753 SymtabCodeSource::getArch() const
754 {
755     return _symtab->getArchitecture();
756 }
757
758 bool
759 SymtabCodeSource::isCode(const Address addr) const
760 {
761     overlapping_warn(FILE__,__LINE__);
762
763     CodeRegion * cr = lookup_region(addr);
764
765     if(cr)
766         return cr->isCode(addr);
767     else
768         return false;
769 }
770
771 bool
772 SymtabCodeSource::isData(const Address addr) const
773 {
774     overlapping_warn(FILE__,__LINE__);
775
776     CodeRegion * cr = lookup_region(addr);
777     if(cr)
778         return cr->isData(addr);
779     else
780         return false;
781 }
782
783 bool
784 SymtabCodeSource::isReadOnly(const Address addr) const
785 {
786     overlapping_warn(FILE__,__LINE__);
787
788     CodeRegion * cr = lookup_region(addr);
789     if(cr)
790         return cr->isReadOnly(addr);
791     else
792         return false;
793 }
794
795
796 Address
797 SymtabCodeSource::offset() const
798 {
799     return _symtab->imageOffset();
800 }
801
802 Address
803 SymtabCodeSource::length() const
804 {
805     return _symtab->imageLength();
806 }
807
808
809 void 
810 SymtabCodeSource::removeRegion(CodeRegion &cr)
811 {
812     _region_tree.remove( &cr );
813
814     for (vector<CodeRegion*>::iterator rit = _regions.begin(); 
815          rit != _regions.end(); rit++) 
816     {
817         if ( &cr == *rit ) {
818             _regions.erase( rit );
819             break;
820         }
821     }
822 }
823
824 // fails and returns false if it can't find a CodeRegion
825 // to match the SymtabAPI::region
826 // has to remove the region before modifying the region's size, 
827 // otherwise the region can't be found
828 bool
829 SymtabCodeSource::resizeRegion(SymtabAPI::Region *sr, Address newDiskSize)
830 {
831     // find region
832     std::set<CodeRegion*> regions;
833     findRegions(sr->getMemOffset(), regions);
834     bool found_it = false;
835     set<CodeRegion*>::iterator rit = regions.begin();
836     for (; rit != regions.end(); rit++) {
837         if (sr == ((SymtabCodeRegion*)(*rit))->symRegion()) {
838             found_it = true;
839             break;
840         }
841     }
842
843     if (!found_it) {
844         return false;
845     }
846
847     // remove, resize, reinsert
848     removeRegion( **rit );
849     sr->setDiskSize( newDiskSize );
850     addRegion( *rit );
851     return true;
852 }
853
854 void
855 SymtabCodeSource::addNonReturning(std::string func_name)
856 {
857     non_returning_funcs[func_name] = true;
858 }
859
860 bool 
861 SymtabCodeSource::findCatchBlockByTryRange(Address addr, std::set<Address> & catchStarts) const {
862     try_block target(addr, 0, 0);
863     catchStarts.clear();
864     std::vector<try_block>::const_iterator bit = upper_bound(try_blocks.begin(), try_blocks.end(), target);
865     if (bit == try_blocks.begin()) return false;
866     --bit;
867     if (bit->tryStart <= addr && addr < bit->tryEnd)
868         catchStarts.insert(bit->catchStart); 
869     return true;
870 }
871