Integrate patchmgr into BPatch_process.
[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::removeSourceEdge(PatchEdge *e) {
140   // This is called as part of teardown
141   // of another Block to remove its edges from our
142   // vectors.
143   for (std::vector<PatchEdge *>::iterator iter = srcs_.begin();
144        iter != srcs_.end(); ++iter) {
145     if ((*iter) == e) {
146       srcs_.erase(iter);
147       return;
148     }
149   }
150 }
151
152 void PatchBlock::removeTargetEdge(PatchEdge *e) {
153   // This is called as part of teardown
154   // of another Block to remove its edges from our
155   // vectors.
156   for (std::vector<PatchEdge *>::iterator iter = trgs_.begin();
157        iter != trgs_.end(); ++iter) {
158     if ((*iter) == e) {
159       trgs_.erase(iter);
160       return;
161     }
162   }
163 }
164
165
166 bool PatchBlock::isShared() {
167   return containingFuncs() > 1;
168 }
169 PatchBlock::~PatchBlock() {
170   // As a note, deleting edges that source and target this
171   // block is an exercise in delicacy. Make sure you know
172   // what you're doing. For this, we ensure that we always
173   // remove source edges first, and that we can't accidentally
174   // invalidate an iterator.
175   for (std::vector<PatchEdge *>::iterator iter = srcs_.begin();
176        iter != srcs_.end(); ++iter) {
177     if ((*iter)->src_) {
178       (*iter)->src_->removeTargetEdge(*iter);
179     }
180     delete *iter;
181   }
182   srcs_.clear();
183   for (std::vector<PatchEdge *>::iterator iter = trgs_.begin();
184        iter != trgs_.end(); ++iter) {
185     if ((*iter)->trg_) {
186       (*iter)->trg_->removeSourceEdge(*iter);
187     }
188     delete *iter;
189   }
190   trgs_.clear();
191 }
192
193 Address PatchBlock::start() const {
194   return object()->codeBase() + block_->start();
195 }
196
197 Address PatchBlock::end() const {
198   return object()->codeBase() + block_->end();
199 }
200
201 Address PatchBlock::last() const {
202   return object()->codeBase() + block_->lastInsnAddr();
203 }
204
205 Address PatchBlock::size() const {
206   return block_->size();
207 }
208
209 int PatchBlock::containingFuncs() const {
210   return block_->containingFuncs();
211 }
212
213 bool PatchBlock::containsCall() {
214   ParseAPI::Block::edgelist & out_edges = block_->targets();
215   ParseAPI::Block::edgelist::iterator eit = out_edges.begin();
216   for( ; eit != out_edges.end(); ++eit) {
217     if ( ParseAPI::CALL == (*eit)->type() ) {
218       return true;
219     }
220   }
221   return false;
222 }
223
224 bool PatchBlock::containsDynamicCall() {
225   ParseAPI::Block::edgelist & out_edges = block_->targets();
226   ParseAPI::Block::edgelist::iterator eit = out_edges.begin();
227    for( ; eit != out_edges.end(); ++eit) {
228      if ( ParseAPI::CALL == (*eit)->type() && ((*eit)->sinkEdge())) {
229          return true;
230       }
231    }
232    return false;
233 }
234
235 std::string PatchBlock::disassemble() const {
236     stringstream ret;
237     Insns instances;
238     getInsns(instances);
239     for (Insns::iterator iter = instances.begin();
240          iter != instances.end(); ++iter) {
241        ret << "\t" << hex << iter->first << ": " << iter->second->format() << dec << endl;
242     }
243     return ret.str();
244 }
245
246 InstructionAPI::Instruction::Ptr PatchBlock::getInsn(Address a) const {
247    Insns insns;
248    getInsns(insns);
249    return insns[a];
250 }
251
252 std::string PatchBlock::format() const {
253     stringstream ret;
254     ret << "BB["
255         << hex << start()
256         << ","
257         << end() << dec
258         << "]" << endl;
259     return ret.str();
260 }