Function wrapping implementation and Symtab extensions for undefined symbols
[dyninst.git] / dyninstAPI / src / function.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
32 // $Id: function.C,v 1.10 2005/03/02 19:44:45 bernat Exp
33
34 #include "function.h"
35 #include "process.h"
36 #include "instPoint.h"
37
38 #include "mapped_object.h"
39 #include "mapped_module.h"
40 #include "InstructionDecoder.h"
41 #include "MemoryEmulator/memEmulator.h"
42 #include "Relocation/Transformers/Movement-analysis.h"
43
44 #include "PatchMgr.h" // Scope
45
46 #include "Parsing.h"
47
48 #include "binaryEdit.h"
49
50 using namespace Dyninst;
51 using namespace Dyninst::ParseAPI;
52 using namespace Dyninst::Relocation;
53 using namespace Dyninst::PatchAPI;
54
55 int func_instance_count = 0;
56
57 func_instance::func_instance(parse_func *f,
58                              Address baseAddr,
59                              mapped_module *mod) :
60   PatchFunction(f, mod->obj()),
61   ptrAddr_(f->getPtrOffset() ? f->getPtrOffset() + baseAddr : 0),
62   mod_(mod),
63   handlerFaultAddr_(0),
64   handlerFaultAddrAddr_(0)
65 #if defined(os_windows)
66   , callingConv(unknown_call)
67   , paramSize(0)
68 #endif
69    , wrapperSym_(NULL)
70 {
71   assert(f);
72 #if defined(ROUGH_MEMORY_PROFILE)
73   func_instance_count++;
74   if ((func_instance_count % 1000) == 0)
75     fprintf(stderr, "func_instance_count: %d (%d)\n",
76             func_instance_count, func_instance_count*sizeof(func_instance));
77 #endif
78
79   parsing_printf("%s: creating new proc-specific function at 0x%lx\n",
80                  symTabName().c_str(), addr_);
81
82 }
83
84 func_instance::func_instance(const func_instance *parFunc,
85                              mapped_module *childMod) :
86   PatchFunction(parFunc->ifunc(), childMod->obj()),
87   ptrAddr_(parFunc->ptrAddr_),
88   mod_(childMod),
89   handlerFaultAddr_(0),
90   handlerFaultAddrAddr_(0)
91 #if defined(os_windows)
92   , callingConv(parFunc->callingConv)
93   , paramSize(parFunc->paramSize)
94 #endif
95    , wrapperSym_(NULL)
96 {
97    assert(ifunc());
98    // According to contract /w/ the mapped_object
99    // all blocks have already been constructed.
100    // Do we duplicate the parent or wait? I'm
101    // tempted to wait, just because of the common
102    // fork/exec case.
103 }
104
105 func_instance::~func_instance() {
106   // We don't delete blocks, since they're shared between functions
107   // We _do_ delete context instPoints, though
108   // Except that should get taken care of normally since the
109   // structures are static.
110   for (unsigned i = 0; i < parallelRegions_.size(); i++)
111     delete parallelRegions_[i];
112
113 }
114
115 void func_instance::setHandlerFaultAddr(Address fa) {
116     handlerFaultAddr_ = fa;
117 }
118
119 // Sets the address in the structure at which the fault instruction's
120 // address is stored if "set" is true.  Accesses the fault address and
121 // translates it back to an original address if it corresponds to
122 // relocated code in the Dyninst heap
123 void func_instance::setHandlerFaultAddrAddr(Address faa, bool set) {
124   if (set) {
125     // save the faultAddrAddr
126     handlerFaultAddrAddr_ = faa;
127   }
128
129   // get the faultAddr
130   assert(proc()->proc());
131   assert(sizeof(Address) == proc()->getAddressWidth());
132   Address faultAddr=0;
133   if (!proc()->readDataSpace
134       ((void*)faa, proc()->getAddressWidth(), (void*)&faultAddr, true))
135     {
136       assert(0);
137     }
138
139   // translate the faultAddr back to an original address, and if
140   // that translation was necessary, save it to the faultAddrAddr in the
141   // CONTEXT struct
142   if (proc()->proc()->isRuntimeHeapAddr(faultAddr)) {
143
144     Address origAddr = faultAddr;
145     vector<func_instance *> tmps;
146     baseTramp *bti = NULL;
147     bool success = proc()->getAddrInfo(faultAddr, origAddr, tmps, bti);
148     assert(success);
149     assert( proc()->writeDataSpace((void*)faa,
150                                    sizeof(Address),
151                                    (void*)&origAddr) );
152   }
153 }
154
155 // Set the handler return addr to the most recent instrumented or
156 // relocated address, similar to instPoint::instrSideEffect.
157 // Also, make sure that we update our mapped view of memory,
158 // we may have overwritten memory that was previously not code
159 void func_instance::fixHandlerReturnAddr(Address /*faultAddr*/) {
160     if ( !proc()->proc() || ! handlerFaultAddrAddr_ ) {
161         assert(0);
162         return;
163     }
164 #if 0 //KEVINTODO: this function doesn't work, I tried setting newPC to 0xdeadbeef and it had no impact on the program's behavior.  If the springboards work properly this code is unneeded
165     // Do a straightfoward forward map of faultAddr
166     // First, get the original address
167     func_instance *func;
168     block_instance *block; baseTrampInstance *ignored;
169     Address origAddr;
170     if (!proc()->getRelocInfo(faultAddr, origAddr, block, ignored)) {
171        func = dynamic_cast<process *>(proc())->findActiveFuncByAddr(faultAddr);
172        origAddr = faultAddr;
173     }
174     else {
175        func = block->func();
176     }
177     std::list<Address> relocAddrs;
178     proc()->getRelocAddrs(origAddr, func, relocAddrs, true);
179     Address newPC = (!relocAddrs.empty() ? relocAddrs.back() : origAddr);
180
181     if (newPC != faultAddr) {
182        if(!proc()->writeDataSpace((void*)handlerFaultAddrAddr_,
183                                   sizeof(Address),
184                                   (void*)&newPC)) {
185           assert(0);
186        }
187     }
188 #endif
189 }
190
191 // Remove funcs from:
192 //   mapped_object & mapped_module datastructures
193 //   addressSpace::textRanges codeRangeTree<func_instance*>
194 //   image-level & SymtabAPI datastructures
195 //   BPatch_addressSpace::BPatch_funcMap <func_instance -> BPatch_function>
196 void func_instance::removeFromAll()
197 {
198     mal_printf("purging blocks_ of size = %d from func at %lx\n",
199                all_blocks_.size(), addr());
200
201     // remove from mapped_object & mapped_module datastructures
202     obj()->removeFunction(this);
203     mod()->removeFunction(this);
204
205     delete(this);
206 }
207
208 #if 0
209
210 /* Find parse_blocks that are missing from these datastructures and add
211  * them.  The block_instance constructor does pretty much all of the work in
212  * a chain of side-effects extending all the way into the mapped_object class
213  *
214  * We have to take into account that additional parsing may cause basic block splitting,
215  * in which case it is necessary not only to add new int-level blocks, but to update
216  * block_instance and BPatch_basicBlock objects.
217  */
218 void func_instance::addMissingBlocks()
219 {
220    assert(0 && "TODO");
221     // A bit of a hack, but be sure that we've re-checked the blocks in the
222     // parse_func as well.
223     ifunc()->invalidateCache();
224
225    blocks();
226    // Add new blocks
227
228    const vector<parse_block*> & nblocks = obj()->parse_img()->getNewBlocks();
229    // add blocks by looking up new blocks, if it promises to be more
230    // efficient than looking through all of the llfunc's blocks
231    vector<parse_block*>::const_iterator nit = nblocks.begin();
232    for( ; nit != nblocks.end(); ++nit) {
233        if (ifunc()->contains(*nit)) {
234            addMissingBlock(*nit);
235        }
236    }
237
238    if (ifunc()->blocks().size() > blocks_.size()) { //not just the else case!
239        // we may have parsed into an existing function and added its blocks
240        // to ours, or this may just be a more efficient lookup method
241        Function::blocklist & iblks = ifunc()->blocks();
242        for (Function::blocklist::iterator bit = iblks.begin();
243             bit != iblks.end();
244             bit++)
245        {
246            if (!findBlock(*bit)) {
247                addMissingBlock(SCAST_PB(*bit));
248            }
249        }
250    }
251 }
252
253 void func_instance::getReachableBlocks(const set<block_instance*> &exceptBlocks,
254                                       const list<block_instance*> &seedBlocks,
255                                       set<block_instance*> &reachBlocks)//output
256 {
257     list<parse_block*> imgSeeds;
258     for (list<block_instance*>::const_iterator sit = seedBlocks.begin();
259          sit != seedBlocks.end();
260          sit++)
261     {
262         imgSeeds.push_back((*sit)->llb());
263     }
264     set<parse_block*> imgExcept;
265     for (set<block_instance*>::const_iterator eit = exceptBlocks.begin();
266          eit != exceptBlocks.end();
267          eit++)
268     {
269         imgExcept.insert((*eit)->llb());
270     }
271
272     // image-level function does the work
273     set<parse_block*> imgReach;
274     ifunc()->getReachableBlocks(imgExcept,imgSeeds,imgReach);
275
276     for (set<parse_block*>::iterator rit = imgReach.begin();
277          rit != imgReach.end();
278          rit++)
279     {
280         reachBlocks.insert( findBlock(*rit) );
281     }
282 }
283 #endif
284
285 void print_func_vector_by_pretty_name(std::string prefix,
286                                       pdvector<func_instance *>*funcs) {
287     unsigned int i;
288     func_instance *func;
289     for(i=0;i<funcs->size();i++) {
290       func = ((*funcs)[i]);
291       cerr << prefix << func->prettyName() << endl;
292     }
293 }
294
295 mapped_object *func_instance::obj() const { return mod()->obj(); }
296 AddressSpace *func_instance::proc() const { return obj()->proc(); }
297
298 const func_instance::BlockSet &func_instance::unresolvedCF() {
299    if (unresolvedCF_.empty()) {
300       // A block has unresolved control flow if it has an indirect
301       // out-edge.
302      for (blockset::const_iterator iter = getAllBlocks().begin(); iter != getAllBlocks().end(); ++iter) {
303        block_instance* iblk = SCAST_BI(*iter);
304          if (iblk->llb()->unresolvedCF()) {
305             unresolvedCF_.insert(iblk);
306          }
307       }
308    }
309    return unresolvedCF_;
310 }
311
312 const func_instance::BlockSet &func_instance::abruptEnds() {
313    if (abruptEnds_.empty()) {
314       // A block has unresolved control flow if it has an indirect
315       // out-edge.
316      for (blockset::const_iterator iter = getAllBlocks().begin(); iter != getAllBlocks().end(); ++iter) {
317        block_instance* iblk = SCAST_BI(*iter);
318          if (iblk->llb()->abruptEnd()) {
319             abruptEnds_.insert(iblk);
320          }
321       }
322    }
323    return abruptEnds_;
324 }
325
326 block_instance *func_instance::entryBlock() {
327   return SCAST_BI(getEntryBlock());
328 }
329
330 unsigned func_instance::getNumDynamicCalls()
331 {
332    unsigned count=0;
333    for (blockset::const_iterator iter = getCallBlocks().begin(); iter != getCallBlocks().end(); ++iter) {
334      block_instance* iblk = SCAST_BI(*iter);
335       if (iblk->containsDynamicCall()) {
336          count++;
337       }
338    }
339    return count;
340 }
341
342
343 void func_instance::debugPrint() const {
344     fprintf(stderr, "Function debug dump (%p):\n", this);
345     fprintf(stderr, "  Symbol table names:\n");
346     for (unsigned i = 0; i < symTabNameVector().size(); i++) {
347         fprintf(stderr, "    %s\n", symTabNameVector()[i].c_str());
348     }
349     fprintf(stderr, "  Demangled names:\n");
350     for (unsigned j = 0; j < prettyNameVector().size(); j++) {
351         fprintf(stderr, "    %s\n", prettyNameVector()[j].c_str());
352     }
353     fprintf(stderr, "  Typed names:\n");
354     for (unsigned k = 0; k < typedNameVector().size(); k++) {
355         fprintf(stderr, "    %s\n", typedNameVector()[k].c_str());
356     }
357     fprintf(stderr, "  Address: 0x%lx\n", addr());
358     fprintf(stderr, "  Internal pointer: %p\n", ifunc());
359     fprintf(stderr, "  Object: %s (%p), module: %s (%p)\n",
360             obj()->fileName().c_str(),
361             obj(),
362             mod()->fileName().c_str(),
363             mod());
364     for (blockset::const_iterator
365          cb = all_blocks_.begin();
366          cb != all_blocks_.end();
367          cb++)
368     {
369         block_instance* orig = SCAST_BI(*cb);
370         fprintf(stderr, "  Block start 0x%lx, end 0x%lx\n", orig->start(),
371                 orig->end());
372     }
373 }
374
375 // Add to internal
376 // Add to mapped_object if a "new" name (true return from internal)
377 void func_instance::addSymTabName(const std::string name, bool isPrimary) {
378     if (ifunc()->addSymTabName(name, isPrimary))
379         obj()->addFunctionName(this, name, mapped_object::mangledName);
380 }
381
382 void func_instance::addPrettyName(const std::string name, bool isPrimary) {
383     if (ifunc()->addPrettyName(name, isPrimary))
384         obj()->addFunctionName(this, name, mapped_object::prettyName);
385 }
386
387 // Dig down to the low-level block of b, find the low-level functions
388 // that share it, and map up to int-level functions and add them
389 // to the funcs list.
390 bool func_instance::getSharingFuncs(block_instance *b,
391                                    std::set<func_instance *> & funcs)
392 {
393     bool ret = false;
394
395     vector<Function *> lfuncs;
396     b->llb()->getFuncs(lfuncs);
397     vector<Function *>::iterator fit = lfuncs.begin();
398     for( ; fit != lfuncs.end(); ++fit) {
399       parse_func *ll_func = SCAST_PF(*fit);
400         func_instance *hl_func = obj()->findFunction(ll_func);
401         assert(hl_func);
402
403         if (hl_func == this) continue;
404
405         if (funcs.find(hl_func) == funcs.end()) ret = true;
406         funcs.insert(hl_func);
407     }
408
409     return ret;
410 }
411
412 // Find sharing functions via checking all basic blocks. We might be
413 // able to check only exit points; but we definitely need to check _all_
414 // exits so for now we're checking everything.
415
416 bool func_instance::getSharingFuncs(std::set<func_instance *> &funcs) {
417     bool ret = false;
418
419     // Create the block list.
420     blockset::const_iterator bIter;
421     for (bIter = getAllBlocks().begin();
422          bIter != getAllBlocks().end();
423          bIter++) {
424       block_instance* iblk = SCAST_BI(*bIter);
425        if (getSharingFuncs(iblk,funcs))
426           ret = true;
427     }
428
429     return ret;
430 }
431
432 bool func_instance::getOverlappingFuncs(block_instance *block,
433                                        std::set<func_instance *> &funcs)
434 {
435         ParseAPI::Block *llB = block->llb();
436         std::set<ParseAPI::Block *> overlappingBlocks;
437         for (Address i = llB->start(); i < llB->end(); ++i) {
438                 llB->obj()->findBlocks(llB->region(), i, overlappingBlocks);
439         }
440         // We now have all of the overlapping ParseAPI blocks. Get the set of
441         // ParseAPI::Functions containing each and up-map to func_instances
442         for (std::set<ParseAPI::Block *>::iterator iter = overlappingBlocks.begin();
443                 iter != overlappingBlocks.end(); ++iter) {
444                 std::vector<ParseAPI::Function *> llFuncs;
445                 (*iter)->getFuncs(llFuncs);
446                 for (std::vector<ParseAPI::Function *>::iterator iter2 = llFuncs.begin();
447                      iter2 != llFuncs.end(); ++iter2)  {
448                    funcs.insert(obj()->findFunction(*iter2));
449                 }
450         }
451         return (funcs.size() > 1);
452 }
453
454 bool func_instance::getOverlappingFuncs(std::set<func_instance *> &funcs)
455 {
456     bool ret = false;
457
458     // Create the block list.
459     blockset::const_iterator bIter;
460     for (bIter = getAllBlocks().begin();
461          bIter != getAllBlocks().end();
462          bIter++) {
463       block_instance* iblk = SCAST_BI(*bIter);
464        if (getOverlappingFuncs(iblk,funcs))
465           ret = true;
466     }
467
468     return ret;
469 }
470
471 std::string func_instance::get_name() const
472 {
473    return symTabName();
474 }
475
476 Offset func_instance::addrToOffset(const Address a) const {
477    return a - (addr() - ifunc()->getOffset());
478 }
479
480 const pdvector< int_parRegion* > &func_instance::parRegions()
481 {
482   if (parallelRegions_.size() > 0)
483     return parallelRegions_;
484
485   for (unsigned int i = 0; i < ifunc()->parRegions().size(); i++)
486     {
487       image_parRegion * imPR = ifunc()->parRegions()[i];
488       //int_parRegion * iPR = new int_parRegion(imPR, baseAddr, this);
489       int_parRegion * iPR = new int_parRegion(imPR, addr_, this);
490       parallelRegions_.push_back(iPR);
491     }
492   return parallelRegions_;
493 }
494
495 bool func_instance::consistency() const {
496    // 1) Check for 1:1 block relationship in
497    //    the block list and block map
498    // 2) Check that all instPoints are in the
499    //    correct block.
500
501    const ParseAPI::Function::blocklist &img_blocks = ifunc()->blocks();
502    assert(img_blocks.size() == all_blocks_.size());
503    for (ParseAPI::Function::blocklist::iterator iter = img_blocks.begin();
504         iter != img_blocks.end(); ++iter) {
505       parse_block *img_block = SCAST_PB(*iter);
506       block_instance *b_inst = obj()->findBlock(img_block);
507       assert(all_blocks_.find(b_inst) != all_blocks_.end());
508    }
509
510    return true;
511 }
512
513 Address func_instance::get_address() const { assert(0); return 0; }
514 unsigned func_instance::get_size() const { assert(0); return 0; }
515
516
517 bool func_instance::isInstrumentable() {
518    return ifunc()->isInstrumentable();
519
520    if (!ifunc()->isInstrumentable()) return false;
521
522    // Hack: avoid things that throw exceptions
523    // Make sure we parsed calls
524    for (blockset::const_iterator iter = getCallBlocks().begin(); iter != getCallBlocks().end(); ++iter) {
525       block_instance* iblk = SCAST_BI(*iter);
526       if (iblk->calleeName().find("cxa_throw") != std::string::npos) {
527          cerr << "Func " << symTabName() << " found exception ret false" << endl;
528          return false;
529       }
530       func_instance *callee = iblk->callee();
531
532       cerr << "Func " << symTabName() << " @ " << hex
533            << iblk->start() << ", callee " << iblk->calleeName() << dec << endl;
534
535       if (!callee) {
536          cerr << "Warning: null callee" << endl;
537          continue;
538       }
539       cerr << "Checking callee named " << callee->symTabName() << endl;
540
541       if (callee->symTabName().find("cxa_throw") != std::string::npos) {
542          cerr << "Func " << symTabName() << " found exception ret false" << endl;
543          return false;
544       }
545
546       // TEMPORARY HACKAGE because we're not picking up names for
547       // PLT functions?
548       if (callee->symTabName().find("402700") != std::string::npos) {
549          cerr << "Func " << symTabName() << " found exception ret false" << endl;
550          return false;
551       }
552    }
553    return true;
554 }
555
556 block_instance *func_instance::getBlock(const Address addr) {
557         block_instance *block = obj()->findOneBlockByAddr(addr);
558         // Make sure it's one of ours
559         std::set<func_instance *> funcs;
560         block->getFuncs(std::inserter(funcs, funcs.end()));
561         if (funcs.find(this) != funcs.end()) {
562           //addBlock(block); // Update parent class's bookkeeping stuffs
563           return block;
564         }
565         return NULL;
566 }
567
568 using namespace SymtabAPI;
569
570 bool func_instance::addSymbolsForCopy() {
571    // Not implemented for dynamic mode
572    if (proc()->proc()) return false;
573    // And not implemented for same-module
574
575    // Get the old symbol
576    Symbol *oldsym = getRelocSymbol();
577
578    // Get the new symbol
579    Symbol *wrapperSym = getWrapperSymbol();
580    if (!wrapperSym) {
581       return false;
582    }
583    // Now we split. If this is a static binary, we want to point all the relocations
584    // in this function at the new symbol. If it's a dynamic binary, we can just relocate
585    // the daylights out of it.
586    if (obj()->isStaticExec()) {
587       proc()->edit()->addDyninstSymbol(wrapperSym_);
588       if (!updateRelocationsToSym(oldsym, wrapperSym)) return false;
589    }
590    else {
591       // I think we just add this to the dynamic symbol table...
592       wrapperSym->setDynamic(true);
593       proc()->edit()->addDyninstSymbol(wrapperSym_);
594    }
595
596    return true;
597 }
598
599 bool func_instance::updateRelocationsToSym(Symbol *oldsym, Symbol *newsym) {
600    for (blockset::const_iterator iter = getAllBlocks().begin();
601         iter != getAllBlocks().end(); ++iter) {
602       obj()->parse_img()->getObject()->updateRelocations((*iter)->start(), (*iter)->last(), oldsym, newsym);
603    }
604    return true;
605 }
606
607 Symbol *func_instance::getWrapperSymbol() {
608    // Is created during relocation, which should have
609    // already happened.
610    return wrapperSym_;
611 }
612
613 Symbol *func_instance::getRelocSymbol() {
614    // there should be only one...
615    // HIGHLANDER!
616
617    // find the Symbol corresponding to the func_instance
618    std::vector<Symbol *> syms;
619    ifunc()->func()->getSymbols(syms);
620
621    if (syms.size() == 0) {
622       char msg[256];
623       sprintf(msg, "%s[%d]:  internal error:  cannot find symbol %s"
624               , __FILE__, __LINE__, name().c_str());
625       showErrorCallback(80, msg);
626       assert(0);
627    }
628
629    // try to find a dynamic symbol
630    // (take first static symbol if none are found)
631    Symbol *referring = syms[0];
632    for (unsigned k=0; k<syms.size(); k++) {
633       if (syms[k]->isInDynSymtab()) {
634          referring = syms[k];
635          break;
636       }
637    }
638    return referring;
639 }
640
641 void func_instance::createWrapperSymbol(Address entry, std::string name) {
642    if (wrapperSym_) {
643       // Just update the address
644       wrapperSym_->setOffset(entry);
645       return;
646    }
647    // Otherwise we need to create a new symbol
648    wrapperSym_ = new Symbol(name,
649                             Symbol::ST_FUNCTION,
650                             Symbol::SL_GLOBAL,
651                             Symbol::SV_DEFAULT,
652                             entry,
653                             NULL, // This is module - I probably want this?
654                             NULL, // Region - again, find it?
655                             0, // size - zero okay?
656                             false, // Definitely not dynamic ("Static binaries don't have dynamic symbols - Dan")
657                             false); // Definitely not absolute
658
659 }
660
661 /* PatchAPI stuffs */
662
663 instPoint *func_instance::funcEntryPoint(bool create) {
664    // Lookup the cached points
665    instPoint *p = IPCONV(proc()->mgr()->findPoint(Location(this), Point::FuncEntry, create));
666    return p;
667 }
668
669 instPoint *func_instance::funcExitPoint(block_instance* b, bool create) {
670    instPoint *p = IPCONV(proc()->mgr()->findPoint(Location(this, b), Point::FuncExit, create));
671    return p;
672 }
673
674 void func_instance::funcExitPoints(Points* pts) {
675   std::vector<Point*> points;
676   proc()->mgr()->findPoints(Scope(this), Point::FuncExit, back_inserter(points));
677   for (std::vector<Point*>::iterator pi = points.begin(); pi != points.end(); pi++) {
678     instPoint* p = IPCONV(*pi);
679     pts->push_back(p);
680     assert(p->block());
681   }
682 }
683
684 instPoint *func_instance::preCallPoint(block_instance* b, bool create) {
685    instPoint *p = IPCONV(proc()->mgr()->findPoint(Location(this, b), Point::PreCall, create));
686   return p;
687 }
688
689 instPoint *func_instance::postCallPoint(block_instance* b, bool create) {
690    instPoint *p = IPCONV(proc()->mgr()->findPoint(Location(this, b), Point::PostCall, create));
691    return p;
692 }
693
694 void func_instance::callPoints(Points* pts) {
695   std::vector<Point*> points;
696   proc()->mgr()->findPoints(Scope(this), Point::PreCall|Point::PostCall, back_inserter(points));
697   for (std::vector<Point*>::iterator pi = points.begin(); pi != points.end(); pi++) {
698      instPoint* p = static_cast<instPoint*>(*pi);
699      pts->push_back(p);
700   }
701 }
702
703 instPoint *func_instance::blockEntryPoint(block_instance* b, bool create) {
704    instPoint *p = IPCONV(proc()->mgr()->findPoint(Location(this, b), Point::BlockEntry, create));
705    return p;
706 }
707
708 instPoint *func_instance::blockExitPoint(block_instance* b, bool create) {
709    instPoint *p = IPCONV(proc()->mgr()->findPoint(Location(this, b), Point::BlockExit, create));
710    return p;
711 }
712
713 instPoint *func_instance::preInsnPoint(block_instance* b, Address a,
714                                        InstructionAPI::Instruction::Ptr ptr,
715                                        bool trusted, bool create) {
716    Location loc;
717    if (trusted) {
718       loc = Location(this, InsnLoc(b, a, ptr));
719    }
720    else {
721       loc = Location(this, b, a, ptr);
722    }
723    instPoint *p = IPCONV(proc()->mgr()->findPoint(loc, Point::PreInsn, create));
724    return p;
725 }
726
727 instPoint *func_instance::postInsnPoint(block_instance* b, Address a,
728                                         InstructionAPI::Instruction::Ptr ptr,
729                                         bool trusted, bool create) {
730    Location loc;
731    if (trusted) {
732       loc = Location(this, InsnLoc(b, a, ptr));
733    }
734    else {
735       loc = Location(this, b, a, ptr);
736    }
737    instPoint *p = IPCONV(proc()->mgr()->findPoint(loc, Point::PostInsn, create));
738    return p;
739 }
740
741 void func_instance::blockInsnPoints(block_instance* b, Points* pts) {
742   std::vector<Point*> points;
743   proc()->mgr()->findPoints(Scope(this, b), Point::PreInsn|Point::PostInsn, back_inserter(points));
744   assert(points.size() > 0);
745   for (std::vector<Point*>::iterator i = points.begin(); i != points.end(); i++) {
746     instPoint* pt = static_cast<instPoint*>(*i);
747     pts->push_back(pt);
748   }
749 }
750
751 instPoint* func_instance::edgePoint(edge_instance* e, bool create) {
752    instPoint *p = IPCONV(proc()->mgr()->findPoint(Location(this, e), Point::EdgeDuring, create));
753    return p;
754 }
755
756 void func_instance::edgePoints(Points* pts) {
757    std::vector<Point *> points;
758    proc()->mgr()->findPoints(Scope(this), Point::EdgeDuring, back_inserter(points));
759    for (std::vector<Point*>::iterator i = points.begin(); i != points.end(); i++) {
760       instPoint* pt = static_cast<instPoint*>(*i);
761       edge_instance* e = static_cast<edge_instance*>(pt->edge());
762       pts->push_back(pt);
763    }
764 }
765
766 void func_instance::destroyBlock(block_instance *block) {
767    // Put things here that go away from the perspective of this function
768 }
769
770 void func_instance::destroy(func_instance *f) {
771    // Put things here that go away when we destroy this function
772    delete f;
773 }