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