2 * See the dyninst/COPYRIGHT file for copyright information.
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.
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.
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.
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.
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
33 #include <boost/assign/list_of.hpp>
35 #include "common/h/stats.h"
38 #include "symtabAPI/h/Symtab.h"
39 #include "symtabAPI/h/Function.h"
41 #include "CodeSource.h"
42 #include "debug_parse.h"
46 using namespace Dyninst;
47 using namespace Dyninst::ParseAPI;
50 /** SymtabCodeRegion **/
52 SymtabCodeRegion::~SymtabCodeRegion()
57 SymtabCodeRegion::SymtabCodeRegion(
58 SymtabAPI::Symtab * st,
59 SymtabAPI::Region * reg) :
66 SymtabCodeRegion::names(Address entry, vector<string> & names)
68 // FIXME SymtabAPI currently doesn't handle ambiguous
69 // functions at the same linear address within
70 // two address spaces. That error is reflected
72 SymtabAPI::Function * f = NULL;
73 bool found = _symtab->findFuncByEntryOffset(f,entry);
76 const vector<string> & pretty = f->getAllPrettyNames();
77 names.insert(names.begin(),pretty.begin(),pretty.end());
80 cerr << "\t Failed to find name" << endl;
85 SymtabCodeRegion::findCatchBlock(Address addr, Address & catchStart)
87 if(!contains(addr)) return false;
89 // FIXME SymtabAPI doesn't handle per-region catch block
90 // lookups either, so faking it for now.
91 SymtabAPI::ExceptionBlock e;
92 if(_symtab->findCatchBlock(e,addr)) {
93 catchStart = e.catchStart();
100 SymtabCodeRegion::isValidAddress(const Address addr) const
102 if(!contains(addr)) return false;
104 return isAligned(addr) && (isCode(addr) || isData(addr));
108 SymtabCodeRegion::getPtrToInstruction(const Address addr) const
110 if(!contains(addr)) return NULL;
113 return (void*)((Address)_region->getPtrToRawData() +
114 addr - _region->getMemOffset());
115 else if(isData(addr))
116 return getPtrToData(addr);
122 SymtabCodeRegion::getPtrToData(const Address addr) const
124 if(!contains(addr)) return NULL;
127 return (void*)((Address)_region->getPtrToRawData() +
128 addr - _region->getMemOffset());
134 SymtabCodeRegion::getAddressWidth() const
136 return _symtab->getAddressWidth();
140 SymtabCodeRegion::getArch() const
142 #if defined(arch_power)
143 if(getAddressWidth() == 8)
147 #elif defined(arch_x86) || defined(arch_x86_64)
148 if(getAddressWidth() == 8)
158 SymtabCodeRegion::isCode(const Address addr) const
160 if(!contains(addr)) return false;
162 // XXX this is the predicate from Symtab::isCode(a) +
163 // the condition by which Symtab::codeRegions_ is filled
164 return !_region->isBSS() &&
165 (_region->getRegionType() == SymtabAPI::Region::RT_TEXT ||
166 _region->getRegionType() == SymtabAPI::Region::RT_TEXTDATA ||
167 (_symtab->isDefensiveBinary() && _region->isLoadable()) );
171 SymtabCodeRegion::isData(const Address addr) const
173 if(!contains(addr)) return false;
175 // XXX Symtab::isData(a) tests both RT_DATA (Region::isData(a))
176 // and RT_TEXTDATA. Mimicking that behavior
177 return _region->isData() ||
178 _region->getRegionType()==SymtabAPI::Region::RT_TEXTDATA;
182 SymtabCodeRegion::offset() const
184 return _region->getMemOffset();
188 SymtabCodeRegion::length() const
190 return _region->getDiskSize();
193 /** SymtabCodeSource **/
195 SymtabCodeSource::~SymtabCodeSource()
199 if(owns_symtab && _symtab)
200 SymtabAPI::Symtab::closeSymtab(_symtab);
201 for(unsigned i=0;i<_regions.size();++i)
205 SymtabCodeSource::SymtabCodeSource(SymtabAPI::Symtab * st,
207 bool allLoadedRegions) :
211 stats_parse(new ::StatContainer()),
215 init(filt,allLoadedRegions);
218 SymtabCodeSource::SymtabCodeSource(SymtabAPI::Symtab * st) :
222 stats_parse(new ::StatContainer()),
229 SymtabCodeSource::SymtabCodeSource(char * file) :
233 stats_parse(new ::StatContainer()),
240 valid = SymtabAPI::Symtab::openFile(_symtab,file);
242 fprintf(stderr,"[%s] FATAL: can't create Symtab object for file %s\n",
251 SymtabCodeSource::init_stats() {
254 if ((p = getenv("DYNINST_STATS_PARSING"))) {
255 parsing_printf("[%s] Enabling ParseAPI parsing statistics\n", FILE__);
257 stats_parse->add(PARSE_BLOCK_COUNT, CountStat);
258 stats_parse->add(PARSE_FUNCTION_COUNT, CountStat);
260 // Basic block size information
261 stats_parse->add(PARSE_BLOCK_SIZE, CountStat);
263 // Function return status counts
264 stats_parse->add(PARSE_NORETURN_COUNT, CountStat);
265 stats_parse->add(PARSE_RETURN_COUNT, CountStat);
266 stats_parse->add(PARSE_UNKNOWN_COUNT, CountStat);
267 stats_parse->add(PARSE_NORETURN_HEURISTIC, CountStat);
269 // Heuristic information
270 stats_parse->add(PARSE_JUMPTABLE_COUNT, CountStat);
271 stats_parse->add(PARSE_JUMPTABLE_FAIL, CountStat);
272 stats_parse->add(PARSE_TAILCALL_COUNT, CountStat);
273 stats_parse->add(PARSE_TAILCALL_FAIL, CountStat);
282 SymtabCodeSource::print_stats() const {
285 fprintf(stderr, "[%s] Printing ParseAPI statistics\n", FILE__);
286 fprintf(stderr, "\t Basic Stats:\n");
287 fprintf(stderr, "\t\t Block Count: %ld\n", (*stats_parse)[PARSE_BLOCK_COUNT]->value());
288 fprintf(stderr, "\t\t Function Count: %ld\n", (*stats_parse)[PARSE_FUNCTION_COUNT]->value());
290 long int blockSize = (*stats_parse)[PARSE_BLOCK_SIZE]->value();
292 fprintf(stderr, "\t Basic Block Stats:\n");
293 fprintf(stderr, "\t\t Sum of block sizes (in bytes): %ld\n", blockSize);
294 fprintf(stderr, "\t\t Average block size (in bytes): %lf\n", (double)blockSize/(double)(*stats_parse)[PARSE_BLOCK_COUNT]->value());
295 fprintf(stderr, "\t\t Average blocks per function: %lf\n",
296 (double)(*stats_parse)[PARSE_BLOCK_COUNT]->value()/(double)(*stats_parse)[PARSE_FUNCTION_COUNT]->value());
298 fprintf(stderr, "\t Function Return Status Stats:\n");
299 fprintf(stderr, "\t\t NORETURN Count: %ld", (*stats_parse)[PARSE_NORETURN_COUNT]->value());
300 long int noretHeuristicCount = (*stats_parse)[PARSE_NORETURN_HEURISTIC]->value();
301 if (noretHeuristicCount) {
302 fprintf(stderr, " (Labled based on heuristic: %ld)", noretHeuristicCount);
304 fprintf(stderr, "\n");
305 fprintf(stderr, "\t\t RETURN Count: %ld\n", (*stats_parse)[PARSE_RETURN_COUNT]->value());
306 fprintf(stderr, "\t\t UNKNOWN Count: %ld\n", (*stats_parse)[PARSE_UNKNOWN_COUNT]->value());
308 fprintf(stderr, "\t Heuristic Stats:\n");
309 fprintf(stderr, "\t\t parseJumpTable attempts: %ld\n", (*stats_parse)[PARSE_JUMPTABLE_COUNT]->value());
310 fprintf(stderr, "\t\t parseJumpTable failures: %ld\n", (*stats_parse)[PARSE_JUMPTABLE_FAIL]->value());
311 fprintf(stderr, "\t\t isTailCall attempts: %ld\n", (*stats_parse)[PARSE_TAILCALL_COUNT]->value());
312 fprintf(stderr, "\t\t isTailCall failures: %ld\n", (*stats_parse)[PARSE_TAILCALL_FAIL]->value());
318 SymtabCodeSource::incrementCounter(std::string name) const
321 stats_parse->incrementCounter(name);
326 SymtabCodeSource::addCounter(std::string name, int num) const
329 stats_parse->addCounter(name, num);
334 SymtabCodeSource::decrementCounter(std::string name) const
337 stats_parse->decrementCounter(name);
342 SymtabCodeSource::init(hint_filt * filt , bool allLoadedRegions)
344 // regions (and hints)
345 init_regions(filt, allLoadedRegions);
350 // table of contents (only exists for some binary types)
351 _table_of_contents = _symtab->getTOCoffset();
355 SymtabCodeSource::init_regions(hint_filt * filt , bool allLoadedRegions)
357 dyn_hash_map<void*,CodeRegion*> rmap;
358 vector<SymtabAPI::Region *> regs;
359 vector<SymtabAPI::Region *> dregs;
360 vector<SymtabAPI::Region *>::iterator rit;
362 if ( ! allLoadedRegions ) {
363 _symtab->getCodeRegions(regs);
364 _symtab->getDataRegions(dregs);
365 regs.insert(regs.end(),dregs.begin(),dregs.end());
368 _symtab->getMappedRegions(regs);
371 parsing_printf("[%s:%d] processing %d symtab regions in %s\n",
372 FILE__,__LINE__,regs.size(),_symtab->name().c_str());
373 for(rit = regs.begin(); rit != regs.end(); ++rit) {
374 parsing_printf(" %lx %s",(*rit)->getMemOffset(),
375 (*rit)->getRegionName().c_str());
377 // XXX only TEXT, DATA, TEXTDATA?
378 SymtabAPI::Region::RegionType rt = (*rit)->getRegionType();
379 if(false == allLoadedRegions &&
380 rt != SymtabAPI::Region::RT_TEXT &&
381 rt != SymtabAPI::Region::RT_DATA &&
382 rt != SymtabAPI::Region::RT_TEXTDATA)
384 parsing_printf(" [skipped]\n");
388 //#if defined(os_vxworks)
389 if(0 == (*rit)->getMemSize()) {
390 parsing_printf(" [skipped null region]\n");
394 parsing_printf("\n");
396 if(HASHDEF(rmap,*rit)) {
397 parsing_printf("[%s:%d] duplicate region at address %lx\n",
398 FILE__,__LINE__,(*rit)->getMemOffset());
400 CodeRegion * cr = new SymtabCodeRegion(_symtab,*rit);
405 // Hints are initialized at the SCS level rather than the SCR level
406 // because there is currently no per-Region lookup of functions in
408 init_hints(rmap,filt);
412 SymtabCodeSource::init_hints(dyn_hash_map<void*, CodeRegion*> & rmap,
415 vector<SymtabAPI::Function *> fsyms;
416 vector<SymtabAPI::Function *>::iterator fsit;
417 dyn_hash_map<Address,bool> seen;
420 if(!_symtab->getAllFunctions(fsyms))
423 parsing_printf("[%s:%d] processing %d symtab hints\n",FILE__,__LINE__,
425 for(fsit = fsyms.begin(); fsit != fsyms.end(); ++fsit) {
426 if(filt && (*filt)(*fsit))
428 parsing_printf(" == filtered hint %s [%lx] ==\n",
429 FILE__,__LINE__,(*fsit)->getOffset(),
430 (*fsit)->getFirstSymbol()->getPrettyName().c_str());
434 if(HASHDEF(seen,(*fsit)->getOffset())) {
435 // XXX it looks as though symtabapi now does de-duplication
436 // of function symbols automatically, so this code should
437 // never be reached, except in the case of overlapping
439 parsing_printf("[%s:%d] duplicate function at address %lx: %s\n",
441 (*fsit)->getOffset(),
442 (*fsit)->getFirstSymbol()->getPrettyName().c_str());
445 seen[(*fsit)->getOffset()] = true;
447 SymtabAPI::Region * sr = (*fsit)->getRegion();
449 parsing_printf("[%s:%d] missing Region in function at %lx\n",
450 FILE__,__LINE__,(*fsit)->getOffset());
453 if(!HASHDEF(rmap,sr)) {
454 parsing_printf("[%s:%d] unrecognized Region %lx in function %lx\n",
455 FILE__,__LINE__,sr->getMemOffset(),(*fsit)->getOffset());
458 CodeRegion * cr = rmap[sr];
459 if(!cr->isCode((*fsit)->getOffset()))
461 parsing_printf("\t<%lx> skipped non-code, region [%lx,%lx)\n",
462 (*fsit)->getOffset(),
464 sr->getMemOffset()+sr->getDiskSize());
466 _hints.push_back( Hint((*fsit)->getOffset(),
468 (*fsit)->getFirstSymbol()->getPrettyName()) );
469 parsing_printf("\t<%lx,%s,[%lx,%lx)>\n",
470 (*fsit)->getOffset(),
471 (*fsit)->getFirstSymbol()->getPrettyName().c_str(),
473 cr->offset()+cr->length());
479 SymtabCodeSource::init_linkage()
481 vector<SymtabAPI::relocationEntry> fbt;
482 vector<SymtabAPI::relocationEntry>::iterator fbtit;
484 if(!_symtab->getFuncBindingTable(fbt))
487 for(fbtit = fbt.begin(); fbtit != fbt.end(); ++fbtit)
488 _linkage[(*fbtit).target_addr()] = (*fbtit).name();
492 SymtabCodeSource::nonReturning(Address addr)
494 SymtabAPI::Function * f = NULL;
496 _symtab->findFuncByEntryOffset(f,addr);
499 const std::vector<std::string> &names = f->getAllMangledNames();
500 for (unsigned i = 0; i < names.size(); ++i) {
501 if (nonReturning(names[i])) {
509 dyn_hash_map<std::string, bool>
510 SymtabCodeSource::non_returning_funcs =
511 boost::assign::map_list_of
516 ("__stack_chk_fail",true)
517 ("__assert_fail",true)
519 ("_ZSt17__throw_bad_allocv",true)
520 ("_ZSt20__throw_length_errorPKc",true)
521 ("_Unwind_Resume",true)
524 ("_ZSt16__throw_bad_castv",true)
525 ("_ZSt19__throw_logic_errorPKc",true)
526 ("_ZSt20__throw_out_of_rangePKc",true)
527 ("__cxa_rethrow",true)
529 ("_ZSt21__throw_runtime_errorPKc",true)
530 ("_gfortran_os_error",true)
531 ("_gfortran_runtime_error",true)
532 ("_gfortran_stop_numeric", true)
533 ("for_stop_core", true)
534 ("__sys_exit", true);
537 SymtabCodeSource::nonReturning(string name)
539 #if defined(os_windows)
540 // We see MSVCR<N>.exit
541 // Of course, it's often reached via indirect call, but hope never fails.
542 if ((name.compare(0, strlen("MSVCR"), "MSVCR") == 0) &&
543 (name.find("exit") != name.npos)) return true;
545 parsing_printf("Checking non-returning (Symtab) for %s\n", name.c_str());
546 return non_returning_funcs.find(name) != non_returning_funcs.end();
550 SymtabCodeSource::baseAddress() const
552 return _symtab->getBaseOffset();
556 SymtabCodeSource::loadAddress() const
558 return _symtab->getLoadOffset();
562 SymtabCodeSource::getTOC(Address addr) const
564 SymtabAPI::Function *func;
566 if (_symtab->getContainingFunction(addr, func)) {
567 return func->getTOCOffset();
569 return _table_of_contents;
573 SymtabCodeSource::lookup_region(const Address addr) const
575 CodeRegion * ret = NULL;
576 if(_lookup_cache && _lookup_cache->contains(addr))
579 set<CodeRegion *> stab;
580 int rcnt = findRegions(addr,stab);
582 assert(rcnt <= 1 || regionsOverlap());
585 // XXX AIX objects frequently have overlapping regions.
586 // Prefer code over data regions, following
587 // SymtabAPI::findEnclosingRegion()
589 set<CodeRegion*>::iterator sit = stab.begin();
590 for( ; sit != stab.end(); ++sit) {
591 CodeRegion * tmp = *sit;
592 if(tmp->isCode(addr)) {
596 // XXX hold the first non-code region as
597 // the default return. Don't stop looking,
598 // however; might find a code region
616 SymtabCodeSource::overlapping_warn(const char * file, unsigned line) const
618 // XXX AIX objects frequently have overlapping regions; just deal.
620 if(regionsOverlap()) {
621 fprintf(stderr,"Invocation of routine at %s:%d is ambiguous for "
622 "binaries with overlapping code regions\n",
629 SymtabCodeSource::isValidAddress(const Address addr) const
631 overlapping_warn(FILE__,__LINE__);
633 CodeRegion * cr = lookup_region(addr);
635 return cr->isValidAddress(addr);
641 SymtabCodeSource::getPtrToInstruction(const Address addr) const
643 overlapping_warn(FILE__,__LINE__);
645 CodeRegion * cr = lookup_region(addr);
647 return cr->getPtrToInstruction(addr);
653 SymtabCodeSource::getPtrToData(const Address addr) const
655 overlapping_warn(FILE__,__LINE__);
657 CodeRegion * cr = lookup_region(addr);
659 return cr->getPtrToData(addr);
665 SymtabCodeSource::getAddressWidth() const
667 return _symtab->getAddressWidth();
671 SymtabCodeSource::getArch() const
673 #if defined(arch_power)
674 if(getAddressWidth() == 8)
678 #elif defined(arch_x86) || defined(arch_x86_64)
679 if(getAddressWidth() == 8)
689 SymtabCodeSource::isCode(const Address addr) const
691 overlapping_warn(FILE__,__LINE__);
693 CodeRegion * cr = lookup_region(addr);
695 return cr->isCode(addr);
701 SymtabCodeSource::isData(const Address addr) const
703 overlapping_warn(FILE__,__LINE__);
705 CodeRegion * cr = lookup_region(addr);
707 return cr->isData(addr);
713 SymtabCodeSource::offset() const
715 return _symtab->imageOffset();
719 SymtabCodeSource::length() const
721 return _symtab->imageLength();
726 SymtabCodeSource::removeRegion(CodeRegion &cr)
728 _region_tree.remove( &cr );
730 for (vector<CodeRegion*>::iterator rit = _regions.begin();
731 rit != _regions.end(); rit++)
734 _regions.erase( rit );
740 // fails and returns false if it can't find a CodeRegion
741 // to match the SymtabAPI::region
742 // has to remove the region before modifying the region's size,
743 // otherwise the region can't be found
745 SymtabCodeSource::resizeRegion(SymtabAPI::Region *sr, Address newDiskSize)
748 std::set<CodeRegion*> regions;
749 findRegions(sr->getMemOffset(), regions);
750 bool found_it = false;
751 set<CodeRegion*>::iterator rit = regions.begin();
752 for (; rit != regions.end(); rit++) {
753 if (sr == ((SymtabCodeRegion*)(*rit))->symRegion()) {
763 // remove, resize, reinsert
764 removeRegion( **rit );
765 sr->setDiskSize( newDiskSize );
771 SymtabCodeSource::addNonReturning(std::string func_name)
773 non_returning_funcs[func_name] = true;