After tested under windows.
[dyninst.git] / patchAPI / src / PatchMgr.C
1 /* Public Interface */
2
3 #include "PatchMgr.h"
4 #include "PatchObject.h"
5 #include "PatchCFG.h"
6
7 using Dyninst::ParseAPI::CodeSource;
8 using Dyninst::InstructionAPI::InstructionDecoder;
9 using Dyninst::InstructionAPI::Instruction;
10 using Dyninst::PatchAPI::PatchMgr;
11 using Dyninst::PatchAPI::PatchMgrPtr;
12 using Dyninst::PatchAPI::PointMaker;
13 using Dyninst::PatchAPI::AddrSpacePtr;
14 using Dyninst::PatchAPI::PointMakerPtr;
15 using Dyninst::PatchAPI::InstrumenterPtr;
16 using Dyninst::PatchAPI::InstancePtr;
17 using Dyninst::PatchAPI::Point;
18 using Dyninst::PatchAPI::PointSet;
19 using Dyninst::PatchAPI::PatchBlock;
20 using Dyninst::PatchAPI::PatchEdge;
21 using Dyninst::PatchAPI::PatchFunction;
22
23 bool debug_patchapi_flag = false;
24
25 static void
26 initDebugFlag() {
27   if (getenv("PATCHAPI_DEBUG"))
28     debug_patchapi_flag = true;
29 }
30
31 PatchMgr::PatchMgr(AddrSpacePtr as, PointMakerPtr pt, InstrumenterPtr inst)
32   : point_maker_(pt), as_(as), batch_mode_(0) {
33   if (inst == InstrumenterPtr()) {
34     instor_ = Instrumenter::create(as);
35   } else {
36     inst->setAs(as);
37     instor_ = inst;
38   }
39 }
40
41 PatchMgrPtr
42 PatchMgr::create(AddrSpacePtr as, PointMakerPtr pf, InstrumenterPtr inst) {
43   PatchMgrPtr ret = PatchMgrPtr(new PatchMgr(as, pf, inst));
44   if (!ret) return PatchMgrPtr();
45   initDebugFlag();
46   ret->as_->mgr_ = ret;
47   ret->pointMaker()->setMgr(ret);
48   patch_cerr << "PatchAPI starts.\n";
49   patch_cerr << ws2 << "Glue Instrumenter and Linker ot PatchMgr.\n";
50   return ret;
51 }
52
53 bool
54 PatchMgr::batchStart() {
55   patch_cerr << ws2 << "Batch Start.\n";
56   if (batch_mode_ != 0) {
57     return false;
58   }
59
60   batch_mode_++;
61   return true;
62 }
63
64 /* Return false if no point is found */
65 bool
66 PatchMgr::removeSnippet(InstancePtr instance) {
67   if (instance == InstancePtr()) return false;
68   return instance->destroy();
69 }
70
71 /* If there's NOT any point in type_pt_map, create one
72    otherwise, simply fill those to *points* */
73 template <class Scope> void
74 PatchMgr::getPointsByType(TypePtMap& type_pt_map, Point::Type types,
75                                 Point::Type type, Address addr,
76                                 Scope* scope, PointSet& points) {
77   // If there's NOT a specific *type* in *types*, done.
78   if (!Point::TestType(types, type)) {
79     return;
80   }
81
82   // If there's a specific *type* in *types*:
83   PointSet& pts = type_pt_map[type];
84   bool should_create = true;
85   for (PointSet::iterator i = pts.begin(); i != pts.end(); i++) {
86     if ((*i)->address() == addr) {
87       should_create = false;
88       break;
89     }
90   }
91   if (should_create) {
92     Point* point;
93     point = point_maker_->createPoint(addr, type, scope);
94     pts.insert(point);
95     del_pt_set_.insert(point);
96   }
97   std::copy(pts.begin(), pts.end(), inserter(points, points.begin()));
98 }
99
100 /* Address-level points:
101    - Valid Types: INSN_BEFORE, INSN_FT, INSN_TAKEN
102    return false if no point is found */
103 bool
104 PatchMgr::findPointsByType(Address* addr, Point::Type types,
105                            PointSet& points) {
106   // Make sure this set contains only points that we find in this method
107   points.clear();
108   TypePtMap& type_pt_map = addr_type_pt_map_[*addr];
109
110   CodeSource* cs = NULL;
111   Address relative_addr = 0;
112   Address codeBase = 0;
113
114   for (AddrSpace::ObjSet::iterator ci = as_->objSet().begin();
115        ci != as_->objSet().end(); ci++) {
116     codeBase = (*ci)->codeBase();
117     relative_addr = *addr - codeBase;
118     if ((*ci)->cs()->isValidAddress(relative_addr)) {
119       cs = (*ci)->cs();
120       break;
121     } else {
122       continue;
123     }
124   }
125   if (cs == NULL) {
126     //    fprintf(stderr, "ERROR: 0x%lx is not a valid relative address (absolute addr: 0x%lx, codeBase: 0x%lx)\n", (size_t)relative_addr, (size_t)*addr, (size_t)codeBase);
127     // exit(-1);
128     return false;
129   }
130   InstructionDecoder d(cs->getPtrToInstruction(relative_addr),
131                        cs->length(),
132                        cs->getArch());
133   /*
134   PatchObject* o = NULL;
135   for (AddrSpace::ObjSet::iterator ci = as_->objSet().begin();
136        ci != as_->objSet().end(); ci++) {
137     if ((*ci)->isValidAddress(*addr)) {
138       o = *ci;
139       break;
140     } else {
141       continue;
142     }
143   }
144   if (o == NULL) {
145     //fprintf(stderr, "ERROR: 0x%lx is not a valid relative address (absolute addr: 0x%lx, codeBase: 0x%lx)\n", (size_t)relative_addr, (size_t)*addr, (size_t)codeBase);
146     return false;
147     // exit(-1);
148   }
149   InstructionDecoder d(o->getPtrToInstruction(*addr),
150                        o->cs()->length(),
151                        o->getArch());
152   */
153   Instruction::Ptr insn = d.decode();
154   if (insn == 0) {
155     patch_cerr << "ERROR: instruction at relative addr 0x" << std::hex << relative_addr
156                << " is not a valid instruction.\n";
157     points.clear();
158     return false;
159   }
160   getPointsByType(type_pt_map, types, Point::PreInsn, *addr, addr, points);
161   getPointsByType(type_pt_map, types, Point::PostInsn, *addr, addr, points);
162   if (insn->getCategory() == InstructionAPI::c_BranchInsn) {
163     getPointsByType(type_pt_map, types, Point::InsnTaken, *addr, addr, points);
164   }
165   if (points.size() == 0) return false;
166   return true;
167 }
168
169 /* Block-level points:
170    - Valid Types: BLOCK_ENTRY, BLOCK_EXIT, BLOCK_DURING
171
172    Address-level points (address inside this block):
173    - call findPointsByType(Address ...)
174
175    return false if no point is found */
176 bool
177 PatchMgr::findPointsByType(PatchBlock* blk, Point::Type types,
178                            PointSet& points) {
179   // Make sure this set contains only points that we find in this method
180   points.clear();
181   TypePtMap& type_pt_map = blk_type_pt_map_[blk];
182
183   // Find block specific points, including:
184   //  BLOCK_ENTRY, BLOCK_EXIT, BLOCK_DURING
185   Address addr = blk->start();
186   getPointsByType(type_pt_map, types, Point::BlockEntry, addr, blk, points);
187
188   addr = blk->last();
189   getPointsByType(type_pt_map, types, Point::BlockExit, addr, blk, points);
190
191   addr = blk->start();
192   getPointsByType(type_pt_map, types, Point::BlockDuring, addr, blk, points);
193
194   // Find instruction (Address) specific points
195   Address off = blk->start();
196   Address relative_off = off - blk->object()->codeBase();
197   InstructionDecoder d(blk->block()->region()->getPtrToInstruction(relative_off),
198                        blk->size(),
199                        blk->block()->region()->getArch());
200   while (off < blk->end()) {
201     Address insn_addr = off;
202     PointSet insn_points;
203     findPointsByType(&insn_addr, types, insn_points);
204     std::copy(insn_points.begin(), insn_points.end(),
205               inserter(points, points.begin()));
206     off += d.decode()->size();
207   }
208
209   // Find call points and edge points for target edges
210   PatchBlock::edgelist::iterator teit = blk->getTargets().begin();
211   for (; teit != blk->getTargets().end(); ++teit) {
212     PatchEdge* edge = *teit;
213     PointSet edge_points;
214     if (edge->type() == ParseAPI::CALL) {
215       Address a = blk->last();
216       getPointsByType(type_pt_map, types, Point::PreCall, a, blk, points);
217       getPointsByType(type_pt_map, types, Point::PostCall, a, blk, points);
218     }
219     findPointsByType(edge, types, edge_points);
220     std::copy(edge_points.begin(), edge_points.end(),
221               inserter(points, points.begin()));
222   }
223
224   // Find edge points for source edges
225   PatchBlock::edgelist::iterator eit = blk->getSources().begin();
226   for (; eit != blk->getSources().end(); ++eit) {
227     PatchEdge* edge = *eit;
228     PointSet edge_points;
229     findPointsByType(edge, types, edge_points);
230     std::copy(edge_points.begin(), edge_points.end(),
231               inserter(points, points.begin()));
232   }
233
234   if (points.size() == 0) return false;
235   return true;
236 }
237
238 /* Edge-level points:
239    - Valid Types: EDGE_DURING
240   return false if no point is found */
241 bool
242 PatchMgr::findPointsByType(PatchEdge* edge, Point::Type types,
243                            PointSet& points) {
244   // Make sure this set contains only points that we find in this method
245   points.clear();
246   TypePtMap& type_pt_map = edge_type_pt_map_[edge];
247
248   // Find edge specific points, including:
249   //  EDGE_DURING
250
251   // TODO(wenbin): handle indirect case
252   Address addr = 0;
253   switch (edge->type()) {
254     case ParseAPI::COND_TAKEN:
255     case ParseAPI::DIRECT:
256       if (edge->source() != NULL) {
257         addr = edge->source()->last();
258       }
259       break;
260     case ParseAPI::COND_NOT_TAKEN:
261     case ParseAPI::CALL:
262     case ParseAPI::FALLTHROUGH:
263     case ParseAPI::CATCH:
264     case ParseAPI::CALL_FT:
265       if (edge->source() != NULL) {
266         addr = edge->source()->last();
267       }
268       break;
269     case ParseAPI::RET:
270       if (edge->source() != NULL) {
271         addr = edge->source()->last();
272       }
273       break;
274     case ParseAPI::INDIRECT:
275     case ParseAPI::NOEDGE:
276     case ParseAPI::_edgetype_end_:
277       return false;
278   }
279   getPointsByType(type_pt_map, types, Point::EdgeDuring, addr, edge, points);
280   if (points.size() == 0) return false;
281   return true;
282 }
283
284 /* Function-level points:
285    - Valid Types: FUNC_ENTRY, FUNC_EXIT, FUNC_DURING
286    Block-level points (blocks inside this func)
287    Edge-level points (edges inside this func)
288    return false if no point is found */
289 bool
290 PatchMgr::findPointsByType(PatchFunction* func,
291                            Point::Type types, PointSet& points) {
292   // Make sure this set contains only points that we find in this method
293   points.clear();
294   TypePtMap& type_pt_map = func_type_pt_map_[func];
295
296   // Find function specific points, including:
297   //  FUNC_ENTRY, FUNC_EXIT, FUNC_DURING
298   Address addr = func->addr();
299   getPointsByType(type_pt_map, types, Point::FuncEntry, addr, func, points);
300
301   const  PatchFunction::blocklist& retblks = func->getExitBlocks();
302   for (PatchFunction::blocklist::const_iterator bi = retblks.begin();
303        bi != retblks.end(); bi++) {
304     PatchBlock* blk = *bi;
305     addr = blk->last();
306     getPointsByType(type_pt_map, types, Point::FuncExit, addr, func, points);
307   }
308   addr = func->addr();
309   getPointsByType(type_pt_map, types, Point::FuncDuring, addr, func, points);
310
311
312   // Find block specific points, including:
313   // BLOCK_ENTRY, BLOCK_EXIT, BLOCK_DURING
314   const PatchFunction::blocklist& blks = func->getAllBlocks();
315   PatchFunction::blocklist::const_iterator bit = blks.begin();
316   for (; bit != func->getAllBlocks().end(); ++bit) {
317     PatchBlock* blk = *bit;
318     PointSet blk_points;
319     findPointsByType(blk, types, blk_points);
320     std::copy(blk_points.begin(), blk_points.end(),
321               inserter(points, points.begin()));
322   }
323   if (points.size() == 0) return false;
324   return true;
325 }
326
327 /* Start instrumentation */
328 bool
329 PatchMgr::patch() {
330   patch_cerr << ws4 << "Relocation and Generation Start.\n";
331
332   if (!instor_->process()) {
333     std::cerr << "ERROR: instrumenter process failed!\n";
334     return false;
335   }
336
337   patch_cerr << ws2 << "Batch Finish.\n";
338   return true;
339 }
340
341 PatchMgr::~PatchMgr() {
342   for (PointSet::iterator pi = del_pt_set_.begin(); pi != del_pt_set_.end(); pi++) {
343     delete *pi;
344   }
345 }
346