Determine the architecture of an ELF by looking at the file header instead of the...
[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
46 using namespace std;
47 using namespace Dyninst;
48 using namespace Dyninst::ParseAPI;
49
50
51 /** SymtabCodeRegion **/
52
53 SymtabCodeRegion::~SymtabCodeRegion()
54 {
55
56 }
57
58 SymtabCodeRegion::SymtabCodeRegion(
59         SymtabAPI::Symtab * st,
60         SymtabAPI::Region * reg) :
61     _symtab(st),
62     _region(reg)
63 {
64     vector<SymtabAPI::Symbol*> symbols;
65     st->getAllSymbols(symbols);
66     for (auto sit = symbols.begin(); sit != symbols.end(); ++sit)
67         if ( (*sit)->getRegion() == reg && (*sit)->getType() != SymtabAPI::Symbol::ST_FUNCTION) {
68             knownData[(*sit)->getOffset()] = (*sit)->getOffset() + (*sit)->getSize();
69         }
70 }
71
72 void
73 SymtabCodeRegion::names(Address entry, vector<string> & names)
74 {
75     // FIXME SymtabAPI currently doesn't handle ambiguous
76     //       functions at the same linear address within
77     //       two address spaces. That error is reflected
78     //       here.
79     SymtabAPI::Function * f = NULL;
80     bool found = _symtab->findFuncByEntryOffset(f,entry);
81     if(found) {
82         // just pretty names?
83         names.insert(names.begin(),f->pretty_names_begin(),
84                      f->pretty_names_end());
85     }
86         else {
87                 cerr << "\t Failed to find name" << endl;
88         }
89 }
90
91 bool
92 SymtabCodeRegion::findCatchBlock(Address addr, Address & catchStart)
93 {
94     if(!contains(addr)) return false;
95
96     // FIXME SymtabAPI doesn't handle per-region catch block
97     //       lookups either, so faking it for now.
98     SymtabAPI::ExceptionBlock e;
99     if(_symtab->findCatchBlock(e,addr)) {
100         catchStart = e.catchStart();
101         return true;
102     }
103     return false;
104 }
105
106 bool
107 SymtabCodeRegion::isValidAddress(const Address addr) const
108 {
109     if(!contains(addr)) return false;
110
111     return isAligned(addr) && (isCode(addr) || isData(addr));
112 }
113
114 void *
115 SymtabCodeRegion::getPtrToInstruction(const Address addr) const
116 {
117     if(!contains(addr)) return NULL;
118
119     if(isCode(addr))
120         return (void*)((Address)_region->getPtrToRawData() + 
121                        addr - _region->getMemOffset());
122     else if(isData(addr))
123         return getPtrToData(addr);
124     else
125         return NULL;
126 }
127
128 void *
129 SymtabCodeRegion::getPtrToData(const Address addr) const
130 {
131     if(!contains(addr)) return NULL;
132
133     if(isData(addr))
134         return (void*)((Address)_region->getPtrToRawData() +
135                         addr - _region->getMemOffset());
136     else
137         return NULL;
138 }
139
140 unsigned int
141 SymtabCodeRegion::getAddressWidth() const
142 {
143     return _symtab->getAddressWidth();
144 }
145
146 Architecture
147 SymtabCodeRegion::getArch() const
148 {
149     return _symtab->getArchitecture();
150 }
151
152 bool
153 SymtabCodeRegion::isCode(const Address addr) const
154 {
155     if(!contains(addr)) return false;
156     map<Address, Address>::const_iterator dit = knownData.upper_bound(addr);
157     if (dit != knownData.begin()) {
158         --dit;
159         if (dit->first <= addr && dit->second > addr) return false;
160     }
161     // XXX this is the predicate from Symtab::isCode(a) +
162     //     the condition by which Symtab::codeRegions_ is filled
163     return !_region->isBSS() && 
164            (_region->getRegionType() == SymtabAPI::Region::RT_TEXT ||
165             _region->getRegionType() == SymtabAPI::Region::RT_TEXTDATA ||
166             (_symtab->isDefensiveBinary() && _region->isLoadable()) );
167 }
168
169 bool
170 SymtabCodeRegion::isData(const Address addr) const
171 {
172     if(!contains(addr)) return false;
173
174     // XXX Symtab::isData(a) tests both RT_DATA (Region::isData(a))
175     //     and RT_TEXTDATA. Mimicking that behavior
176     return _region->isData() || 
177            _region->getRegionType()==SymtabAPI::Region::RT_TEXTDATA;
178 }
179
180 bool
181 SymtabCodeRegion::isReadOnly(const Address addr) const
182 {
183     if(!contains(addr)) return false;
184     if (_region->getRegionName() == ".data.rel.ro") return true;
185 //    parsing_printf("Region name %s, permission %d\n", _region->getRegionName().c_str(), _region->getRegionPermissions());
186     return _region->getRegionPermissions() == SymtabAPI::Region::RP_R ||
187            _region->getRegionPermissions() == SymtabAPI::Region::RP_RX;
188 }
189
190 Address
191 SymtabCodeRegion::offset() const
192 {
193     return _region->getMemOffset();
194 }
195
196 Address
197 SymtabCodeRegion::length() const
198 {
199     return _region->getDiskSize();
200 }
201
202 /** SymtabCodeSource **/
203
204 SymtabCodeSource::~SymtabCodeSource()
205 {
206     _have_stats = false;
207     delete stats_parse;
208     if(owns_symtab && _symtab)
209         SymtabAPI::Symtab::closeSymtab(_symtab);
210     for(unsigned i=0;i<_regions.size();++i)
211         delete _regions[i];
212 }
213
214 SymtabCodeSource::SymtabCodeSource(SymtabAPI::Symtab * st, 
215                                    hint_filt * filt,
216                                    bool allLoadedRegions) : 
217     _symtab(st),
218     owns_symtab(false),
219     _lookup_cache(NULL),
220     stats_parse(new ::StatContainer()),
221     _have_stats(false)
222 {
223     init_stats();
224     init(filt,allLoadedRegions);
225 }
226
227 SymtabCodeSource::SymtabCodeSource(SymtabAPI::Symtab * st) : 
228     _symtab(st),
229     owns_symtab(false),
230     _lookup_cache(NULL),
231     stats_parse(new ::StatContainer()),
232     _have_stats(false)
233 {
234     init_stats();
235     init(NULL,false);
236 }
237
238 SymtabCodeSource::SymtabCodeSource(char * file) :
239     _symtab(NULL),
240     owns_symtab(true),
241     _lookup_cache(NULL),
242     stats_parse(new ::StatContainer()),
243     _have_stats(false)
244 {
245     init_stats();
246     
247     bool valid;
248
249     valid = SymtabAPI::Symtab::openFile(_symtab,file);
250     if(!valid) {
251         fprintf(stderr,"[%s] FATAL: can't create Symtab object for file %s\n",
252             FILE__,file);
253         _symtab = NULL;
254         return;
255     }
256     init(NULL,false);
257 }
258
259 bool
260 SymtabCodeSource::init_stats() {
261     if ((getenv("DYNINST_STATS_PARSING"))) {
262         parsing_printf("[%s] Enabling ParseAPI parsing statistics\n", FILE__);
263         // General counts
264         stats_parse->add(PARSE_BLOCK_COUNT, CountStat);
265         stats_parse->add(PARSE_FUNCTION_COUNT, CountStat);
266         
267         // Basic block size information
268         stats_parse->add(PARSE_BLOCK_SIZE, CountStat);
269
270         // Function return status counts
271         stats_parse->add(PARSE_NORETURN_COUNT, CountStat);
272         stats_parse->add(PARSE_RETURN_COUNT, CountStat);
273         stats_parse->add(PARSE_UNKNOWN_COUNT, CountStat);
274         stats_parse->add(PARSE_NORETURN_HEURISTIC, CountStat);
275
276         // Heuristic information
277         stats_parse->add(PARSE_JUMPTABLE_COUNT, CountStat);
278         stats_parse->add(PARSE_JUMPTABLE_FAIL, CountStat);
279         stats_parse->add(PARSE_TAILCALL_COUNT, CountStat);
280         stats_parse->add(PARSE_TAILCALL_FAIL, CountStat);
281
282         _have_stats = true;
283     }
284
285     return _have_stats;
286 }
287
288 void
289 SymtabCodeSource::print_stats() const {
290     
291     if (_have_stats) {
292         fprintf(stderr, "[%s] Printing ParseAPI statistics\n", FILE__);
293         fprintf(stderr, "\t Basic Stats:\n");
294         fprintf(stderr, "\t\t Block Count: %ld\n", (*stats_parse)[PARSE_BLOCK_COUNT]->value());
295         fprintf(stderr, "\t\t Function Count: %ld\n", (*stats_parse)[PARSE_FUNCTION_COUNT]->value());
296         
297         long int blockSize = (*stats_parse)[PARSE_BLOCK_SIZE]->value();
298         if (blockSize) {
299             fprintf(stderr, "\t Basic Block Stats:\n");
300             fprintf(stderr, "\t\t Sum of block sizes (in bytes): %ld\n", blockSize);
301             fprintf(stderr, "\t\t Average block size (in bytes): %lf\n", (double)blockSize/(double)(*stats_parse)[PARSE_BLOCK_COUNT]->value());
302             fprintf(stderr, "\t\t Average blocks per function: %lf\n", 
303                     (double)(*stats_parse)[PARSE_BLOCK_COUNT]->value()/(double)(*stats_parse)[PARSE_FUNCTION_COUNT]->value());
304         } 
305         fprintf(stderr, "\t Function Return Status Stats:\n");
306         fprintf(stderr, "\t\t NORETURN Count: %ld", (*stats_parse)[PARSE_NORETURN_COUNT]->value());
307         long int noretHeuristicCount = (*stats_parse)[PARSE_NORETURN_HEURISTIC]->value();
308         if (noretHeuristicCount) {
309             fprintf(stderr, " (Labled based on heuristic: %ld)", noretHeuristicCount);
310         }
311         fprintf(stderr, "\n");
312         fprintf(stderr, "\t\t RETURN Count: %ld\n", (*stats_parse)[PARSE_RETURN_COUNT]->value());
313         fprintf(stderr, "\t\t UNKNOWN Count: %ld\n", (*stats_parse)[PARSE_UNKNOWN_COUNT]->value());
314
315         fprintf(stderr, "\t Heuristic Stats:\n");
316         fprintf(stderr, "\t\t parseJumpTable attempts: %ld\n", (*stats_parse)[PARSE_JUMPTABLE_COUNT]->value());
317         fprintf(stderr, "\t\t parseJumpTable failures: %ld\n", (*stats_parse)[PARSE_JUMPTABLE_FAIL]->value());
318         fprintf(stderr, "\t\t isTailCall attempts: %ld\n", (*stats_parse)[PARSE_TAILCALL_COUNT]->value());
319         fprintf(stderr, "\t\t isTailCall failures: %ld\n", (*stats_parse)[PARSE_TAILCALL_FAIL]->value());
320
321     }
322 }
323
324 void
325 SymtabCodeSource::incrementCounter(const std::string& name) const
326 {
327     if (_have_stats) {
328         stats_parse->incrementCounter(name);
329     }
330 }
331
332 void 
333 SymtabCodeSource::addCounter(const std::string& name, int num) const
334 {
335     if (_have_stats) {
336         stats_parse->addCounter(name, num);
337     }
338 }
339
340 void
341 SymtabCodeSource::decrementCounter(const std::string& name) const
342 {
343     if (_have_stats) {
344         stats_parse->decrementCounter(name);
345     }
346 }
347
348 void
349 SymtabCodeSource::init(hint_filt * filt , bool allLoadedRegions)
350 {
351     // regions (and hints)
352     init_regions(filt, allLoadedRegions);
353
354     // external linkage
355     init_linkage();
356
357     // table of contents (only exists for some binary types)
358     _table_of_contents = _symtab->getTOCoffset();
359 }
360
361 void 
362 SymtabCodeSource::init_regions(hint_filt * filt , bool allLoadedRegions)
363 {
364     dyn_hash_map<void*,CodeRegion*> rmap;
365     vector<SymtabAPI::Region *> regs;
366     vector<SymtabAPI::Region *> dregs;
367     vector<SymtabAPI::Region *>::iterator rit;
368
369     if ( ! allLoadedRegions ) {
370         _symtab->getCodeRegions(regs);
371         _symtab->getDataRegions(dregs);
372         regs.insert(regs.end(),dregs.begin(),dregs.end());
373     }
374     else {
375         _symtab->getMappedRegions(regs);
376     }
377
378     parsing_printf("[%s:%d] processing %d symtab regions in %s\n",
379         FILE__,__LINE__,regs.size(),_symtab->name().c_str());
380     for(rit = regs.begin(); rit != regs.end(); ++rit) {
381         parsing_printf("   %lx %s",(*rit)->getMemOffset(),
382             (*rit)->getRegionName().c_str());
383     
384         // XXX only TEXT, DATA, TEXTDATA?
385         SymtabAPI::Region::RegionType rt = (*rit)->getRegionType();
386         if(false == allLoadedRegions &&
387            rt != SymtabAPI::Region::RT_TEXT &&
388            rt != SymtabAPI::Region::RT_DATA &&
389            rt != SymtabAPI::Region::RT_TEXTDATA)
390         {
391             parsing_printf(" [skipped]\n");
392             continue;
393         }
394
395         //#if defined(os_vxworks)
396         if(0 == (*rit)->getMemSize()) {
397             parsing_printf(" [skipped null region]\n");
398             continue;
399         }
400         //#endif
401         parsing_printf("\n");
402
403         if(HASHDEF(rmap,*rit)) {
404             parsing_printf("[%s:%d] duplicate region at address %lx\n",
405                 FILE__,__LINE__,(*rit)->getMemOffset());
406         }
407         CodeRegion * cr = new SymtabCodeRegion(_symtab,*rit);
408         rmap[*rit] = cr;
409         addRegion(cr);
410     }
411
412     // Hints are initialized at the SCS level rather than the SCR level
413     // because there is currently no per-Region lookup of functions in
414     // SymtabAPI.
415     init_hints(rmap,filt);
416 }
417
418 void
419 SymtabCodeSource::init_hints(dyn_hash_map<void*, CodeRegion*> & rmap,
420     hint_filt * filt)
421 {
422     vector<SymtabAPI::Function *> fsyms;
423     vector<SymtabAPI::Function *>::iterator fsit;
424     dyn_hash_map<Address,bool> seen;
425     int dupes = 0;
426
427     if(!_symtab->getAllFunctions(fsyms))
428         return;
429
430     parsing_printf("[%s:%d] processing %d symtab hints\n",FILE__,__LINE__,
431         fsyms.size());
432     for(fsit = fsyms.begin(); fsit != fsyms.end(); ++fsit) {
433         if(filt && (*filt)(*fsit))
434         {
435             parsing_printf("    == filtered hint %s [%lx] ==\n",
436                 FILE__,__LINE__,(*fsit)->getOffset(),
437                 (*fsit)->getFirstSymbol()->getPrettyName().c_str());
438             continue;
439         }
440                 /*Achin added code starts 12/15/2014*/
441                 if(!strcmp((*fsit)->getFirstSymbol()->getPrettyName().c_str(),"_non_rtti_object::`vftable'") || !strcmp((*fsit)->getFirstSymbol()->getPrettyName().c_str(),"bad_cast::`vftable'") || !strcmp((*fsit)->getFirstSymbol()->getPrettyName().c_str(),"exception::`vftable'") || !strcmp((*fsit)->getFirstSymbol()->getPrettyName().c_str(),"bad_typeid::`vftable'") || !strcmp((*fsit)->getFirstSymbol()->getPrettyName().c_str(),"sys_errlist"))
442                 {
443                 continue;
444                 }
445
446                 if(!strcmp((*fsit)->getFirstSymbol()->getPrettyName().c_str(),"std::_non_rtti_object::`vftable'") || !strcmp((*fsit)->getFirstSymbol()->getPrettyName().c_str(),"std::__non_rtti_object::`vftable'") || !strcmp((*fsit)->getFirstSymbol()->getPrettyName().c_str(),"std::bad_cast::`vftable'") || !strcmp((*fsit)->getFirstSymbol()->getPrettyName().c_str(),"std::exception::`vftable'") || !strcmp((*fsit)->getFirstSymbol()->getPrettyName().c_str(),"std::bad_typeid::`vftable'"))
447                 {
448                 continue;
449                 }
450                 /*Achin added code ends*/
451
452         if(HASHDEF(seen,(*fsit)->getOffset())) {
453             // XXX it looks as though symtabapi now does de-duplication
454             //     of function symbols automatically, so this code should
455             //     never be reached, except in the case of overlapping
456             //     regions
457            parsing_printf("[%s:%d] duplicate function at address %lx: %s\n",
458                 FILE__,__LINE__,
459                 (*fsit)->getOffset(),
460                 (*fsit)->getFirstSymbol()->getPrettyName().c_str());
461             ++dupes;
462         }
463         seen[(*fsit)->getOffset()] = true;
464
465         SymtabAPI::Region * sr = (*fsit)->getRegion();
466         if(!sr) {
467             parsing_printf("[%s:%d] missing Region in function at %lx\n",
468                 FILE__,__LINE__,(*fsit)->getOffset());
469             continue;
470         }
471         if(!HASHDEF(rmap,sr)) {
472             parsing_printf("[%s:%d] unrecognized Region %lx in function %lx\n",
473                 FILE__,__LINE__,sr->getMemOffset(),(*fsit)->getOffset());
474             continue;
475         }
476         CodeRegion * cr = rmap[sr];
477         if(!cr->isCode((*fsit)->getOffset()))
478         {
479             parsing_printf("\t<%lx> skipped non-code, region [%lx,%lx)\n",
480                 (*fsit)->getOffset(),
481                 sr->getMemOffset(),
482                 sr->getMemOffset()+sr->getDiskSize());
483         } else {
484             _hints.push_back( Hint((*fsit)->getOffset(),
485                                cr,
486                                (*fsit)->getFirstSymbol()->getPrettyName()) );
487             parsing_printf("\t<%lx,%s,[%lx,%lx)>\n",
488                 (*fsit)->getOffset(),
489                 (*fsit)->getFirstSymbol()->getPrettyName().c_str(),
490                 cr->offset(),
491                 cr->offset()+cr->length());
492         }
493     }
494     sort(_hints.begin(), _hints.end());
495 }
496
497 void
498 SymtabCodeSource::init_linkage()
499 {
500     vector<SymtabAPI::relocationEntry> fbt;
501     vector<SymtabAPI::relocationEntry>::iterator fbtit;
502
503     if(!_symtab->getFuncBindingTable(fbt))
504         return;
505
506     for(fbtit = fbt.begin(); fbtit != fbt.end(); ++fbtit)
507         _linkage[(*fbtit).target_addr()] = (*fbtit).name(); 
508 }
509
510 bool
511 SymtabCodeSource::nonReturning(Address addr)
512 {
513     SymtabAPI::Function * f = NULL;
514    
515     _symtab->findFuncByEntryOffset(f,addr); 
516
517     if(f) {
518       for(auto i = f->mangled_names_begin();
519           i != f->mangled_names_end();
520           ++i)
521       {
522         if(CodeSource::nonReturning(*i)) return true;
523       }
524     }
525     return false;
526 }
527
528 bool
529 SymtabCodeSource::nonReturningSyscall(int num)
530 {
531   parsing_printf("Checking non-returning (Symtab) for %d\n", num);
532   Architecture arch = getArch();
533   switch(arch) {
534     case(Arch_x86):
535       return non_returning_syscalls_x86.find(num) != non_returning_syscalls_x86.end();
536     case(Arch_x86_64):
537       return non_returning_syscalls_x86_64.find(num) != non_returning_syscalls_x86_64.end();
538     default:
539       return false;
540   }
541 }
542
543 Address
544 SymtabCodeSource::baseAddress() const
545 {
546     return _symtab->getBaseOffset();
547 }
548
549 Address
550 SymtabCodeSource::loadAddress() const
551 {
552     return _symtab->getLoadOffset();
553 }
554
555 Address
556 SymtabCodeSource::getTOC(Address addr) const
557 {
558     SymtabAPI::Function *func;
559
560     if (_symtab->getContainingFunction(addr, func)) {
561         return func->getTOCOffset();
562     }
563     return _table_of_contents;
564 }
565
566 inline CodeRegion *
567 SymtabCodeSource::lookup_region(const Address addr) const
568 {
569     CodeRegion * ret = NULL;
570     if(_lookup_cache && _lookup_cache->contains(addr))
571         ret = _lookup_cache;
572     else {
573         set<CodeRegion *> stab;
574         int rcnt = findRegions(addr,stab);
575     
576         assert(rcnt <= 1 || regionsOverlap());
577
578         if(rcnt) {
579             ret = *stab.begin();
580             _lookup_cache = ret;
581         } 
582     }
583     return ret;
584 }
585
586 inline void 
587 SymtabCodeSource::overlapping_warn(const char * file, unsigned line) const
588 {
589     
590     if(regionsOverlap()) {
591         fprintf(stderr,"Invocation of routine at %s:%d is ambiguous for "
592                        "binaries with overlapping code regions\n",
593             file,line);
594     }
595 }
596
597 bool
598 SymtabCodeSource::isValidAddress(const Address addr) const
599 {
600     overlapping_warn(FILE__,__LINE__);
601
602     CodeRegion * cr = lookup_region(addr);
603     if(cr)
604         return cr->isValidAddress(addr);
605     else
606         return false;
607 }
608
609 void *
610 SymtabCodeSource::getPtrToInstruction(const Address addr) const
611 {
612     overlapping_warn(FILE__,__LINE__);
613
614     CodeRegion * cr = lookup_region(addr);
615     if(cr)
616         return cr->getPtrToInstruction(addr);
617     else
618         return NULL;
619 }
620
621 void *
622 SymtabCodeSource::getPtrToData(const Address addr) const
623 {
624     overlapping_warn(FILE__,__LINE__);
625
626     CodeRegion * cr = lookup_region(addr);
627     if(cr)
628         return cr->getPtrToData(addr);
629     else
630         return NULL;
631 }
632
633 unsigned int
634 SymtabCodeSource::getAddressWidth() const
635 {
636     return _symtab->getAddressWidth();
637 }
638
639 Architecture
640 SymtabCodeSource::getArch() const
641 {
642     return _symtab->getArchitecture();
643 }
644
645 bool
646 SymtabCodeSource::isCode(const Address addr) const
647 {
648     overlapping_warn(FILE__,__LINE__);
649
650     CodeRegion * cr = lookup_region(addr);
651
652     if(cr)
653         return cr->isCode(addr);
654     else
655         return false;
656 }
657
658 bool
659 SymtabCodeSource::isData(const Address addr) const
660 {
661     overlapping_warn(FILE__,__LINE__);
662
663     CodeRegion * cr = lookup_region(addr);
664     if(cr)
665         return cr->isData(addr);
666     else
667         return false;
668 }
669
670 bool
671 SymtabCodeSource::isReadOnly(const Address addr) const
672 {
673     overlapping_warn(FILE__,__LINE__);
674
675     CodeRegion * cr = lookup_region(addr);
676     if(cr)
677         return cr->isReadOnly(addr);
678     else
679         return false;
680 }
681
682
683 Address
684 SymtabCodeSource::offset() const
685 {
686     return _symtab->imageOffset();
687 }
688
689 Address
690 SymtabCodeSource::length() const
691 {
692     return _symtab->imageLength();
693 }
694
695
696 void 
697 SymtabCodeSource::removeRegion(CodeRegion &cr)
698 {
699     _region_tree.remove( &cr );
700
701     for (vector<CodeRegion*>::iterator rit = _regions.begin(); 
702          rit != _regions.end(); rit++) 
703     {
704         if ( &cr == *rit ) {
705             _regions.erase( rit );
706             break;
707         }
708     }
709 }
710
711 // fails and returns false if it can't find a CodeRegion
712 // to match the SymtabAPI::region
713 // has to remove the region before modifying the region's size, 
714 // otherwise the region can't be found
715 bool
716 SymtabCodeSource::resizeRegion(SymtabAPI::Region *sr, Address newDiskSize)
717 {
718     // find region
719     std::set<CodeRegion*> regions;
720     findRegions(sr->getMemOffset(), regions);
721     bool found_it = false;
722     set<CodeRegion*>::iterator rit = regions.begin();
723     for (; rit != regions.end(); rit++) {
724         if (sr == ((SymtabCodeRegion*)(*rit))->symRegion()) {
725             found_it = true;
726             break;
727         }
728     }
729
730     if (!found_it) {
731         return false;
732     }
733
734     // remove, resize, reinsert
735     removeRegion( **rit );
736     sr->setDiskSize( newDiskSize );
737     addRegion( *rit );
738     return true;
739 }
740
741 void
742 SymtabCodeSource::addNonReturning(std::string func_name)
743 {
744     non_returning_funcs[func_name] = true;
745 }