Thread safety and memory improvements
[dyninst.git] / parseAPI / h / CFG.h
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 #ifndef _PARSER_CFG_H_
31 #define _PARSER_CFG_H_
32
33 #include <vector>
34 #include <set>
35 #include <map>
36 #include <string>
37 #include <functional>
38 #include <boost/iterator/transform_iterator.hpp>
39 #include <boost/range.hpp>
40 #include "dyntypes.h"
41 #include "IBSTree.h"
42
43 #include "InstructionSource.h"
44 #include "ParseContainers.h"
45 #include "Annotatable.h"
46 #include <iostream>
47
48 namespace Dyninst {
49
50    namespace InstructionAPI {
51       class Instruction;
52       typedef boost::shared_ptr<Instruction> InstructionPtr;
53    }
54
55 namespace ParseAPI {
56
57 class LoopAnalyzer;
58 class dominatorCFG;
59 class CodeObject;
60 class CFGModifier;
61
62 enum EdgeTypeEnum {
63     CALL = 0,
64     COND_TAKEN,
65     COND_NOT_TAKEN,
66     INDIRECT,
67     DIRECT,
68     FALLTHROUGH,
69     CATCH,
70     CALL_FT,        // fallthrough after call instruction
71     RET,
72     NOEDGE,
73     _edgetype_end_
74 };
75
76 PARSER_EXPORT std::string format(EdgeTypeEnum e);
77
78 #define FLIST_BADNEXT ((void*)0x111)
79 #define FLIST_BADPREV ((void*)0x222)
80
81 /*
82  * All CFG objects extend allocatable, which
83  * allows them to be added and removed from
84  * accounting structures in constant time
85  */
86 class PARSER_EXPORT allocatable {
87  public:
88     allocatable() :
89        anext_((allocatable*)FLIST_BADNEXT),
90        aprev_((allocatable*)FLIST_BADPREV)
91     { }
92     allocatable * anext_;
93     allocatable * aprev_;
94
95     inline allocatable * alloc_next() const { return anext_; }
96     inline allocatable * alloc_prev() const { return aprev_; }
97     inline void alloc_set_next(allocatable *t) { anext_ = t; }
98     inline void alloc_set_prev(allocatable *t) { aprev_ = t; }
99
100     void remove() {
101         if(anext_ != (allocatable*)FLIST_BADNEXT)
102             anext_->aprev_ = aprev_;
103         if(aprev_ != (allocatable*)FLIST_BADPREV)
104             aprev_->anext_ = anext_;
105
106         anext_ = (allocatable*)FLIST_BADNEXT;
107         aprev_ = (allocatable*)FLIST_BADPREV;
108     }
109
110     void append(allocatable & new_elem) {
111         if(anext_ == (allocatable*)FLIST_BADNEXT ||
112            aprev_ == (allocatable*)FLIST_BADPREV)
113         {
114             fprintf(stderr,
115                 "allocatable::append called on element not on list: %p\n",this);
116             return;
117         }
118         anext_->aprev_ = &new_elem;
119         new_elem.anext_ = anext_;
120         new_elem.aprev_ = this;
121         anext_ = &new_elem;
122     }
123
124     void prepend(allocatable & new_elem) {
125         if(anext_ == (allocatable*)FLIST_BADNEXT ||
126            aprev_ == (allocatable*)FLIST_BADPREV)
127         {
128             fprintf(stderr,
129                "allocatable::prepend called on element not on list: %p\n",this);
130             return;
131         }
132         aprev_->anext_ = &new_elem;
133         new_elem.aprev_ = aprev_;
134         new_elem.anext_ = this;
135         aprev_ = &new_elem;
136     }
137 };
138
139 class Block;
140 class PARSER_EXPORT Edge : public allocatable {
141    friend class CFGModifier;
142  protected:
143     Block * _source;
144     Block * _target;
145
146  private:
147
148 #if defined(_MSC_VER)
149         typedef unsigned __int16 uint16_t;
150         typedef unsigned __int8 uint8_t;
151 #else
152         typedef unsigned short uint16_t;
153         typedef unsigned char uint8_t;
154 #endif
155
156     struct EdgeType {
157         EdgeType(EdgeTypeEnum t, bool s) :
158             _type_enum(t), _sink(s), _interproc(false)
159         { }
160         uint16_t _type_enum;
161         uint8_t _sink;
162         uint8_t  _interproc;    // modifier for interprocedural branches
163                                 // (tail calls)
164     };
165     EdgeType _type;
166
167  public:
168     Edge(Block * source,
169          Block * target,
170          EdgeTypeEnum type);
171      virtual ~Edge();
172
173     Block * src() const { return _source; }
174     Block * trg() const { return _target; }
175     EdgeTypeEnum type() const { 
176         return static_cast<EdgeTypeEnum>(_type._type_enum); 
177     }
178     bool sinkEdge() const { return _type._sink != 0; }
179     bool interproc() const { 
180        return (_type._interproc != 0 ||
181                type() == CALL ||
182                type() == RET);
183     }
184
185     bool intraproc() const {
186        return !interproc();
187     }
188
189     void install();
190
191     /* removes from blocks (and if of type CALL, from finalized source functions ) */
192     void uninstall();
193
194     static void destroy(Edge *, CodeObject *);
195
196  friend class CFGFactory;
197  friend class Parser;
198 };
199
200 /* 
201  * Iteration over edges can be controlled by an EdgePredicate.
202  * Edges are returned only if pred(edge) evaluates true.
203  * 
204  * EdgePredicates are composable by AND.
205  */
206 class PARSER_EXPORT EdgePredicate 
207 {
208  public:
209   EdgePredicate() { }
210     virtual ~EdgePredicate() { }
211     virtual bool pred_impl(Edge *) const;
212     bool operator()(Edge* e) const 
213     {
214       return pred_impl(e);
215     }
216  };
217
218 /* may follow branches into the function if there is shared code */
219 class PARSER_EXPORT Intraproc : public EdgePredicate {
220  public:
221     Intraproc() { }
222     ~Intraproc() { }
223     bool pred_impl(Edge *) const;
224
225 };
226
227 /* follow interprocedural edges */
228  class PARSER_EXPORT Interproc : public EdgePredicate {
229     public:
230         Interproc() {}
231         ~Interproc() { }
232         bool pred_impl(Edge *) const;
233 };
234
235 /*
236  * For proper ostritch-like denial of 
237  * unresolved control flow edges
238  */
239  class PARSER_EXPORT NoSinkPredicate : public ParseAPI::EdgePredicate {
240  public:
241     NoSinkPredicate() { }
242
243     bool pred_impl(ParseAPI::Edge * e) const {
244         return !e->sinkEdge() && EdgePredicate::pred_impl(e);
245     }
246 };
247
248 /* doesn't follow branches into the function if there is shared code */
249 class Function;
250  class PARSER_EXPORT SingleContext : public EdgePredicate {
251  private:
252     Function * _context;
253     bool _forward;
254     bool _backward;
255  public:
256     SingleContext(Function * f, bool forward, bool backward) : 
257         _context(f),
258         _forward(forward),
259         _backward(backward) { }
260     ~SingleContext() { }
261     bool pred_impl(Edge *) const;
262 };
263
264 /* Doesn't follow branches into the function if there is shared code. 
265  * Will follow interprocedural call/return edges */
266  class PARSER_EXPORT SingleContextOrInterproc : public EdgePredicate {
267     private:
268         Function * _context;
269         bool _forward;
270         bool _backward;
271     public:
272         SingleContextOrInterproc(Function * f, bool forward, bool backward) :
273             _context(f),
274             _forward(forward),
275             _backward(backward) { }
276         ~SingleContextOrInterproc() { }
277         bool pred_impl(Edge *) const;
278         bool operator()(Edge* e) const 
279         {
280           return pred_impl(e);
281         }
282 };
283
284 class CodeRegion;
285 class PARSER_EXPORT Block : public Dyninst::interval<Address>, 
286               public allocatable {
287     friend class CFGModifier;
288  public:
289     typedef std::map<Offset, InstructionAPI::InstructionPtr> Insns;
290     typedef std::vector<Edge*> edgelist;
291
292     Block(CodeObject * o, CodeRegion * r, Address start);
293     virtual ~Block();
294
295     Address start() const { return _start; }
296     Address end() const { return _end; }
297     Address lastInsnAddr() const { return _lastInsn; } 
298     Address last() const { return lastInsnAddr(); }
299     Address size() const { return _end - _start; }
300
301     bool parsed() const { return _parsed; }
302
303     CodeObject * obj() const { return _obj; }
304     CodeRegion * region() const { return _region; }
305
306     /* Edge access */
307     const edgelist & sources() const { return _srclist; }
308     const edgelist & targets() const { return _trglist; }
309
310     bool consistent(Address addr, Address & prev_insn);
311
312     int  containingFuncs() const;
313     void getFuncs(std::vector<Function *> & funcs);
314     template<class OutputIterator> void getFuncs(OutputIterator result); 
315
316     void getInsns(Insns &insns) const;
317     InstructionAPI::InstructionPtr getInsn(Offset o) const;
318
319     bool wasUserAdded() const;
320
321     /* interval implementation */
322     Address low() const { return start(); }
323     Address high() const { return end(); }
324
325     struct compare {
326         bool operator()(Block * const & b1, Block * const & b2) const {
327             if(b1->start() < b2->start()) return true;
328             if(b1->start() > b2->start()) return false;
329             
330             // XXX debugging
331             if(b1 != b2)
332                 fprintf(stderr,"FATAL: blocks %p [%lx,%lx) and %p [%lx,%lx) "
333                             "conflict",b1,b1->start(),b1->end(),
334                             b2,b2->start(),b2->end());
335
336             assert(b1 == b2);
337             return false;
338         }
339     };
340
341     static void destroy(Block *b);
342   
343  private:
344     void addSource(Edge * e);
345     void addTarget(Edge * e);
346     void removeTarget(Edge * e);
347     void removeSource(Edge * e);
348     void removeFunc(Function *);
349     void updateEnd(Address addr);
350
351  private:
352     CodeObject * _obj;
353     CodeRegion * _region;
354
355     Address _start;
356     Address _end;
357     Address _lastInsn;
358
359
360     edgelist _srclist;
361     edgelist _trglist;
362     int _func_cnt;
363     bool _parsed;
364
365
366  friend class Edge;
367  friend class Function;
368  friend class Parser;
369  friend class CFGFactory;
370 };
371
372 inline void Block::addSource(Edge * e) 
373 {
374     _srclist.push_back(e);
375 }
376
377 inline void Block::addTarget(Edge * e)
378 {
379     _trglist.push_back(e);
380 }
381
382 inline void Block::removeTarget(Edge * e)
383 {
384     for(unsigned i=0;i<_trglist.size();++i) {
385         if(_trglist[i] == e) {
386             _trglist[i] = _trglist.back();
387             _trglist.pop_back();    
388             break;
389         }
390     }
391 }
392
393 inline void Block::removeSource(Edge * e) {
394     for(unsigned i=0;i<_srclist.size();++i) {
395         if(_srclist[i] == e) {
396             _srclist[i] = _srclist.back();
397             _srclist.pop_back();    
398             break;
399         }
400     }
401 }
402
403 enum FuncReturnStatus {
404     UNSET,
405     NORETURN,
406     UNKNOWN,
407     RETURN
408 };
409
410 /* Discovery method of functions */
411 enum FuncSource {
412     RT = 0,     // recursive traversal (default)
413     HINT,       // specified in code object hints
414     GAP,        // gap heuristics
415     GAPRT,      // RT from gap-discovered function
416     ONDEMAND,   // dynamically discovered
417     MODIFICATION, // Added via user modification
418     _funcsource_end_
419 };
420
421 enum StackTamper {
422     TAMPER_UNSET,
423     TAMPER_NONE,
424     TAMPER_REL,
425     TAMPER_ABS,
426     TAMPER_NONZERO
427 };
428
429 class CodeObject;
430 class CodeRegion;
431 class FuncExtent;
432 class Loop;
433 class LoopTreeNode;
434
435 class PARSER_EXPORT Function : public allocatable, public AnnotatableSparse {
436    friend class CFGModifier;
437    friend class LoopAnalyzer;
438  protected:
439     Address _start;
440     CodeObject * _obj;
441     CodeRegion * _region;
442     InstructionSource * _isrc;
443     
444     FuncSource _src;
445     FuncReturnStatus _rs;
446
447     std::string _name;
448     Block * _entry;
449  protected:
450     Function(); 
451  public:
452     bool _is_leaf_function;
453     Address _ret_addr; // return address of a function stored in stack at function entry
454     typedef std::map<Address, Block*> blockmap;
455     template <typename P>
456     struct select2nd
457     {
458       typedef typename P::second_type result_type;
459       
460       result_type operator()(const P& p) const
461       {
462         return p.second;
463       }
464     };
465     typedef select2nd<blockmap::value_type> selector;
466
467     
468     typedef boost::transform_iterator<selector, blockmap::iterator> bmap_iterator;
469     typedef boost::transform_iterator<selector, blockmap::const_iterator> bmap_const_iterator;
470     typedef boost::iterator_range<bmap_iterator> blocklist;
471     typedef boost::iterator_range<bmap_const_iterator> const_blocklist;
472     typedef std::set<Edge*> edgelist;
473     
474     Function(Address addr, string name, CodeObject * obj, 
475         CodeRegion * region, InstructionSource * isource);
476
477     virtual ~Function();
478
479     virtual const string & name() const;
480
481     Address addr() const { return _start; }
482     CodeRegion * region() const { return _region; }
483     InstructionSource * isrc() const { return _isrc; }
484     CodeObject * obj() const { return _obj; }
485     FuncSource src() const { return _src; }
486     FuncReturnStatus retstatus() const { return _rs; }
487     Block * entry() const { return _entry; }
488     bool parsed() const { return _parsed; }
489
490     /* Basic block and CFG access */
491     blocklist blocks();
492     const_blocklist blocks() const;
493     size_t num_blocks()
494     {
495       if(!_cache_valid) finalize();
496       return _bmap.size();
497     }
498     
499     bool contains(Block *b);
500     const edgelist & callEdges();
501     const_blocklist returnBlocks() ;
502     const_blocklist exitBlocks();
503     const_blocklist exitBlocks() const;
504
505     /* Function details */
506     bool hasNoStackFrame() const { return _no_stack_frame; }
507     bool savesFramePointer() const { return _saves_fp; }
508     bool cleansOwnStack() const { return _cleans_stack; }
509
510     /* Loops */    
511     LoopTreeNode* getLoopTree() const;
512     Loop* findLoop(const char *name) const;
513     bool getLoops(vector<Loop*> &loops) const;
514     bool getOuterLoops(vector<Loop*> &loops) const;
515
516     /* Dominator info */
517
518     /* Return true if A dominates B in this function */
519     bool dominates(Block* A, Block *B) const;
520     Block* getImmediateDominator(Block *A) const;
521     void getImmediateDominates(Block *A, set<Block*> &) const;
522     void getAllDominates(Block *A, set<Block*> &) const;
523
524     /* Post-dominator info */
525
526     /* Return true if A post-dominates B in this function */
527     bool postDominates(Block* A, Block *B) const;
528     Block* getImmediatePostDominator(Block *A) const;
529     void getImmediatePostDominates(Block *A, set<Block*> &) const;
530     void getAllPostDominates(Block *A, set<Block*> &) const;
531
532
533     /* Parse updates and obfuscation */
534     void setEntryBlock(Block *new_entry);
535     void set_retstatus(FuncReturnStatus rs);
536     void removeBlock( Block* );
537
538     StackTamper tampersStack(bool recalculate=false);
539
540     struct less
541     {
542         bool operator()(const Function * f1, const Function * f2) const
543         {
544             return f1->addr() < f2->addr();
545         }
546     };
547
548     /* Contiguous code segments of function */
549     std::vector<FuncExtent *> const& extents();
550
551     /* This should not remain here - this is an experimental fix for
552        defensive mode CFG inconsistency */
553     void invalidateCache() { _cache_valid = false; }
554
555     static void destroy(Function *f);
556
557  private:
558     void delayed_link_return(CodeObject * co, Block * retblk);
559     void finalize();
560
561     bool _parsed;
562     bool _cache_valid;
563     //    blocklist _bl;
564     std::vector<FuncExtent *> _extents;
565
566     /* rapid lookup for edge predicate tests */
567     blocklist blocks_int();
568     
569     blockmap _bmap;
570     bmap_iterator blocks_begin() {
571       return bmap_iterator(_bmap.begin());
572     }
573     bmap_iterator blocks_end() {
574       return bmap_iterator(_bmap.end());
575     }
576     bmap_const_iterator blocks_begin() const 
577     {
578       return bmap_const_iterator(_bmap.begin());
579     }
580     
581     bmap_const_iterator blocks_end() const 
582     {
583       return bmap_const_iterator(_bmap.end());
584     }
585     
586     
587
588     /* rapid lookup for interprocedural queries */
589     edgelist _call_edge_list;
590     blockmap _retBL;
591     bmap_const_iterator ret_begin() const 
592     {
593       return bmap_const_iterator(_retBL.begin());
594     }
595     bmap_const_iterator ret_end() const 
596     {
597       return bmap_const_iterator(_retBL.end());
598     }
599     // Superset of return blocks; this includes all blocks where
600     // execution leaves the function without coming back, including
601     // returns, calls to non-returning calls, tail calls, etc.
602     // Might want to include exceptions...
603     blockmap _exitBL;
604     bmap_const_iterator exit_begin() const 
605     {
606       return bmap_const_iterator(_exitBL.begin());
607     }
608     bmap_const_iterator exit_end() const 
609     {
610       return bmap_const_iterator(_exitBL.end());
611     }
612
613     /* function details */
614     bool _no_stack_frame;
615     bool _saves_fp;
616     bool _cleans_stack;
617     StackTamper _tamper;
618     Address _tamper_addr;
619
620     /* Loop details*/
621     mutable bool _loop_analyzed; // true if loops in the function have been found and stored in _loops
622     mutable std::set<Loop*> _loops;
623     mutable LoopTreeNode *_loop_root; // NULL if the tree structure has not be calculated
624     void getLoopsByNestingLevel(vector<Loop*>& lbb, bool outerMostOnly) const;
625
626
627     /* Dominator and post-dominator info details */
628     mutable bool isDominatorInfoReady;
629     mutable bool isPostDominatorInfoReady;
630     void fillDominatorInfo() const;
631     void fillPostDominatorInfo() const;
632     /** set of basic blocks that this basicblock dominates immediately*/
633     mutable std::map<Block*, std::set<Block*>*> immediateDominates;
634     /** basic block which is the immediate dominator of the basic block */
635     mutable std::map<Block*, Block*> immediateDominator;
636     /** same as previous two fields, but for postdominator tree */
637     mutable std::map<Block*, std::set<Block*>*> immediatePostDominates;
638     mutable std::map<Block*, Block*> immediatePostDominator;
639
640     /*** Internal parsing methods and state ***/
641     void add_block(Block *b);
642
643     friend void Edge::uninstall();
644     friend class Parser;
645     friend class CFGFactory;
646     friend class CodeObject;
647     friend class dominatorCFG;
648 };
649
650 /* Describes a contiguous extent of a Function object */
651 class PARSER_EXPORT FuncExtent : public Dyninst::interval<Address> {
652  private:
653     Function * _func;
654     Address _start;
655     Address _end;
656
657  public:
658     FuncExtent(Function * f, Address start, Address end) :
659         _func(f),
660         _start(start),
661         _end(end) { }
662
663     ~FuncExtent() {
664         _func = NULL;
665     }
666
667     Function * func() { return _func; }
668
669     Address start() const { return _start; }
670     Address end() const { return _end; }
671
672     /* interval implementation */
673     Address low() const { return _start; }
674     Address high() const { return _end; } 
675 };
676
677 /** Natural loops
678   */
679
680 class PARSER_EXPORT Loop  
681 {
682         friend class LoopAnalyzer;
683         friend std::ostream& operator<<(std::ostream&,Loop&);
684
685 private:
686         std::set<Edge*> backEdges;
687         std::set<Block*> entries;
688
689         // the function this loop is part of
690         const Function * func;
691
692         /** set of loops that are contained (nested) in this loop. */
693         std::set<Loop*> containedLoops;
694
695         /** the basic blocks in the loop */
696         std::set<Block*> basicBlocks;
697
698 public:
699         /** If loop which directly encloses this loop. NULL if no such loop */
700
701         Loop* parent;
702
703         /** Return true if the given address is within the range of
704             this loop's basicBlocks */
705
706         bool containsAddress(Address addr);
707           
708         /** Return true if the given address is within the range of
709             this loop's basicBlocks or its children */
710                    
711         bool containsAddressInclusive(Address addr);
712
713
714         /** Loop::getBackEdges */
715         /** Sets edges to the set of back edges that define this loop,
716             returns the number of back edges that define this loop */
717         int getBackEdges(vector<Edge*> &edges);
718
719         /* returns the entry blocks of the loop.
720          * A natural loop has a single entry block
721          * and an irreducible loop has mulbile entry blocks
722          * */
723         int getLoopEntries(vector<Block*>&);
724
725         /** Loop::getContainedLoops    */
726         /** returns vector of contained loops */
727
728         bool getContainedLoops(vector<Loop*> &loops);
729
730         /** Loop::getOuterLoops    */
731         /** returns vector of outer contained loops */
732
733         bool getOuterLoops(vector<Loop*> &loops);
734
735         /** Loop::getLoopBasicBlocks    */
736         /** returns all basic blocks in the loop */
737
738         bool getLoopBasicBlocks(vector<Block*> &blocks);
739
740         /** Loop::getLoopBasicBlocksExclusive    */
741         /** returns all basic blocks in this loop, exluding the blocks
742             of its sub loops. */
743
744         bool getLoopBasicBlocksExclusive(vector<Block*> &blocks);
745
746         /** does this loop or its subloops contain the given block? */
747
748         bool hasBlock(Block *b);
749
750         /** does this loop contain the given block? */
751
752         bool hasBlockExclusive(Block *b);
753
754         /** Loop::hasAncestor    */
755         /** returns true if this loop is a descendant of the given loop */
756
757         bool hasAncestor(Loop *loop);
758
759         /** returns the function this loop is in */
760
761         const Function * getFunction();
762
763         /** Loop::~Loop    */
764         /** destructor for the class */
765
766         ~Loop() { }
767
768         std::string format() const;
769
770 private:
771 // internal use only
772         /** constructor of class */
773         Loop(const Function *);
774
775         /** constructor of the class */
776         Loop(Edge *, const Function *);
777
778         /** get either contained or outer loops, determined by outerMostOnly */
779         bool getLoops(vector<Loop*>&, 
780                       bool outerMostOnly) const;
781 }; // class Loop
782
783 /** A class to represent the tree of nested loops and 
784  *  callees (functions) in the control flow graph.
785  *  @see BPatch_basicBlockLoop
786  *  @see BPatch_flowGraph
787  */
788
789 class PARSER_EXPORT LoopTreeNode {
790     friend class LoopAnalyzer;
791
792  public:
793     // A loop node contains a single Loop instance
794     Loop *loop;
795
796     // The LoopTreeNode instances nested within this loop.
797     vector<LoopTreeNode *> children;
798
799     //  LoopTreeNode::LoopTreeNode
800     //  Create a loop tree node for Loop with name n 
801     LoopTreeNode(Loop *l, const char *n);
802
803     //  Destructor
804     ~LoopTreeNode();
805
806     //  LoopTreeNode::name
807     //  Return the name of this loop. 
808     const char * name(); 
809
810     //  LoopTreeNode::getCalleeName
811     //  Return the function name of the ith callee. 
812     const char * getCalleeName(unsigned int i);
813
814     //  LoopTreeNode::numCallees
815     //  Return the number of callees contained in this loop's body. 
816     unsigned int numCallees();
817
818     //Returns a vector of the functions called by this loop.
819     bool getCallees(vector<Function *> &v);
820     
821
822     //  BPatch_loopTreeNode::findLoop
823     //  find loop by hierarchical name
824     Loop * findLoop(const char *name);
825
826  private:
827
828     /** name which indicates this loop's relative nesting */
829     char *hierarchicalName;
830
831     // A vector of functions called within the body of this loop (and
832     // not the body of sub loops). 
833     vector<Function *> callees;
834
835 }; // class LoopTreeNode 
836
837 } //namespace ParseAPI
838 } //namespace Dyninst
839
840 #endif