Various fixes, half in defensive-mode code, half not
[dyninst.git] / patchAPI / src / PatchBlock.C
1 /* Public Interface */
2
3 #include "common.h"
4 #include "PatchCFG.h"
5 #include "AddrSpace.h"
6 #include "PatchObject.h"
7 #include "PatchMgr.h"
8 #include "PatchCallback.h"
9 #include "Point.h"
10
11 using namespace Dyninst;
12 using namespace PatchAPI;
13 using namespace InstructionAPI;
14
15 PatchBlock*
16 PatchBlock::create(ParseAPI::Block *ib, PatchFunction *f) {
17   return f->object()->getBlock(ib);
18 }
19
20 PatchBlock::PatchBlock(ParseAPI::Block *blk, PatchObject *obj)
21   : block_(blk),   obj_(obj) {
22 }
23
24 PatchBlock::PatchBlock(const PatchBlock *parent, PatchObject *child)
25   : block_(parent->block_), obj_(child) {
26 }
27
28 void
29 PatchBlock::getInsns(Insns &insns) const {
30   // Pass through to ParseAPI. They don't have a native interface, so add one.
31   Offset off = block_->start();
32   const unsigned char *ptr =
33     (const unsigned char *)block_->region()->getPtrToInstruction(off);
34   if (ptr == NULL) return;
35   InstructionDecoder d(ptr, size(), block_->obj()->cs()->getArch());
36   while (off < block_->end()) {
37     Instruction::Ptr insn = d.decode();
38     insns[off + obj_->codeBase()] = insn;
39     off += insn->size();
40   }
41 }
42
43 const PatchBlock::edgelist&
44 PatchBlock::getSources() {
45   if (srclist_.empty()) {
46     for (ParseAPI::Block::edgelist::iterator iter = block_->sources().begin();
47          iter != block_->sources().end(); ++iter) {
48       PatchEdge *newEdge = obj_->getEdge(*iter, NULL, this);
49       srclist_.push_back(newEdge);
50     }
51   }
52   return srclist_;
53 }
54
55 const PatchBlock::edgelist&
56 PatchBlock::getTargets() {
57   if (trglist_.empty()) {
58     for (ParseAPI::Block::edgelist::iterator iter = block_->targets().begin();
59          iter != block_->targets().end(); ++iter) {
60       PatchEdge *newEdge = obj_->getEdge(*iter, this, NULL);
61       assert(newEdge);
62       trglist_.push_back(newEdge);
63     }
64   }
65   return trglist_;
66 }
67
68 PatchEdge *PatchBlock::findSource(ParseAPI::EdgeTypeEnum type) {
69    for (edgelist::iterator iter = srclist_.begin();
70         iter != srclist_.end(); ++iter) {
71       if ((*iter)->type() == type) return *iter;
72    }
73    return NULL;
74 }
75
76 PatchEdge *PatchBlock::findTarget(ParseAPI::EdgeTypeEnum type) {
77    for (edgelist::iterator iter = trglist_.begin();
78         iter != trglist_.end(); ++iter) {
79       assert(*iter);
80       assert((*iter)->edge());
81       if ((*iter)->type() == type) return *iter;
82    }
83    return NULL;
84 }
85
86 void PatchBlock::addSourceEdge(PatchEdge *e, bool addIfEmpty) {
87    if (!addIfEmpty && srclist_.empty()) return;
88
89    srclist_.push_back(e);
90
91   cb()->add_edge(this, e, PatchCallback::source);
92 }
93
94 void PatchBlock::addTargetEdge(PatchEdge *e, bool addIfEmpty) {
95    assert(e);
96    if (!addIfEmpty && trglist_.empty()) return;
97
98    trglist_.push_back(e);
99    
100    cb()->add_edge(this, e, PatchCallback::target);
101 }
102
103
104 void
105 PatchBlock::removeSourceEdge(PatchEdge *e) {
106    if (srclist_.empty()) return;
107
108   std::vector<PatchEdge *>::iterator iter;
109   if ((iter = std::find(srclist_.begin(), srclist_.end(), e)) != srclist_.end()) {
110     srclist_.erase(iter);
111   }
112
113   cb()->remove_edge(this, e, PatchCallback::source);
114 }
115
116 void
117 PatchBlock::removeTargetEdge(PatchEdge *e) {
118    if (trglist_.empty()) return;
119
120   std::vector<PatchEdge *>::iterator iter;
121   if ((iter = std::find(trglist_.begin(), trglist_.end(), e)) != trglist_.end()) {
122      cerr << "Erasing target edge" << endl;
123     trglist_.erase(iter);
124   }
125   cb()->remove_edge(this, e, PatchCallback::target);
126 }
127
128
129 bool
130 PatchBlock::isShared() {
131   return containingFuncs() > 1;
132 }
133
134 PatchBlock::~PatchBlock() {
135 #if 0
136    // Our predecessor may be deleted...
137   for (std::vector<PatchEdge *>::iterator iter = srclist_.begin();
138        iter != srclist_.end(); ++iter) {
139     PatchBlock* blk = (*iter)->source();
140     blk->removeTargetEdge(*iter);
141   }
142   for (std::vector<PatchEdge *>::iterator iter = trglist_.begin();
143        iter != trglist_.end(); ++iter) {
144     PatchBlock* blk = (*iter)->target();
145     blk->removeSourceEdge(*iter);
146   }
147 #endif
148 }
149
150 Address
151 PatchBlock::start() const {
152   return object()->codeBase() + block_->start();
153 }
154
155 Address
156 PatchBlock::end() const {
157   return object()->codeBase() + block_->end();
158 }
159
160 Address
161 PatchBlock::last() const {
162   return object()->codeBase() + block_->lastInsnAddr();
163 }
164
165 Address
166 PatchBlock::size() const {
167   return block_->size();
168 }
169
170 int
171 PatchBlock::containingFuncs() const {
172   return block_->containingFuncs();
173 }
174
175 bool
176 PatchBlock::containsCall() {
177   ParseAPI::Block::edgelist & out_edges = block_->targets();
178   ParseAPI::Block::edgelist::iterator eit = out_edges.begin();
179   for( ; eit != out_edges.end(); ++eit) {
180     if ( ParseAPI::CALL == (*eit)->type() ) {
181       return true;
182     }
183   }
184   return false;
185 }
186
187 bool
188 PatchBlock::containsDynamicCall() {
189   ParseAPI::Block::edgelist & out_edges = block_->targets();
190   ParseAPI::Block::edgelist::iterator eit = out_edges.begin();
191    for( ; eit != out_edges.end(); ++eit) {
192      if ( ParseAPI::CALL == (*eit)->type() ) { 
193          // see if it's a static call to a bad address
194          return getInsn(last())->readsMemory();
195       }
196    }
197    return false;
198 }
199
200 std::string
201 PatchBlock::disassemble() const {
202   stringstream ret;
203   Insns instances;
204   getInsns(instances);
205   for (Insns::iterator iter = instances.begin();
206        iter != instances.end(); ++iter) {
207     ret << "\t" << hex << iter->first << ": " << iter->second->format() << dec << endl;
208   }
209   return ret.str();
210 }
211
212 InstructionAPI::Instruction::Ptr
213 PatchBlock::getInsn(Address a) const {
214    Insns insns;
215    getInsns(insns);
216    return insns[a];
217 }
218
219 std::string
220 PatchBlock::format() const {
221   stringstream ret;
222   ret << "BB["
223       << hex << start()
224       << ","
225       << end() << dec
226       << "]" << endl;
227   return ret.str();
228 }
229
230 PatchFunction*
231 PatchBlock::getFunction(ParseAPI::Function* f) {
232   return obj_->getFunc(f);
233 }
234
235 ParseAPI::Block*
236 PatchBlock::block() const { return block_; }
237
238 PatchObject*
239 PatchBlock::object() const { return obj_; }
240
241 PatchFunction*
242 PatchBlock::getCallee() {
243   PatchBlock::edgelist::const_iterator it = getTargets().begin();
244   for (; it != getTargets().end(); ++it) {
245     if ((*it)->type() == ParseAPI::CALL) {
246       PatchBlock* trg = (*it)->target();
247       return obj_->getFunc(obj_->co()->findFuncByEntry(trg->block()->region(),
248                                                        trg->start()));
249     }
250   }
251   return NULL;
252 }
253
254 Point *PatchBlock::findPoint(Location loc, Point::Type type, bool create) {
255    PointMakerPtr maker = obj_->addrSpace()->mgr()->pointMaker();
256    PatchMgrPtr mgr = obj_->addrSpace()->mgr();
257    Point *ret = NULL;
258
259    switch (type) {
260       case Point::BlockEntry:
261          if (!points_.entry && create) {
262             points_.entry = maker->createPoint(loc, type);
263          }
264          return points_.entry;
265          break;
266       case Point::BlockExit:
267          if (!points_.exit && create) {
268             points_.exit = maker->createPoint(loc, type);
269          }
270          return points_.exit;
271          break;
272       case Point::BlockDuring:
273          if (!points_.during && create) {
274             points_.during = maker->createPoint(loc, type);
275          }
276          return points_.during;
277          break;
278       case Point::PreInsn: {
279          if (!loc.addr || !loc.insn) return NULL;
280          InsnPoints::iterator iter2 = points_.preInsn.find(loc.addr);
281          if (iter2 == points_.preInsn.end()) {
282             if (!create) return NULL;
283             ret = maker->createPoint(loc, type);
284             points_.preInsn[loc.addr] = ret;
285             return ret;
286          }
287          else {
288             return iter2->second;
289          }
290          break;
291       }
292       case Point::PostInsn: {
293          if (!loc.addr || !loc.insn) return NULL;
294          InsnPoints::iterator iter2 = points_.postInsn.find(loc.addr);
295          if (iter2 == points_.postInsn.end()) {
296             if (!create) return NULL;
297             ret = maker->createPoint(loc, type);
298             points_.preInsn[loc.addr] = ret;
299             return ret;
300          }
301          else return iter2->second;
302          break;
303       }
304       default:
305          return NULL;
306    }
307    assert(0); return NULL; // unreachable, but keep compiler happy
308 }
309
310
311 void PatchBlock::destroy(Point *p) {
312    assert(p->getBlock() == this);
313
314    switch(p->type()) {
315       case Point::PreInsn:
316          delete points_.preInsn[p->address()];
317          break;
318       case Point::PostInsn:
319          delete points_.postInsn[p->address()];
320          break;
321       case Point::BlockEntry:
322          delete points_.entry;
323          break;
324       case Point::BlockExit:
325          delete points_.exit;
326          break;
327       case Point::BlockDuring:
328          delete points_.during;
329          break;
330       default:
331          break;
332    }
333 }
334
335 PatchCallback *PatchBlock::cb() const {
336    return obj_->cb();
337 }
338
339 void PatchBlock::splitBlock(PatchBlock *succ)
340 {
341
342    // Okay, get our edges right and stuff. 
343    // We want to modify when possible so that we keep Points on affected edges the same. 
344    // Therefore:
345    // 1) Incoming edges are unchanged. 
346    // 2) Outgoing edges from p1 are switched to p2 (except the fallthrough from p1 to p2)
347    // 3) Fallthrough edge from p1 to p2 added if it wasn't already (depends on the status
348    //    of our lazy block & edge creation when parseAPI added the edge)
349    // 4) We fix up Points on the block, entry and during points stay here
350
351    // 2)
352    bool hasFTEdge = false;
353    unsigned tidx= 0; 
354    while (tidx < trglist_.size()) {
355       PatchEdge *cur = trglist_[tidx];
356       if (cur->target() == succ) {
357           hasFTEdge = true;
358           tidx++;
359       } else {
360           cur->src_ = succ;
361           succ->trglist_.push_back(cur);
362           int last = trglist_.size()-1;
363           trglist_[tidx] = trglist_[last];
364           trglist_.pop_back();
365       }
366    }
367
368    // 3)
369    if (!hasFTEdge) { // may have been created by ParseAPI callbacks
370        ParseAPI::Block::edgelist &tmp = this->block()->targets();
371        if (tmp.size() != 1) {
372           cerr << "ERROR: split block has " << tmp.size() 
373               << " edges, not 1 as expected!" << endl;
374           assert(0);
375        }
376        ParseAPI::Edge *ft = *(tmp.begin());
377        obj_->getEdge(ft, this, succ);
378    }
379
380    // 4)
381    if (points_.exit) {
382       succ->points_.exit = points_.exit;
383       points_.exit = NULL;
384       succ->points_.exit->changeBlock(succ);
385    }
386
387    InsnPoints::iterator pre = points_.preInsn.lower_bound(succ->start());
388    for (InsnPoints::iterator tmp = pre; tmp != points_.preInsn.end(); ++tmp) {
389       tmp->second->changeBlock(succ);
390       succ->points_.preInsn[tmp->first] = tmp->second;
391    }
392    points_.preInsn.erase(pre, points_.preInsn.end());
393
394    InsnPoints::iterator post = points_.postInsn.lower_bound(succ->start());
395    for (InsnPoints::iterator tmp = post; tmp != points_.postInsn.end(); ++tmp) {
396       tmp->second->changeBlock(succ);
397       succ->points_.postInsn[tmp->first] = tmp->second;
398    }
399    points_.postInsn.erase(post, points_.postInsn.end());
400
401 }
402
403 bool PatchBlock::consistency() const {
404    if (!block_) {
405       cerr << "Error: block has no associated ParseAPI block, failed consistency" << endl;
406       CONSIST_FAIL;
407    }
408    if (!srclist_.empty()) {
409       if (srclist_.size() != block_->sources().size()) {
410          cerr << "Error: block has inconsistent sources size" << endl;
411          CONSIST_FAIL;
412       }
413       for (unsigned i = 0; i < srclist_.size(); ++i) {
414          if (!srclist_[i]->consistency()) {
415             cerr << "Error: source edge inconsistent" << endl;
416             CONSIST_FAIL;
417          }
418       }
419    }
420    if (!trglist_.empty()) {
421       if (trglist_.size() != block_->targets().size()) {
422          cerr << "Error: block has inconsistent targets size; ParseAPI "
423               << block_->targets().size() << " and PatchAPI " 
424               << trglist_.size() << endl;
425          CONSIST_FAIL;
426       }
427       for (unsigned i = 0; i < trglist_.size(); ++i) {
428          if (!trglist_[i]->consistency()) {
429             cerr << "Error: target edge inconsistent" << endl;
430             CONSIST_FAIL;
431          }
432       }
433    }
434    if (!obj_) {
435       cerr << "Error: block has no object" << endl;
436       CONSIST_FAIL;
437    }
438    if (!points_.consistency(this, NULL)) {
439       cerr << "Error: block has inconsistent points" << endl;
440       CONSIST_FAIL;
441    }
442    return true;
443 }
444
445 bool BlockPoints::consistency(const PatchBlock *b, const PatchFunction *f) const {
446    if (entry) {
447       if (!entry->consistency()) CONSIST_FAIL;
448       if (entry->block() != b) CONSIST_FAIL;
449       if (entry->func() != f) CONSIST_FAIL;
450       if (entry->type() != Point::BlockEntry) CONSIST_FAIL;
451    }
452    if (during) {
453       if (!during->consistency()) CONSIST_FAIL;
454       if (during->block() != b) CONSIST_FAIL;
455       if (during->func() != f) CONSIST_FAIL;
456       if (during->type() != Point::BlockDuring) CONSIST_FAIL;
457    }
458    if (exit) {
459       if (!exit->consistency()) CONSIST_FAIL;
460       if (exit->block() != b) CONSIST_FAIL;
461       if (exit->func() != f) CONSIST_FAIL;
462       if (exit->type() != Point::BlockExit) CONSIST_FAIL;
463    }
464    for (InsnPoints::const_iterator iter = preInsn.begin(); iter != preInsn.end(); ++iter) {
465       if (!iter->second->consistency()) CONSIST_FAIL;
466       if (iter->second->block() != b) CONSIST_FAIL;
467       if (iter->second->func() != f) CONSIST_FAIL;
468       if (iter->second->addr() != iter->first) CONSIST_FAIL;
469       if (iter->second->type() != Point::PreInsn) CONSIST_FAIL;
470       if (!b->getInsn(iter->first)) CONSIST_FAIL;
471    }
472    for (InsnPoints::const_iterator iter = postInsn.begin(); iter != postInsn.end(); ++iter) {
473       if (!iter->second->consistency()) CONSIST_FAIL;
474       if (iter->second->block() != b) CONSIST_FAIL;
475       if (iter->second->func() != f) CONSIST_FAIL;
476       if (iter->second->addr() != iter->first) CONSIST_FAIL;
477       if (iter->second->type() != Point::PostInsn) CONSIST_FAIL;
478       if (!b->getInsn(iter->first)) CONSIST_FAIL;
479    }
480    return true;
481 }
482