Subclass block_instance
[dyninst.git] / patchAPI / src / PatchBlock.C
1 /* Public Interface */
2
3 #include "common.h"
4 #include "PatchCFG.h"
5
6 using namespace Dyninst;
7 using namespace PatchAPI;
8 using namespace InstructionAPI;
9
10 PatchBlock *PatchBlock::create(ParseAPI::Block *ib, PatchFunction *f) {
11   return f->getBlock(ib);
12 }
13
14 PatchBlock::PatchBlock(ParseAPI::Block *block,
15                        PatchFunction *func)
16    : block_(block),
17      function_(func),
18      srclist_(srcs_),
19      trglist_(trgs_) {};
20
21 PatchBlock::PatchBlock(ParseAPI::Block *blk, PatchObject *obj)
22   : block_(blk),  srclist_(srcs_), trglist_(trgs_) {
23   /*
24   std::vector<ParseAPI::Function*> ifuncs;
25   blk->getFuncs(ifuncs);
26   function_ = obj->getFunc(ifuncs[0]);
27   */
28 }
29
30 PatchBlock::PatchBlock(const PatchBlock *parent, PatchObject *child)
31   : block_(parent->block_), srclist_(srcs_), trglist_(trgs_) {
32   /*  std::vector<ParseAPI::Function*> ifuncs;
33   parent->block_->getFuncs(ifuncs);
34   function_ = child->getFunc(ifuncs[0]);
35   */
36 }
37
38 void PatchBlock::getInsns(InsnInstances &insns) {
39   // Pass through to ParseAPI. They don't have a native interface, so add one.
40   Offset off = block_->start();
41   const unsigned char *ptr =
42     (const unsigned char *)block_->region()->getPtrToInstruction(off);
43   if (ptr == NULL) return;
44   InstructionDecoder d(ptr, size(), block_->obj()->cs()->getArch());
45   while (off < block_->end()) {
46     insns.push_back(std::make_pair(off, d.decode()));
47     off += insns.back().second->size();
48   }
49 }
50
51 void PatchBlock::createInterproceduralEdges(ParseAPI::Edge *iedge,
52                                             Direction dir,
53                                             std::vector<PatchEdge *> &edges) {
54   // Let pT be the target block in the parseAPI
55   // Let {f_1, ..., f_n} be the functions T is in
56   // We create blocks t_i for each function f_i
57   ParseAPI::Block *iblk = (dir == backwards) ? iedge->src() : iedge->trg();
58   if (!iblk) {
59     assert(dir == forwards); // Can't have sink in-edges
60
61     edges.push_back(PatchEdge::create(iedge, this, NULL));
62     return;
63   }
64   std::vector<ParseAPI::Function *> ifuncs;
65   iblk->getFuncs(ifuncs);
66   for (unsigned i = 0; i < ifuncs.size(); ++i) {
67     PatchFunction *pfunc = object()->getFunc(ifuncs[i]);
68     assert(pfunc);
69     PatchBlock *pblock = pfunc->getBlock(iblk);
70     assert(pblock);
71     PatchEdge *newEdge = NULL;
72     if (dir == forwards)
73       newEdge = PatchEdge::create(iedge, this, pblock);
74     else
75       newEdge = PatchEdge::create(iedge, pblock, this);
76
77     edges.push_back(newEdge);
78   }
79   return;
80 }
81
82
83 PatchBlock::edgelist &PatchBlock::sources() {
84   if (srcs_.empty()) {
85     for (ParseAPI::Block::edgelist::iterator iter = block_->sources().begin();
86          iter != block_->sources().end(); ++iter) {
87       // We need to copy interprocedural edges to ensure that we de-overlap
88       // code in functions. We do this here.
89       // XXX
90       //if ((*iter)->interproc()) {
91       if ((*iter)->type() == ParseAPI::CALL) {
92         createInterproceduralEdges(*iter, backwards, srcs_);
93       }
94       else {
95         // Can lazily create the source block since it's in
96         // our function.
97         PatchEdge *newEdge = PatchEdge::create(*iter, NULL, this);
98         srcs_.push_back(newEdge);
99       }
100     }
101   }
102   return srclist_;
103 }
104
105 PatchBlock::edgelist &PatchBlock::targets() {
106   if (trgs_.empty()) {
107     for (ParseAPI::Block::edgelist::iterator iter = block_->targets().begin();
108          iter != block_->targets().end(); ++iter) {
109       // We need to copy interprocedural edges to ensure that we de-overlap
110       // code in functions. We do this here.
111       // XXX: this doesn't work!
112       //         if ((*iter)->interproc()) {
113       if ((*iter)->type() == ParseAPI::CALL) {
114         createInterproceduralEdges(*iter, forwards, trgs_);
115       }
116       else {
117         // Can lazily create the source block since it's in
118         // our function.
119         PatchEdge *newEdge = PatchEdge::create(*iter, this, NULL);
120         trgs_.push_back(newEdge);
121       }
122     }
123   }
124   return trglist_;
125 }
126
127 PatchObject* PatchBlock::object() const {
128   assert(function_);
129   return function_->object();
130 }
131
132
133 void PatchBlock::destroy(PatchBlock *b) {
134   // As a note, deleting edges that source and target this
135   // block is an exercise in delicacy. Make sure you know
136   // what you're doing. For this, we ensure that we always
137   // remove source edges first, and that we can't accidentally
138   // invalidate an iterator.
139   for (std::vector<PatchEdge *>::iterator iter = b->srcs_.begin();
140        iter != b->srcs_.end(); ++iter) {
141     if ((*iter)->src_) {
142       (*iter)->src_->removeTargetEdge(*iter);
143     }
144     PatchEdge::destroy(*iter);
145   }
146   b->srcs_.clear();
147   for (std::vector<PatchEdge *>::iterator iter = b->trgs_.begin();
148        iter != b->trgs_.end(); ++iter) {
149     if ((*iter)->trg_) {
150       (*iter)->trg_->removeSourceEdge(*iter);
151     }
152     PatchEdge::destroy(*iter);
153   }
154   b->trgs_.clear();
155   delete b;
156 }
157
158 void PatchBlock::removeSourceEdge(PatchEdge *e) {
159   // This is called as part of teardown
160   // of another Block to remove its edges from our
161   // vectors.
162   for (std::vector<PatchEdge *>::iterator iter = srcs_.begin();
163        iter != srcs_.end(); ++iter) {
164     if ((*iter) == e) {
165       srcs_.erase(iter);
166       return;
167     }
168   }
169 }
170
171 void PatchBlock::removeTargetEdge(PatchEdge *e) {
172   // This is called as part of teardown
173   // of another Block to remove its edges from our
174   // vectors.
175   for (std::vector<PatchEdge *>::iterator iter = trgs_.begin();
176        iter != trgs_.end(); ++iter) {
177     if ((*iter) == e) {
178       trgs_.erase(iter);
179       return;
180     }
181   }
182 }
183
184
185 bool PatchBlock::isShared() {
186   std::vector<ParseAPI::Function*> funcs;
187   block()->getFuncs(funcs);
188   if (funcs.size() > 1) return true;
189   return false;
190 }
191 PatchBlock::~PatchBlock() {
192   // We assume top-down teardown of data
193   //   assert(srcs_.empty());
194   //   assert(trgs_.empty());
195 }