Merge branch 'master' of ssh://git.dyninst.org/pub/dyninst into Defensive
[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
10 using namespace Dyninst;
11 using namespace PatchAPI;
12 using namespace InstructionAPI;
13
14 PatchBlock*
15 PatchBlock::create(ParseAPI::Block *ib, PatchFunction *f) {
16   return f->object()->getBlock(ib);
17 }
18
19 PatchBlock::PatchBlock(ParseAPI::Block *blk, PatchObject *obj)
20   : block_(blk),   obj_(obj) {
21 }
22
23 PatchBlock::PatchBlock(const PatchBlock *parent, PatchObject *child)
24   : block_(parent->block_), obj_(child) {
25 }
26
27 void
28 PatchBlock::getInsns(Insns &insns) const {
29   // Pass through to ParseAPI. They don't have a native interface, so add one.
30   Offset off = block_->start();
31   const unsigned char *ptr =
32     (const unsigned char *)block_->region()->getPtrToInstruction(off);
33   if (ptr == NULL) return;
34   InstructionDecoder d(ptr, size(), block_->obj()->cs()->getArch());
35   while (off < block_->end()) {
36     Instruction::Ptr insn = d.decode();
37     insns[off + obj_->codeBase()] = insn;
38     off += insn->size();
39   }
40 }
41
42 const PatchBlock::edgelist&
43 PatchBlock::getSources() {
44   if (srclist_.empty()) {
45     for (ParseAPI::Block::edgelist::iterator iter = block_->sources().begin();
46          iter != block_->sources().end(); ++iter) {
47       PatchEdge *newEdge = obj_->getEdge(*iter, NULL, this);
48       srclist_.push_back(newEdge);
49     }
50   }
51   return srclist_;
52 }
53
54 const PatchBlock::edgelist&
55 PatchBlock::getTargets() {
56   if (trglist_.empty()) {
57     for (ParseAPI::Block::edgelist::iterator iter = block_->targets().begin();
58          iter != block_->targets().end(); ++iter) {
59       PatchEdge *newEdge = obj_->getEdge(*iter, this, NULL);
60       trglist_.push_back(newEdge);
61     }
62   }
63   return trglist_;
64 }
65
66 void PatchBlock::addSourceEdge(PatchEdge *e, bool addIfEmpty) {
67    if (!addIfEmpty && srclist_.empty()) return;
68
69    srclist_.push_back(e);
70
71   cb()->add_edge(this, e, PatchCallback::source);
72 }
73
74 void PatchBlock::addTargetEdge(PatchEdge *e, bool addIfEmpty) {
75    if (!addIfEmpty && trglist_.empty()) return;
76
77    trglist_.push_back(e);
78    
79    cb()->add_edge(this, e, PatchCallback::target);
80 }
81
82
83 void
84 PatchBlock::removeSourceEdge(PatchEdge *e) {
85    if (srclist_.empty()) return;
86
87   std::vector<PatchEdge *>::iterator iter;
88   if ((iter = std::find(srclist_.begin(), srclist_.end(), e)) != srclist_.end()) {
89     srclist_.erase(iter);
90   }
91
92   cb()->remove_edge(this, e, PatchCallback::source);
93 }
94
95 void
96 PatchBlock::removeTargetEdge(PatchEdge *e) {
97    if (trglist_.empty()) return;
98
99   std::vector<PatchEdge *>::iterator iter;
100   if ((iter = std::find(trglist_.begin(), trglist_.end(), e)) != trglist_.end()) {
101     trglist_.erase(iter);
102   }
103   cb()->remove_edge(this, e, PatchCallback::target);
104 }
105
106
107 bool
108 PatchBlock::isShared() {
109   return containingFuncs() > 1;
110 }
111
112 PatchBlock::~PatchBlock() {
113 #if 0
114    // Our predecessor may be deleted...
115   for (std::vector<PatchEdge *>::iterator iter = srclist_.begin();
116        iter != srclist_.end(); ++iter) {
117     PatchBlock* blk = (*iter)->source();
118     blk->removeTargetEdge(*iter);
119   }
120   for (std::vector<PatchEdge *>::iterator iter = trglist_.begin();
121        iter != trglist_.end(); ++iter) {
122     PatchBlock* blk = (*iter)->target();
123     blk->removeSourceEdge(*iter);
124   }
125 #endif
126 }
127
128 Address
129 PatchBlock::start() const {
130   return object()->codeBase() + block_->start();
131 }
132
133 Address
134 PatchBlock::end() const {
135   return object()->codeBase() + block_->end();
136 }
137
138 Address
139 PatchBlock::last() const {
140   return object()->codeBase() + block_->lastInsnAddr();
141 }
142
143 Address
144 PatchBlock::size() const {
145   return block_->size();
146 }
147
148 int
149 PatchBlock::containingFuncs() const {
150   return block_->containingFuncs();
151 }
152
153 bool
154 PatchBlock::containsCall() {
155   ParseAPI::Block::edgelist & out_edges = block_->targets();
156   ParseAPI::Block::edgelist::iterator eit = out_edges.begin();
157   for( ; eit != out_edges.end(); ++eit) {
158     if ( ParseAPI::CALL == (*eit)->type() ) {
159       return true;
160     }
161   }
162   return false;
163 }
164
165 bool
166 PatchBlock::containsDynamicCall() {
167   ParseAPI::Block::edgelist & out_edges = block_->targets();
168   ParseAPI::Block::edgelist::iterator eit = out_edges.begin();
169    for( ; eit != out_edges.end(); ++eit) {
170      if ( ParseAPI::CALL == (*eit)->type() && ((*eit)->sinkEdge())) {
171          return true;
172       }
173    }
174    return false;
175 }
176
177 std::string
178 PatchBlock::disassemble() const {
179   stringstream ret;
180   Insns instances;
181   getInsns(instances);
182   for (Insns::iterator iter = instances.begin();
183        iter != instances.end(); ++iter) {
184     ret << "\t" << hex << iter->first << ": " << iter->second->format() << dec << endl;
185   }
186   return ret.str();
187 }
188
189 InstructionAPI::Instruction::Ptr
190 PatchBlock::getInsn(Address a) const {
191    Insns insns;
192    getInsns(insns);
193    return insns[a];
194 }
195
196 std::string
197 PatchBlock::format() const {
198   stringstream ret;
199   ret << "BB["
200       << hex << start()
201       << ","
202       << end() << dec
203       << "]" << endl;
204   return ret.str();
205 }
206
207 PatchFunction*
208 PatchBlock::getFunction(ParseAPI::Function* f) {
209   return obj_->getFunc(f);
210 }
211
212 ParseAPI::Block*
213 PatchBlock::block() const { return block_; }
214
215 PatchObject*
216 PatchBlock::object() const { return obj_; }
217
218 PatchFunction*
219 PatchBlock::getCallee() {
220   PatchBlock::edgelist::const_iterator it = getTargets().begin();
221   for (; it != getTargets().end(); ++it) {
222     if ((*it)->type() == ParseAPI::CALL) {
223       PatchBlock* trg = (*it)->target();
224       return obj_->getFunc(obj_->co()->findFuncByEntry(trg->block()->region(),
225                                                        trg->start()));
226     }
227   }
228   return NULL;
229 }
230
231 Point *PatchBlock::findPoint(Location loc, Point::Type type, bool create) {
232    PointMakerPtr maker = obj_->addrSpace()->mgr()->pointMaker();
233    PatchMgrPtr mgr = obj_->addrSpace()->mgr();
234    Point *ret = NULL;
235
236    switch (type) {
237       case Point::BlockEntry:
238          if (!points_.entry && create) {
239             points_.entry = maker->createPoint(loc, type);
240          }
241          return points_.entry;
242          break;
243       case Point::BlockExit:
244          if (!points_.exit && create) {
245             points_.exit = maker->createPoint(loc, type);
246          }
247          return points_.exit;
248          break;
249       case Point::BlockDuring:
250          if (!points_.during && create) {
251             points_.during = maker->createPoint(loc, type);
252          }
253          return points_.during;
254          break;
255       case Point::PreInsn: {
256          if (!loc.addr || !loc.insn) return NULL;
257          InsnPoints::iterator iter2 = points_.preInsn.find(loc.addr);
258          if (iter2 == points_.preInsn.end()) {
259             if (!create) return NULL;
260             ret = maker->createPoint(loc, type);
261             points_.preInsn[loc.addr] = ret;
262             return ret;
263          }
264          else {
265             return iter2->second;
266          }
267          break;
268       }
269       case Point::PostInsn: {
270          if (!loc.addr || !loc.insn) return NULL;
271          InsnPoints::iterator iter2 = points_.postInsn.find(loc.addr);
272          if (iter2 == points_.postInsn.end()) {
273             if (!create) return NULL;
274             ret = maker->createPoint(loc, type);
275             points_.preInsn[loc.addr] = ret;
276             return ret;
277          }
278          else return iter2->second;
279          break;
280       }
281       default:
282          return NULL;
283    }
284    assert(0); return NULL; // unreachable, but keep compiler happy
285 }
286
287
288 void PatchBlock::destroy(Point *p) {
289    assert(p->getBlock() == this);
290
291    switch(p->type()) {
292       case Point::PreInsn:
293          delete points_.preInsn[p->address()];
294          break;
295       case Point::PostInsn:
296          delete points_.postInsn[p->address()];
297          break;
298       case Point::BlockEntry:
299          delete points_.entry;
300          break;
301       case Point::BlockExit:
302          delete points_.exit;
303          break;
304       case Point::BlockDuring:
305          delete points_.during;
306          break;
307       default:
308          break;
309    }
310 }
311
312 PatchCallback *PatchBlock::cb() const {
313    return obj_->cb();
314 }
315
316