Brought Dyninst API up to date with latest changes in Paradyn.
[dyninst.git] / dyninstAPI / src / inst.C
1 /*
2  * Copyright (c) 1996 Barton P. Miller
3  * 
4  * We provide the Paradyn Parallel Performance Tools (below
5  * described as Paradyn") on an AS IS basis, and do not warrant its
6  * validity or performance.  We reserve the right to update, modify,
7  * or discontinue this software at any time.  We shall have no
8  * obligation to supply such updates or modifications or any other
9  * form of support to you.
10  * 
11  * This license is for research uses.  For such uses, there is no
12  * charge. We define "research use" to mean you may freely use it
13  * inside your organization for whatever purposes you see fit. But you
14  * may not re-distribute Paradyn or parts of Paradyn, in any form
15  * source or binary (including derivatives), electronic or otherwise,
16  * to any other organization or entity without our permission.
17  * 
18  * (for other uses, please contact us at paradyn@cs.wisc.edu)
19  * 
20  * All warranties, including without limitation, any warranty of
21  * merchantability or fitness for a particular purpose, are hereby
22  * excluded.
23  * 
24  * By your use of Paradyn, you understand and agree that we (or any
25  * other person or entity with proprietary rights in Paradyn) are
26  * under no obligation to provide either maintenance services,
27  * update services, notices of latent defects, or correction of
28  * defects for Paradyn.
29  * 
30  * Even if advised of the possibility of such damages, under no
31  * circumstances shall we (or any other person or entity with
32  * proprietary rights in the software licensed hereunder) be liable
33  * to you or any third party for direct, indirect, or consequential
34  * damages of any character regardless of type of action, including,
35  * without limitation, loss of profits, loss of use, loss of good
36  * will, or computer failure or malfunction.  You agree to indemnify
37  * us (and any other person or entity with proprietary rights in the
38  * software licensed hereunder) for any and all liability it may
39  * incur to third parties resulting from your use of Paradyn.
40  */
41
42 /*
43  * inst.C - Code to install and remove inst funcs from a running process.
44  */
45
46 #include <assert.h>
47 //#include <sys/signal.h>
48 //#include <sys/param.h>
49
50
51 #include "dyninstAPI/src/symtab.h"
52 #include "dyninstAPI/src/process.h"
53 #include "dyninstAPI/src/inst.h"
54 #include "dyninstAPI/src/instP.h"
55 #include "dyninstAPI/src/ast.h"
56 #include "dyninstAPI/src/util.h"
57 #include "dyninstAPI/src/stats.h"
58 #include "paradynd/src/showerror.h"
59
60 dictionary_hash <string, unsigned> primitiveCosts(string::hash);
61
62 #if defined(rs6000_ibm_aix4_1)
63   extern void resetBRL(process *p, unsigned loc, unsigned val); //inst-power.C
64   extern void resetBR( process *p, unsigned loc);               //inst-power.C
65 #endif
66
67
68 // get the address of the branch from the base to the minitramp
69 int getBaseBranchAddr(process *, instInstance *inst)
70 {
71     int fromAddr;
72
73     fromAddr = (int) inst->baseInstance->baseAddr;
74     if (inst->when == callPreInsn) {
75         fromAddr += inst->baseInstance->localPreOffset;
76     } else {
77         fromAddr += inst->baseInstance->localPostOffset;
78     }
79     return(fromAddr);
80 }
81
82 // get the address in the base tramp where the minitramp should return to
83 int getBaseReturnAddr(process *, instInstance *inst) {
84     int returnAddr = (int)inst->baseInstance->baseAddr;
85     if (inst->when == callPreInsn) {
86       returnAddr += inst->baseInstance->localPreReturnOffset;
87     } else {
88       returnAddr += inst->baseInstance->localPostReturnOffset;
89     }
90     return(returnAddr);
91 }
92
93 // clear the basetramp jump to a minitramp
94 void clearBaseBranch(process *proc, instInstance *inst)
95 {
96     int addr;
97
98     addr = (int) inst->baseInstance->baseAddr;
99     if (inst->when == callPreInsn) {
100         addr += inst->baseInstance->localPreOffset;
101     } else {
102         addr += inst->baseInstance->localPostOffset;
103     }
104     // stupid kludge because the instPoint class is defined in a .C file
105     // so we can't access any of its member functions
106 #if defined(rs6000_ibm_aix4_1)
107     resetBRL(proc, addr, 0);
108 #else
109     generateNoOp(proc, addr);
110 #endif
111     // If there is no instrumentation at this point, skip.
112     unsigned fromAddr, toAddr;
113
114     int trampCost;
115     if (inst->when == callPreInsn) {
116       fromAddr = inst->baseInstance->baseAddr + 
117                  (unsigned)inst->baseInstance->skipPreInsOffset;
118       toAddr = inst->baseInstance->baseAddr + 
119 #if defined(rs6000_ibm_aix4_1)
120                (unsigned)inst->baseInstance->emulateInsOffset;
121 #else
122                (unsigned)inst->baseInstance->updateCostOffset;
123 #endif
124       inst->baseInstance->prevInstru = false;
125       trampCost = -(inst->baseInstance->prevBaseCost);
126     }
127     else {
128       fromAddr = inst->baseInstance->baseAddr + 
129                  (unsigned)inst->baseInstance->skipPostInsOffset; 
130       toAddr = inst->baseInstance->baseAddr + 
131                (unsigned)inst->baseInstance->returnInsOffset;
132       inst->baseInstance->postInstru = false;
133       trampCost = -(inst->baseInstance->postBaseCost);
134     }
135     inst->baseInstance->updateTrampCost(proc, trampCost);
136     generateBranch(proc,fromAddr,toAddr);
137 #if defined(MT_DEBUG)
138     sprintf(errorLine,"generating branch from address 0x%x to address 0x%x - CLEAR\n",fromAddr,toAddr);
139     logLine(errorLine);
140 #endif
141 }
142
143 // implicit assumption that tramps generate to less than 64K bytes!!!
144 static int insn[65536/sizeof(int)]; // Made into array of int so it would be
145                                     // aligned correctly on platoforms that
146                                     // need it to be (like SPARC) - BRB
147
148 static dictionary_hash<const instPoint*, point*> activePoints(ipHash);
149
150 vector<instWaitingList *> instWList;
151
152 // Shouldn't this be a member fn of class process?
153 instInstance *addInstFunc(process *proc, instPoint *&location,
154                           AstNode *&ast, // ast may change (sysFlag stuff)
155                           callWhen when, callOrder order,
156                           bool noCost)
157 {
158     returnInstance *retInstance = NULL;
159        // describes how to jmp to the base tramp
160
161     instInstance *inst = addInstFunc(proc, location, ast, when, order,
162                                      noCost, retInstance);
163     if (retInstance) {
164        // Looking at the code for the other addInstFunc below, it seems that
165        // this will always be true...retInstance is never NULL.
166
167        retInstance-> installReturnInstance(proc);
168        // writes to addr space
169     }
170
171     // delete retInstance; 
172     // safe if NULL (may have been alloc'd by findAndInstallBaseTramp)
173
174     return inst;
175 }
176
177 // Shouldn't this be a member fn of class process?
178 instInstance *addInstFunc(process *proc, instPoint *&location,
179                           AstNode *&ast, // the ast could be changed 
180                           callWhen when, callOrder order,
181                           bool noCost,
182                           returnInstance *&retInstance)
183 {
184     // retInstance gets filled in with info on how to jmp to the base tramp
185     // (the call to findAndInstallBaseTramp doesn't do that)
186
187     assert(proc && location);
188     initTramps();
189
190     instInstance *ret = new instInstance;
191     assert(ret);
192
193     ret->proc = proc;
194     ret->baseInstance = findAndInstallBaseTramp(proc, location, retInstance, 
195                                                 noCost);
196     if (!ret->baseInstance)
197        return(NULL);
198
199 #if defined(MT_DEBUG_ON)
200     sprintf(errorLine,"==>BaseTramp is in 0x%x\n",ret->baseInstance->baseAddr);
201     logLine(errorLine);
202 #endif
203
204     /* check if there are other inst points at this location. for this process
205        at the same pre/post mode */
206     instInstance *firstAtPoint = NULL;
207     instInstance *lastAtPoint = NULL;
208
209     point *thePoint;
210     if (!activePoints.find((const instPoint *)location, thePoint)) {
211        thePoint = new point;
212        activePoints[(const instPoint*)location] = thePoint;
213     }
214     
215 //    point *thePoint;
216 //    if (!activePoints.defines((const instPoint *)location)) {
217 //      thePoint = new point;
218 //      activePoints[(const instPoint*)location] = thePoint;
219 //    } else
220 //      thePoint = activePoints[(const instPoint*)location];
221 //    assert(thePoint);
222
223     instInstance *next;
224     for (next = thePoint->inst; next; next = next->next) {
225         if ((next->proc == proc) && (next->when == when)) {
226             if (!next->nextAtPoint) lastAtPoint = next;
227             if (!next->prevAtPoint) firstAtPoint = next;
228         }
229     }
230
231     // must do this before findAndInstallBaseTramp, puts the tramp in to
232     // get the correct cost.
233     // int trampCost = getPointCost(proc, (const instPoint*)location);
234
235     // 
236     // Generate the code for this (mini-)tramp.
237     //
238     // return value is offset of return stmnt.
239     //
240
241 #if defined(MEMSET)
242     // clear out old stuff - for debugging.
243     memset(insn, 0x00, 65536);
244 #endif
245
246     u_int count = 0;
247
248 #if defined(sparc_sun_sunos4_1_3) || defined(sparc_sun_solaris2_4)     
249     ast->sysFlag((instPoint*)location);  
250
251     // If the return value is in the case of compiler optimization,
252     // modify the ast node tree to insert an instruction to get the 
253     // return the value
254     extern bool processOptimaRet(instPoint *location, AstNode *&ast);
255     bool isOpt = processOptimaRet(location, ast);
256 #endif
257
258     int trampCost = 0;
259     ret->returnAddr = ast->generateTramp(proc, (char *)insn, count, trampCost, noCost);
260
261 #if defined(sparc_sun_sunos4_1_3) || defined(sparc_sun_solaris2_4)
262     // The ast node might be shared, so remove the changes made to
263     // ast node tree  
264     if (isOpt)
265         ast->optRetVal(NULL); 
266 #endif
267
268     if (!noCost) {
269         ret->cost = trampCost; 
270         ret->baseInstance->updateTrampCost(proc, trampCost);
271     }
272 #if defined(rs6000_ibm_aix4_1)
273     ret->trampBase = inferiorMalloc(proc, count, dataHeap);
274 #else
275     ret->trampBase = inferiorMalloc(proc, count, textHeap);
276 #endif
277     assert(ret->trampBase);
278
279     if (!ret->trampBase) return(NULL);
280     trampBytes += count;
281     ret->returnAddr += ret->trampBase;
282
283     ret->when = when;
284     ret->location = (instPoint*)location;
285
286     ret->next = thePoint->inst;
287     ret->prev = NULL;
288     if (thePoint->inst) thePoint->inst->prev = ret;
289     thePoint->inst = ret;
290
291     /*
292      * Now make the call to actually put the code in place.
293      *
294      */
295     installTramp(ret, (char *)insn, count); // install mini-tramp into inferior addr space
296
297     if (!lastAtPoint) {
298         // jump from the base tramp to the minitramp
299         unsigned fromAddr = getBaseBranchAddr(proc, ret);
300 #if defined(rs6000_ibm_aix4_1)
301         resetBRL(proc, fromAddr, ret->trampBase);
302 #else
303         generateBranch(proc, fromAddr, ret->trampBase);
304 #endif
305
306         // jump from the minitramp back to the basetramp
307 #if defined(rs6000_ibm_aix4_1)
308         resetBR(proc, ret->returnAddr);
309 #else
310         unsigned toAddr = getBaseReturnAddr(proc, ret);
311         generateBranch(proc, ret->returnAddr, toAddr);
312 #endif
313
314         // just activated this slot.
315         //activeSlots->value += 1.0;
316     } else if (order == orderLastAtPoint) {
317         /* patch previous tramp to call us rather than return */
318         generateBranch(proc,lastAtPoint->returnAddr,ret->trampBase);
319         lastAtPoint->nextAtPoint = ret;
320         ret->prevAtPoint = lastAtPoint;
321         
322         // jump from the minitramp to the basetramp
323 #if defined(rs6000_ibm_aix4_1)
324         resetBR(proc, ret->returnAddr);
325 #else
326         unsigned toAddr = getBaseReturnAddr(proc, ret);
327         generateBranch(proc, ret->returnAddr, toAddr);
328 #endif
329     } else {
330         /* first at point */
331         firstAtPoint->prevAtPoint = ret;
332         ret->nextAtPoint = firstAtPoint;
333
334         /* branch to the old first one */
335         generateBranch(proc, ret->returnAddr, firstAtPoint->trampBase);
336
337         /* base tramp branches to us */
338         unsigned fromAddr = getBaseBranchAddr(proc, ret);
339 #if defined(rs6000_ibm_aix4_1)
340         resetBRL(proc, fromAddr, ret->trampBase);
341 #else
342         generateBranch(proc, fromAddr, ret->trampBase);
343 #endif
344     }
345
346     return(ret);
347 }
348
349 //
350 // copyInstInstances: called when a process we are tracing forks.
351 // The child will have a copy of all instrumentation in the parent, so we
352 // must duplicate all instInstances of the parent for the child.
353 // 
354 // On return, for each active instInstance parentInst in the parent
355 // instInstanceMapping[parentInst] will be the corresponding instInstance for the
356 // child.
357 //
358
359 void getAllInstInstancesForProcess(const process *proc,
360                                    vector<instInstance*> &result) {
361     vector<point*> allPoints = activePoints.values();
362  
363     // find all instInstances of the parent process
364     for (unsigned u = 0; u < allPoints.size(); u++) {
365       for (instInstance *inst = allPoints[u]->inst; inst; inst = inst->next) {
366         if (inst->proc == proc)
367           result += inst;
368       }
369     }
370 }
371
372 void copyInstInstances(const process *parent, const process *child, 
373             dictionary_hash<instInstance *, instInstance *> &instInstanceMapping)
374 {
375     vector<instInstance*> instsToCopy;
376     getAllInstInstancesForProcess(parent, instsToCopy);
377  
378     // duplicate the parent instance for the child, and define instMapping
379     vector<instInstance *>newInsts;
380     for (unsigned u1 = 0; u1 < instsToCopy.size(); u1++) {
381       instInstance *old = instsToCopy[u1];
382       instInstance *newInst = new instInstance;
383       newInst->proc = (process *)child;
384       newInst->when = old->when;
385       newInst->location = old->location;
386       newInst->trampBase = old->trampBase;
387       newInst->returnAddr = old->returnAddr;
388       newInst->baseInstance = old->baseInstance;
389       newInst->cost = old->cost;
390       instInstanceMapping[old] = newInst;
391       newInsts += newInst;
392     }
393
394     // update nextAtPoint and prevAtPoint
395     for (unsigned u2 = 0; u2 < newInsts.size(); u2++) {
396       instInstance *newInst = newInsts[u2];
397       instInstance *old = instsToCopy[u2];
398       newInst->nextAtPoint = instInstanceMapping[old->nextAtPoint];
399       newInst->prevAtPoint = instInstanceMapping[old->prevAtPoint];
400
401       assert(activePoints.defines(newInst->location));
402       point *thePoint = activePoints[newInst->location];
403       newInst->next = thePoint->inst;
404       newInst->prev = NULL;
405       if (thePoint->inst) thePoint->inst->prev = newInst;
406       thePoint->inst = newInst;
407     }
408 }
409
410 // This procedure assumes that any mini-tramp for an inst request could refer 
411 // to any data pointer for that request. A more complex analysis could check 
412 // what data pointers each mini-tramp really used, but I don't think it is 
413 // worth the trouble.
414 //
415 vector<unsigned> getAllTrampsAtPoint(instInstance *instance)
416 {
417     vector<unsigned> pointsToCheck;
418     instInstance *start;
419     instInstance *next;
420     point *thePoint;
421
422     if (instance) {
423       if (activePoints.defines(instance->location)) {
424         thePoint = activePoints[instance->location];
425         start = thePoint->inst;
426         // Base tramp
427         pointsToCheck += start->baseInstance->baseAddr; 
428         pointsToCheck += start->trampBase;
429         // All mini-tramps at this point
430         for (next = start->next; next; next = next->next) {
431           if ((next->location == instance->location) && 
432               (next->proc == instance->proc) &&
433               (next->when == instance->when)) {
434               if (next != instance) {
435                 pointsToCheck += start->trampBase;
436               }
437           }
438         }
439       }
440     }
441     return(pointsToCheck);
442 }
443
444 /*
445  * The tramps are chained together left to right, so we need to find the
446  *    tramps to the left anf right of the one to delete, and then patch the
447  *    call from the left one to the old to call the right one.
448  *    Also we need to patch the return from the right one to go to the left
449  *    one.
450  *
451  */
452 void deleteInst(instInstance *old, const vector<unsigned> &pointsToCheck)
453 {
454     point *thePoint;
455     instInstance *lag;
456     instInstance *left;
457     instInstance *right;
458     instInstance *othersAtPoint;
459
460     if (!old) {
461       logLine("Internal error in inst.C: instInstance pointer \"old\" is NULL\n");
462       return;
463     }
464
465     /* check if there are other inst points at this location. */
466     othersAtPoint = NULL;
467     left = right = NULL;
468
469     if (!activePoints.defines(old->location)) {
470       abort();
471     }
472     thePoint = activePoints[old->location];
473
474     for (lag= thePoint->inst; lag; lag = lag->next) {
475         if ((lag->location == old->location) && 
476             (lag->proc == old->proc) &&
477             (lag->when == old->when)) {
478             if (lag != old) {
479                 othersAtPoint = lag;
480                 left = old->prevAtPoint;
481                 right = old->nextAtPoint;
482                 assert(right || left);
483             }
484         }
485     }
486
487   if (old->proc->status() != exited) {
488     if (!othersAtPoint) {
489         clearBaseBranch(old->proc, old);
490         //activeSlots->value -= 1.0;
491     } else {
492         if (left) {
493             if (right) {
494                 /* set left's return insn to branch to tramp to the right */
495                 generateBranch(old->proc, left->returnAddr, right->trampBase);
496             } else {
497                 /* branch back to the correct point in the base tramp */
498 #if defined(rs6000_ibm_aix4_1)
499                 resetBR(old->proc, left->returnAddr);
500 #else
501                 unsigned toAddr = getBaseReturnAddr(old->proc, old);
502                 generateBranch(old->proc, left->returnAddr, toAddr);
503 #endif
504             }
505         } else {
506             /* old is first one make code call right tramp */
507             int fromAddr;
508             fromAddr = getBaseBranchAddr(old->proc, right);
509 #if defined(rs6000_ibm_aix4_1)
510             resetBRL(old->proc, fromAddr, right->trampBase);
511 #else
512             generateBranch(old->proc, fromAddr, right->trampBase);
513 #endif
514         }
515     }
516
517     vector<unsigVecType> tmp;
518     tmp += (unsigVecType) pointsToCheck;
519
520 #ifdef FREEDEBUG1
521     sprintf(errorLine,"***** (pid=%d) In inst.C, calling inferiorFree, pointer=0x%x\n",old->proc->pid,old->trampBase);
522     logLine(errorLine);
523 #endif
524 #if defined(rs6000_ibm_aix4_1)
525     inferiorFree(old->proc, old->trampBase, dataHeap, tmp);
526 #else
527     inferiorFree(old->proc, old->trampBase, textHeap, tmp);
528 #endif
529   }
530
531     /* remove old from atPoint linked list */
532     if (right) right->prevAtPoint = left;
533     if (left) left->nextAtPoint = right;
534
535     /* remove from doubly linked list for all insts */
536     if (old->prev) {
537         lag = old->prev;
538         lag->next = old->next;
539         if (old->next) old->next->prev = lag;
540     } else {
541         thePoint->inst = old->next;
542         if (old->next) old->next->prev = NULL;
543     }
544     int trampCost = 0-old->cost;
545     old->baseInstance->updateTrampCost(old->proc, trampCost);
546
547     delete old;
548
549     //free(old);
550 }
551
552 //
553 // Routine that checks whether a particular address is valid before deleting
554 // the corresponding instrumentation associated to it.
555 //
556 bool isValidAddress(process * , Address )
557 {
558   bool result=true;
559   //
560   // Note: It seems that it is not necessary to do this step. In any case,
561   // calling "proc->symbols->isValidAddress(where)" usually returns false
562   // even for cases when the address looks ok. If it is required to have
563   // such a routine, we will have to figure out a better one. An idea
564   // could be to get the address for "start" and length of the code and
565   // make sure that the address "where" is between those two values (that's
566   // what gdb goes for sparcs) - naim
567   // 
568
569 #ifdef FREEDEBUG
570   if (!result) {
571     sprintf(errorLine,"==> TEST <== isValidAddress is FALSE\n");
572     logLine(errorLine);
573   }
574 #endif
575
576   return(result);
577 }
578
579
580 /*
581  * return the time required to execute the passed primitive.
582  *
583  */
584 unsigned getPrimitiveCost(const string &name)
585 {
586
587     static bool init=false;
588
589     if (!init) { init = 1; initPrimitiveCost(); }
590
591     if (!primitiveCosts.defines(name)) {
592       return 1;
593     } else
594       return (primitiveCosts[name]);
595 }
596
597
598 // find any tags to associate semantic meaning to function
599 unsigned findTags(const string ) {
600   return 0;
601 #ifdef notdef
602   if (tagDict.defines(funcName))
603     return (tagDict[funcName]);
604   else
605     return 0;
606 #endif
607 }
608
609
610 void
611 trampTemplate::updateTrampCost(process *proc, int trampCost) {
612     
613     int caddr;
614     cost = cost + trampCost;
615     if (cost < 0) cost = 0;
616
617     char costInsn[40];
618     unsigned csize = 0;
619
620     // quick dirty hack; Will be changed soon so that we 
621     // don't call getObservedCostAddr() every time  --ling  
622     proc->getObservedCostAddr();   
623     caddr = proc->costAddr(); 
624
625     emit(updateCostOp, cost, 0, caddr, costInsn, csize, false);
626     proc->writeDataSpace((caddr_t)costAddr, csize, costInsn);
627 }
628
629 void cleanInstFromActivePoints(process *proc)
630 {
631     assert(proc);
632     vector<point*> allPoints = activePoints.values();
633  
634     // is it ok to have activePoints elements with empty points? - naim
635     for (unsigned u = 0; u < allPoints.size(); u++) {
636       instInstance *inst = allPoints[u]->inst;
637       while (inst) {
638         assert(inst->proc);
639         if (inst->proc->getPid() == proc->getPid()) {
640           if (!inst->prev) {
641             // this is the first one on the list
642             if (!inst->next) {
643               // this is the only one on the list
644               delete inst;
645               allPoints[u]->inst = NULL;
646               inst = NULL;
647             } else {
648               inst->next->prev = NULL;
649               allPoints[u]->inst = inst->next;
650               delete inst;
651               inst = allPoints[u]->inst;
652             }
653           } else {
654             // this is not the first one
655             if (!inst->next) {
656               // this is the last one
657               inst->prev->next = NULL;
658               delete inst;
659               inst = NULL;
660             } else {
661               // we are somewhere in the middle of the list
662               inst->prev->next = inst->next;
663               inst->next->prev = inst->prev;
664               instInstance *next_inst = inst->next;
665               delete inst;
666               inst = next_inst;
667             }
668           }
669         } else {
670           inst = inst->next;
671         }
672       }
673     }
674 }