Fix init_fini_callback.
[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      obj_(func->object()) {
21 }
22
23 PatchBlock::PatchBlock(ParseAPI::Block *blk, PatchObject *obj)
24   : block_(blk),  srclist_(srcs_), trglist_(trgs_), obj_(obj) {
25
26   ParseAPI::CodeObject::funclist& all = obj->co()->funcs();
27   for (ParseAPI::CodeObject::funclist::iterator fit = all.begin();
28        fit != all.end(); ++fit) {
29     if ((*fit)->contains(blk)) {
30       function_ = obj->getFunc(*fit);
31       break;
32     }
33   }
34 }
35
36 PatchBlock::PatchBlock(const PatchBlock *parent, PatchObject *child)
37   : block_(parent->block_), srclist_(srcs_), trglist_(trgs_), obj_(child) {
38
39   ParseAPI::CodeObject::funclist& all = child->co()->funcs();
40   for (ParseAPI::CodeObject::funclist::iterator fit = all.begin();
41        fit != all.end(); ++fit) {
42     if ((*fit)->contains(block_)) {
43       function_ = child->getFunc(*fit);
44       break;
45     }
46   }
47 }
48
49 void PatchBlock::getInsns(Insns &insns) const {
50   // Pass through to ParseAPI. They don't have a native interface, so add one.
51   Offset off = block_->start();
52   const unsigned char *ptr =
53     (const unsigned char *)block_->region()->getPtrToInstruction(off);
54   if (ptr == NULL) return;
55   InstructionDecoder d(ptr, size(), block_->obj()->cs()->getArch());
56   while (off < block_->end()) {
57     Instruction::Ptr insn = d.decode();
58     insns[off + obj_->codeBase()] = insn;
59     off += insn->size();
60   }
61 }
62
63 void PatchBlock::createInterproceduralEdges(ParseAPI::Edge *iedge,
64                                             Direction dir,
65                                             std::vector<PatchEdge *> &edges) {
66   // Let pT be the target block in the parseAPI
67   // Let {f_1, ..., f_n} be the functions T is in
68   // We create blocks t_i for each function f_i
69   ParseAPI::Block *iblk = (dir == backwards) ? iedge->src() : iedge->trg();
70   if (!iblk) {
71     assert(dir == forwards); // Can't have sink in-edges
72
73     edges.push_back(PatchEdge::create(iedge, this, NULL));
74     return;
75   }
76   std::vector<ParseAPI::Function *> ifuncs;
77   iblk->getFuncs(ifuncs);
78   for (unsigned i = 0; i < ifuncs.size(); ++i) {
79     PatchFunction *pfunc = object()->getFunc(ifuncs[i]);
80     assert(pfunc);
81     PatchBlock *pblock = pfunc->getBlock(iblk);
82     assert(pblock);
83     PatchEdge *newEdge = NULL;
84     if (dir == forwards)
85       newEdge = PatchEdge::create(iedge, this, pblock);
86     else
87       newEdge = PatchEdge::create(iedge, pblock, this);
88
89     edges.push_back(newEdge);
90   }
91   return;
92 }
93
94
95 PatchBlock::edgelist &PatchBlock::sources() {
96   if (srcs_.empty()) {
97     for (ParseAPI::Block::edgelist::iterator iter = block_->sources().begin();
98          iter != block_->sources().end(); ++iter) {
99       // We need to copy interprocedural edges to ensure that we de-overlap
100       // code in functions. We do this here.
101       // XXX
102       //if ((*iter)->interproc()) {
103       if ((*iter)->type() == ParseAPI::CALL) {
104         createInterproceduralEdges(*iter, backwards, srcs_);
105       }
106       else {
107         // Can lazily create the source block since it's in
108         // our function.
109         PatchEdge *newEdge = PatchEdge::create(*iter, NULL, this);
110         srcs_.push_back(newEdge);
111       }
112     }
113   }
114   return srclist_;
115 }
116
117 PatchBlock::edgelist &PatchBlock::targets() {
118   if (trgs_.empty()) {
119     for (ParseAPI::Block::edgelist::iterator iter = block_->targets().begin();
120          iter != block_->targets().end(); ++iter) {
121       // We need to copy interprocedural edges to ensure that we de-overlap
122       // code in functions. We do this here.
123       // XXX: this doesn't work!
124       //         if ((*iter)->interproc()) {
125       if ((*iter)->type() == ParseAPI::CALL) {
126         createInterproceduralEdges(*iter, forwards, trgs_);
127       }
128       else {
129         // Can lazily create the source block since it's in
130         // our function.
131         PatchEdge *newEdge = PatchEdge::create(*iter, this, NULL);
132         trgs_.push_back(newEdge);
133       }
134     }
135   }
136   return trglist_;
137 }
138
139 void PatchBlock::destroy(PatchBlock *b) {
140   // As a note, deleting edges that source and target this
141   // block is an exercise in delicacy. Make sure you know
142   // what you're doing. For this, we ensure that we always
143   // remove source edges first, and that we can't accidentally
144   // invalidate an iterator.
145   for (std::vector<PatchEdge *>::iterator iter = b->srcs_.begin();
146        iter != b->srcs_.end(); ++iter) {
147     if ((*iter)->src_) {
148       (*iter)->src_->removeTargetEdge(*iter);
149     }
150     PatchEdge::destroy(*iter);
151   }
152   b->srcs_.clear();
153   for (std::vector<PatchEdge *>::iterator iter = b->trgs_.begin();
154        iter != b->trgs_.end(); ++iter) {
155     if ((*iter)->trg_) {
156       (*iter)->trg_->removeSourceEdge(*iter);
157     }
158     PatchEdge::destroy(*iter);
159   }
160   b->trgs_.clear();
161   delete b;
162 }
163
164 void PatchBlock::removeSourceEdge(PatchEdge *e) {
165   // This is called as part of teardown
166   // of another Block to remove its edges from our
167   // vectors.
168   for (std::vector<PatchEdge *>::iterator iter = srcs_.begin();
169        iter != srcs_.end(); ++iter) {
170     if ((*iter) == e) {
171       srcs_.erase(iter);
172       return;
173     }
174   }
175 }
176
177 void PatchBlock::removeTargetEdge(PatchEdge *e) {
178   // This is called as part of teardown
179   // of another Block to remove its edges from our
180   // vectors.
181   for (std::vector<PatchEdge *>::iterator iter = trgs_.begin();
182        iter != trgs_.end(); ++iter) {
183     if ((*iter) == e) {
184       trgs_.erase(iter);
185       return;
186     }
187   }
188 }
189
190
191 bool PatchBlock::isShared() {
192   return containingFuncs() > 1;
193 }
194 PatchBlock::~PatchBlock() {
195   // We assume top-down teardown of data
196   assert(srcs_.empty());
197   assert(trgs_.empty());
198 }
199
200 Address PatchBlock::start() const {
201   return object()->codeBase() + block_->start();
202 }
203
204 Address PatchBlock::end() const {
205   return object()->codeBase() + block_->end();
206 }
207
208 Address PatchBlock::last() const {
209   return object()->codeBase() + block_->lastInsnAddr();
210 }
211
212 Address PatchBlock::size() const {
213   return block_->size();
214 }
215
216 int PatchBlock::containingFuncs() const {
217   return block_->containingFuncs();
218 }
219
220 bool PatchBlock::containsCall() {
221   ParseAPI::Block::edgelist & out_edges = block_->targets();
222   ParseAPI::Block::edgelist::iterator eit = out_edges.begin();
223   for( ; eit != out_edges.end(); ++eit) {
224     if ( ParseAPI::CALL == (*eit)->type() ) {
225       return true;
226     }
227   }
228   return false;
229 }
230
231 bool PatchBlock::containsDynamicCall() {
232   ParseAPI::Block::edgelist & out_edges = block_->targets();
233   ParseAPI::Block::edgelist::iterator eit = out_edges.begin();
234    for( ; eit != out_edges.end(); ++eit) {
235      if ( ParseAPI::CALL == (*eit)->type() && ((*eit)->sinkEdge())) {
236          return true;
237       }
238    }
239    return false;
240 }
241
242 std::string PatchBlock::disassemble() const {
243     stringstream ret;
244     Insns instances;
245     getInsns(instances);
246     for (Insns::iterator iter = instances.begin();
247          iter != instances.end(); ++iter) {
248        ret << "\t" << hex << iter->first << ": " << iter->second->format() << dec << endl;
249     }
250     return ret.str();
251 }
252
253 InstructionAPI::Instruction::Ptr PatchBlock::getInsn(Address a) const {
254    Insns insns;
255    getInsns(insns);
256    return insns[a];
257 }
258
259 std::string PatchBlock::format() const {
260     stringstream ret;
261     ret << "BB["
262         << hex << start()
263         << ","
264         << end() << dec
265         << "]" << endl;
266     return ret.str();
267 }