Version goes to 9.2. All independent defines/constants for version should be replaced...
[dyninst.git] / patchAPI / src / PatchMgr.C
1 /*
2  * See the dyninst/COPYRIGHT file for copyright information.
3  * 
4  * We provide the Paradyn Tools (below described as "Paradyn")
5  * on an AS IS basis, and do not warrant its validity or performance.
6  * We reserve the right to update, modify, or discontinue this
7  * software at any time.  We shall have no obligation to supply such
8  * updates or modifications or any other form of support to you.
9  * 
10  * By your use of Paradyn, you understand and agree that we (or any
11  * other person or entity with proprietary rights in Paradyn) are
12  * under no obligation to provide either maintenance services,
13  * update services, notices of latent defects, or correction of
14  * defects for Paradyn.
15  * 
16  * This library is free software; you can redistribute it and/or
17  * modify it under the terms of the GNU Lesser General Public
18  * License as published by the Free Software Foundation; either
19  * version 2.1 of the License, or (at your option) any later version.
20  * 
21  * This library is distributed in the hope that it will be useful,
22  * but WITHOUT ANY WARRANTY; without even the implied warranty of
23  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
24  * Lesser General Public License for more details.
25  * 
26  * You should have received a copy of the GNU Lesser General Public
27  * License along with this library; if not, write to the Free Software
28  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
29  */
30 /* Public Interface */
31
32 #include "PatchMgr.h"
33 #include "PatchObject.h"
34 #include "PatchCFG.h"
35 #include "Point.h"
36 #include "PatchCallback.h"
37
38 #include "version.h"
39
40 using namespace Dyninst;
41 using namespace PatchAPI;
42
43 using Dyninst::ParseAPI::CodeSource;
44 using Dyninst::InstructionAPI::InstructionDecoder;
45 using Dyninst::InstructionAPI::Instruction;
46 using Dyninst::PatchAPI::PatchMgr;
47 using Dyninst::PatchAPI::PatchMgrPtr;
48 using Dyninst::PatchAPI::PointMaker;
49 using Dyninst::PatchAPI::InstancePtr;
50 using Dyninst::PatchAPI::Point;
51 using Dyninst::PatchAPI::PointSet;
52 using Dyninst::PatchAPI::PatchBlock;
53 using Dyninst::PatchAPI::PatchEdge;
54 using Dyninst::PatchAPI::PatchFunction;
55
56 static const int PatchAPI_major_version = DYNINST_MAJOR_VERSION;
57 static const int PatchAPI_minor_version = DYNINST_MINOR_VERSION;
58 static const int PatchAPI_maintenance_version = DYNINST_PATCH_VERSION;
59
60 void PatchMgr::version(int& major, int& minor, int& maintenance)
61 {
62     major = PatchAPI_major_version;
63     minor = PatchAPI_minor_version;
64     maintenance = PatchAPI_maintenance_version;
65 }
66
67 PatchMgr::PatchMgr(AddrSpace* as, Instrumenter* inst, PointMaker* pt)
68   : as_(as) {
69   if (!pt) {
70     patchapi_debug("Use default PointMaker");
71     point_maker_ = new PointMaker;
72   } else {
73     patchapi_debug("Use plugin PointMaker");
74     point_maker_ = pt;
75   }
76   if (!inst) {
77     patchapi_debug("Use default Instrumenter");
78     instor_ = Instrumenter::create(as);
79   } else {
80     patchapi_debug("Use plugin Instrumenter");
81     inst->setAs(as);
82     instor_ = inst;
83   }
84 }
85
86 PatchMgrPtr
87 PatchMgr::create(AddrSpace* as, Instrumenter* inst, PointMaker* pf) {
88   patchapi_debug("Create PatchMgr");
89   PatchMgrPtr ret = PatchMgrPtr(new PatchMgr(as, inst, pf));
90   if (!ret) return PatchMgrPtr();
91   ret->as_->mgr_ = ret;
92   ret->pointMaker()->setMgr(ret);
93   return ret;
94 }
95
96 /* Return false if no point is found */
97 bool
98 PatchMgr::removeSnippet(InstancePtr instance) {
99   if (instance == InstancePtr()) return false;
100   return instance->destroy();
101 }
102
103 Point *PatchMgr::findPoint(Location loc,
104                            Point::Type type,
105                            bool create) {
106    // Verify an untrusted Location
107    if (!loc.trusted) {
108       if (!verify(loc)) return NULL;
109    }
110
111    // Not sure if it's better to go by type
112    // or location first, so we're running
113    // with type...
114    switch (type) {
115       case Point::PreInsn:
116       case Point::PostInsn:
117       case Point::BlockEntry:
118       case Point::BlockExit:
119       case Point::BlockDuring:
120          if (loc.func) {
121             return loc.func->findPoint(loc, type, create);
122          }
123          else {
124             if (!loc.block) return NULL;
125             return loc.block->findPoint(loc, type, create);
126          }
127          break;
128       case Point::PreCall:
129       case Point::PostCall:
130       case Point::FuncExit:
131          if (!loc.func || !loc.block) return NULL;
132          return loc.func->findPoint(loc, type, create);
133          break;
134       case Point::FuncEntry:
135       case Point::FuncDuring:
136          if (!loc.func) {
137             return NULL;
138          }
139          return loc.func->findPoint(loc, type, create);
140          break;
141       case Point::EdgeDuring:
142          if (loc.func) {
143             return loc.func->findPoint(loc, type, create);
144          }
145          else {
146             // Not doing generic edges yet...
147             return NULL;
148          }
149          break;
150          // These are unimplemented
151       case Point::LoopStart:
152       case Point::LoopEnd:
153       case Point::LoopIterStart:
154       case Point::LoopIterEnd:
155       default:
156          return NULL;
157    }
158 }
159
160 PatchMgr::~PatchMgr() {
161   patchapi_debug("Destroy PatchMgr");
162   delete as_;
163   delete point_maker_;
164   delete instor_;
165   
166 }
167
168 bool PatchMgr::getCandidates(Scope &scope,
169                              Point::Type types,
170                              Candidates &ret) {
171    // We hand in pre-generated lists to reduce the requirement for iteration
172    if (wantFuncs(scope, types)) getFuncCandidates(scope, types, ret);
173    if (wantCallSites(scope, types)) getCallSiteCandidates(scope, types, ret);
174    if (wantExitSites(scope, types)) getExitSiteCandidates(scope, types, ret);
175
176    if (wantBlocks(scope, types)) getBlockCandidates(scope, types, ret);
177    if (wantEdges(scope, types)) getEdgeCandidates(scope, types, ret);
178    if (wantInsns(scope, types)) getInsnCandidates(scope, types, ret);
179
180    if (wantBlockInstances(scope, types)) getBlockInstanceCandidates(scope, types, ret);
181    //if (wantEdgeInstances(scope, types)) getEdgeInstanceCandidates(scope, types, ret);
182    if (wantInsnInstances(scope, types)) getInsnInstanceCandidates(scope, types, ret);
183
184    return true;
185 }
186
187 bool PatchMgr::wantFuncs(Scope &scope, Point::Type types) {
188   return (Point::TestType(types, Point::FuncDuring) ||
189           (Point::TestType(types, Point::FuncEntry) &&
190            (scope.func || scope.obj || scope.wholeProgram)));
191 }
192
193 bool PatchMgr::wantCallSites(Scope &scope, Point::Type types) {
194   return (Point::TestType(types, Point::CallTypes) &&
195          (scope.func || scope.obj || scope.wholeProgram));
196 }
197
198 bool PatchMgr::wantExitSites(Scope &scope, Point::Type types) {
199   return (Point::TestType(types, Point::FuncExit) &&
200          (scope.func || scope.obj || scope.wholeProgram));
201 }
202
203 bool PatchMgr::wantBlocks(Scope &scope, Point::Type types) {
204   return (scope.func == NULL && Point::TestType(types, Point::BlockTypes));
205 }
206
207 bool PatchMgr::wantBlockInstances(Scope &scope, Point::Type types) {
208   return (scope.func != NULL && Point::TestType(types, Point::BlockTypes));
209 }
210
211 bool PatchMgr::wantEdges(Scope &scope, Point::Type types) {
212   return (scope.func == NULL && Point::TestType(types, Point::EdgeTypes));
213 }
214
215 bool PatchMgr::wantInsns(Scope &scope, Point::Type types) {
216   return (scope.func == NULL && Point::TestType(types, Point::InsnTypes));
217 }
218
219 bool PatchMgr::wantInsnInstances(Scope &scope, Point::Type types) {
220   return (scope.func != NULL && Point::TestType(types, Point::InsnTypes));
221 }
222
223 void PatchMgr::getFuncCandidates(Scope &scope, Point::Type types, Candidates &ret) {
224    // We can either have a scope of PatchObject and be looking for all
225    // the functions it contains, a scope of a Function, or be looking
226    // for every single function we know about.
227    Functions funcs;
228    getFuncs(scope, funcs);
229
230    for (Functions::iterator iter = funcs.begin(); iter != funcs.end(); ++iter) {
231       if (types & Point::FuncDuring) ret.push_back(Candidate(Location::Function(*iter), Point::FuncDuring));
232       if (types & Point::FuncEntry) ret.push_back(Candidate(Location::EntrySite(*iter, (*iter)->entry(), true), Point::FuncEntry));
233    }
234 }
235
236
237 void PatchMgr::getCallSiteCandidates(Scope &scope, Point::Type types, Candidates &ret) {
238    CallSites sites;
239    getCallSites(scope, sites);
240    for (CallSites::iterator iter = sites.begin(); iter != sites.end(); ++iter) {
241       if (types & Point::PreCall) ret.push_back(Candidate(Location::CallSite(*iter), Point::PreCall));
242       if (types & Point::PostCall) ret.push_back(Candidate(Location::CallSite(*iter), Point::PostCall));
243    }
244 }
245
246 void PatchMgr::getExitSiteCandidates(Scope &scope, Point::Type, Candidates &ret) {
247    ExitSites sites;
248    getExitSites(scope, sites);
249    for (ExitSites::iterator iter = sites.begin(); iter != sites.end(); ++iter) {
250       ret.push_back(Candidate(Location::ExitSite(*iter), Point::FuncExit));
251    }
252 }
253
254 void PatchMgr::getBlockCandidates(Scope &scope, Point::Type types, Candidates &ret) {
255    Blocks blocks;
256    getBlocks(scope, blocks);
257    for (Blocks::iterator iter = blocks.begin(); iter != blocks.end(); ++iter) {
258       if (types & Point::BlockEntry) ret.push_back(Candidate(Location::Block(*iter), Point::BlockEntry));
259       if (types & Point::BlockDuring) ret.push_back(Candidate(Location::Block(*iter), Point::BlockDuring));
260       if (types & Point::BlockExit) ret.push_back(Candidate(Location::Block(*iter), Point::BlockExit));
261    }
262 }
263
264 void PatchMgr::getEdgeCandidates(Scope &scope, Point::Type, Candidates &ret) {
265    Edges edges;
266    getEdges(scope, edges);
267    for (Edges::iterator iter = edges.begin(); iter != edges.end(); ++iter) {
268       ret.push_back(Candidate(Location::Edge(*iter), Point::EdgeDuring));
269    }
270 }
271
272 void PatchMgr::getInsnCandidates(Scope &scope, Point::Type types, Candidates &ret) {
273    Insns insns;
274    getInsns(scope, insns);
275    for (Insns::iterator iter = insns.begin(); iter != insns.end(); ++iter) {
276       if (types & Point::PreInsn) ret.push_back(Candidate(Location::Instruction(*iter), Point::PreInsn));
277       if (types & Point::PostInsn) ret.push_back(Candidate(Location::Instruction(*iter), Point::PostInsn));
278    }
279 }
280
281 void PatchMgr::getBlockInstanceCandidates(Scope &scope, Point::Type types, Candidates &ret) {
282    BlockInstances blocks;
283    getBlockInstances(scope, blocks);
284    for (BlockInstances::iterator iter = blocks.begin(); iter != blocks.end(); ++iter) {
285       if (types & Point::BlockEntry) ret.push_back(Candidate(Location::BlockInstance(iter->first, iter->second, true), Point::BlockEntry));
286       if (types & Point::BlockDuring) ret.push_back(Candidate(Location::BlockInstance(iter->first, iter->second, true), Point::BlockDuring));
287       if (types & Point::BlockExit) ret.push_back(Candidate(Location::BlockInstance(iter->first, iter->second, true), Point::BlockExit));
288    }
289 }
290
291 void PatchMgr::getInsnInstanceCandidates(Scope &scope, Point::Type types, Candidates &ret) {
292    InsnInstances insns;
293    getInsnInstances(scope, insns);
294    for (InsnInstances::iterator iter = insns.begin(); iter != insns.end(); ++iter) {
295       if (types & Point::PreInsn) ret.push_back(Candidate(Location::InstructionInstance(iter->first, iter->second, true), Point::PreInsn));
296       if (types & Point::PostInsn) ret.push_back(Candidate(Location::InstructionInstance(iter->first, iter->second, true), Point::PostInsn));
297    }
298 }
299
300 void PatchMgr::getFuncs(Scope &scope, Functions &funcs) {
301    if (scope.wholeProgram) {
302       AddrSpace::ObjMap &objs = as()->objMap();
303       for (AddrSpace::ObjMap::iterator iter = objs.begin(); iter != objs.end(); ++iter) {
304          iter->second->funcs(std::back_inserter(funcs));
305       }
306    }
307    else if (scope.obj) {
308       scope.obj->funcs(std::back_inserter(funcs));
309    }
310    else if (scope.func) {
311       funcs.push_back(scope.func);
312    }
313 }
314
315 void PatchMgr::getCallSites(Scope &scope, CallSites &sites) {
316    // All sites in whatever functions we want
317    Functions funcs;
318    getFuncs(scope, funcs);
319    for (Functions::iterator iter = funcs.begin(); iter != funcs.end(); ++iter) {
320       const PatchFunction::Blockset &c = (*iter)->callBlocks();
321       for (PatchFunction::Blockset::const_iterator iter2 = c.begin(); iter2 != c.end(); ++iter2) {
322          if (!scope.block || (scope.block == *iter2))
323             sites.push_back(CallSite_t(*iter, *iter2));
324       }
325    }
326 }
327
328 void PatchMgr::getExitSites(Scope &scope, ExitSites &sites) {
329    // All sites in whatever functions we want
330    Functions funcs;
331    getFuncs(scope, funcs);
332    for (Functions::iterator iter = funcs.begin(); iter != funcs.end(); ++iter) {
333       const PatchFunction::Blockset &e = (*iter)->exitBlocks();
334       for (PatchFunction::Blockset::const_iterator iter2 = e.begin(); iter2 != e.end(); ++iter2) {
335          if (!scope.block || (scope.block == *iter2))
336             sites.push_back(ExitSite_t(*iter, *iter2));
337       }
338    }
339 }
340
341 void PatchMgr::getBlocks(Scope &scope, Blocks &blocks) {
342    if (scope.wholeProgram) {
343       const AddrSpace::ObjMap &objs = as()->objMap();
344       for (AddrSpace::ObjMap::const_iterator iter = objs.begin(); iter != objs.end(); ++iter) {
345          iter->second->blocks(std::back_inserter(blocks));
346       }
347    }
348    else if (scope.obj) {
349       scope.obj->blocks(std::back_inserter(blocks));
350    }
351    else if (scope.block) {
352       blocks.push_back(scope.block);
353    }
354 }
355
356 void PatchMgr::getEdges(Scope &scope, Edges &edges) {
357    if (scope.wholeProgram) {
358       const AddrSpace::ObjMap &objs = as()->objMap();
359       for (AddrSpace::ObjMap::const_iterator iter = objs.begin(); iter != objs.end(); ++iter) {
360          iter->second->edges(std::back_inserter(edges));
361       }
362    }
363    else if (scope.obj) {
364       scope.obj->edges(std::back_inserter(edges));
365    }
366 }
367
368 void PatchMgr::getInsns(Scope &scope, Insns &insns) {
369    Blocks blocks;
370    getBlocks(scope, blocks);
371
372    for (Blocks::iterator iter = blocks.begin(); iter != blocks.end(); ++iter) {
373       PatchBlock::Insns tmp;
374       (*iter)->getInsns(tmp);
375       for (PatchBlock::Insns::iterator t = tmp.begin(); t != tmp.end(); ++t) {
376          insns.push_back(InsnLoc_t(*iter, t->first, t->second));
377       }
378    }
379 }
380
381 void PatchMgr::getBlockInstances(Scope &scope, BlockInstances &blocks) {
382    Functions funcs;
383    getFuncs(scope, funcs);
384
385    for (Functions::iterator iter = funcs.begin(); iter != funcs.end(); ++iter) {
386       const PatchFunction::Blockset &b = (*iter)->blocks();
387       for (PatchFunction::Blockset::const_iterator iter2 = b.begin(); iter2 != b.end(); ++iter2) {
388          // TODO FIXME: make this more efficient to avoid iunnecessary iteration
389          if (scope.block && scope.block != *iter2) continue;
390          blocks.push_back(BlockInstance(*iter, *iter2));
391       }
392    }
393 }
394
395 void PatchMgr::getInsnInstances(Scope &scope, InsnInstances &insns) {
396    Functions funcs;
397    getFuncs(scope, funcs);
398
399    for (Functions::iterator iter = funcs.begin(); iter != funcs.end(); ++iter) {
400       const PatchFunction::Blockset &b = (*iter)->blocks();
401       for (PatchFunction::Blockset::const_iterator iter2 = b.begin(); iter2 != b.end(); ++iter2) {
402          // TODO FIXME: make this more efficient to avoid iunnecessary iteration
403          if (scope.block && scope.block != *iter2) continue;
404          PatchBlock::Insns i;
405          (*iter2)->getInsns(i);
406          for (PatchBlock::Insns::iterator iter3 = i.begin(); iter3 != i.end(); ++iter3) {
407             insns.push_back(InsnInstance(*iter, InsnLoc_t(*iter2, iter3->first, iter3->second)));
408          }
409       }
410    }
411 }
412
413
414 void PatchMgr::enumerateTypes(Point::Type types, EnumeratedTypes &out) {
415    for (unsigned i = 0; i <= 31; ++i) {
416       Point::Type tmp = (Point::Type) type_val(i);
417       if (types & tmp) out.push_back(tmp);
418    }
419 };
420
421
422 void PatchMgr::destroy(Point *p) {
423    p->obj()->cb()->destroy(p);
424 }
425
426 bool PatchMgr::verify(Location &loc) {
427    if (loc.trusted) return true;
428
429    switch (loc.type) {
430       case Location::Function_:
431          break;
432       case Location::Block_:
433          break;
434       case Location::BlockInstance_:
435          if (loc.func->blocks().find(loc.block) == loc.func->blocks().end()) return false;
436          break;
437       case Location::InstructionInstance_:
438          if (loc.func->blocks().find(loc.block) == loc.func->blocks().end()) return false;
439          // Fall through to Instruction_ case for detailed checking.
440       case Location::Instruction_:
441          if (loc.addr < loc.block->start()) return false;
442          if (loc.addr > loc.block->last()) return false;
443          loc.insn = loc.block->getInsn(loc.addr);
444          if (!loc.insn) return false;
445          break;
446       case Location::Edge_:
447          break;
448       case Location::EdgeInstance_:
449          if (loc.func->blocks().find(loc.edge->src()) == loc.func->blocks().end()) return false;
450          if (loc.func->blocks().find(loc.edge->trg()) == loc.func->blocks().end()) return false;
451          break;
452       case Location::Entry_:
453          if (loc.func->entry() != loc.block) return false;
454          break;
455       case Location::Call_:
456          // Check to see if the block is in the call blocks
457          if (loc.func->callBlocks().find(loc.block) == loc.func->callBlocks().end()) return false;
458          break;
459       case Location::Exit_:
460          if (loc.func->exitBlocks().find(loc.block) == loc.func->exitBlocks().end()) return false;
461          break;
462       default:
463          assert(0);
464          return true;
465    }
466    loc.trusted = true;
467    return true;
468
469 }
470
471 bool PatchMgr::consistency() const {
472    if (!point_maker_) return false;
473    if (!instor_) return false;
474    if (!as_) return false;
475    return (as_->consistency(this));
476 }
477