changes to support changing the sampling rate: dynRPC::setSampleRate changes
[dyninst.git] / dyninstAPI / src / inst.C
1 /*
2  *  Copyright 1993 Jeff Hollingsworth.  All rights reserved.
3  *
4  */
5
6 #ifndef lint
7 static char Copyright[] = "@(#) Copyright (c) 1993 Jeff Hollingsowrth\
8     All rights reserved.";
9
10 static char rcsid[] = "@(#) $Header: /home/jaw/CVSROOT_20081103/CVSROOT/core/dyninstAPI/src/inst.C,v 1.21 1995/11/03 00:06:08 newhall Exp $";
11 #endif
12
13
14 /*
15  * inst.C - Code to install and remove inst funcs from a running process.
16  *
17  * $Log: inst.C,v $
18  * Revision 1.21  1995/11/03 00:06:08  newhall
19  * changes to support changing the sampling rate: dynRPC::setSampleRate changes
20  *     the value of DYNINSTsampleMultiple, implemented image::findInternalSymbol
21  * fix so that SIGKILL is not being forwarded to CM5 applications.
22  *
23  * Revision 1.20  1995/10/26  21:06:37  tamches
24  * removed some warnings
25  *
26  * Revision 1.19  1995/09/26 20:17:48  naim
27  * Adding error messages using showErrorCallback function for paradynd
28  *
29  * Revision 1.18  1995/08/24  15:04:05  hollings
30  * AIX/SP-2 port (including option for split instruction/data heaps)
31  * Tracing of rexec (correctly spawns a paradynd if needed)
32  * Added rtinst function to read getrusage stats (can now be used in metrics)
33  * Critical Path
34  * Improved Error reporting in MDL sematic checks
35  * Fixed MDL Function call statement
36  * Fixed bugs in TK usage (strings passed where UID expected)
37  *
38  * Revision 1.17  1995/08/05  17:15:28  krisna
39  * deleted redundant AND WRONG definition of ipHash
40  *
41  * Revision 1.16  1995/05/18  10:36:42  markc
42  * removed tag dictionary
43  *
44  * Revision 1.15  1995/03/10  19:33:51  hollings
45  * Fixed several aspects realted to the cost model:
46  *     track the cost of the base tramp not just mini-tramps
47  *     correctly handle inst cost greater than an imm format on sparc
48  *     print starts at end of pvm apps.
49  *     added option to read a file with more accurate data for predicted cost.
50  *
51  * Revision 1.14  1995/02/16  08:53:33  markc
52  * Corrected error in comments -- I put a "star slash" in the comment.
53  *
54  * Revision 1.13  1995/02/16  08:33:30  markc
55  * Changed igen interfaces to use strings/vectors rather than char igen-arrays
56  * Changed igen interfaces to use bool, not Boolean.
57  * Cleaned up symbol table parsing - favor properly labeled symbol table objects
58  * Updated binary search for modules
59  * Moved machine dependnent ptrace code to architecture specific files.
60  * Moved machine dependent code out of class process.
61  * Removed almost all compiler warnings.
62  * Use "posix" like library to remove compiler warnings
63  *
64  * Revision 1.12  1994/11/09  18:40:12  rbi
65  * the "Don't Blame Me" commit
66  *
67  * Revision 1.11  1994/11/02  11:08:28  markc
68  * Moved redundant code to here from inst-< >.C.
69  *
70  * Revision 1.10  1994/09/30  19:47:07  rbi
71  * Basic instrumentation for CMFortran
72  *
73  * Revision 1.9  1994/09/22  02:00:02  markc
74  * Changed *allocs to news
75  * cast stringHandles for printing
76  * cast args to PCptrace
77  *
78  * Revision 1.8  1994/08/17  18:13:31  markc
79  * Changed variable names in installDefaultInst to quiet compiler warnings.
80  * Added reachedFirstBreak check to avoid stopping processes that have yet
81  * to reach their initial SIGSTOP.
82  *
83  * Revision 1.7  1994/07/28  22:40:39  krisna
84  * changed definitions/declarations of xalloc functions to conform to alloc.
85  *
86  * Revision 1.6  1994/07/20  23:23:36  hollings
87  * added insn generated metric.
88  *
89  * Revision 1.5  1994/07/12  19:48:46  jcargill
90  * Added warning for functions not found in initialRequests set
91  *
92  * Revision 1.4  1994/06/29  02:52:30  hollings
93  * Added metricDefs-common.{C,h}
94  * Added module level performance data
95  * cleanedup types of inferrior addresses instrumentation defintions
96  * added firewalls for large branch displacements due to text+data over 2meg.
97  * assorted bug fixes.
98  *
99  * Revision 1.3  1994/06/27  18:56:51  hollings
100  * removed printfs.  Now use logLine so it works in the remote case.
101  * added internalMetric class.
102  * added extra paramter to metric info for aggregation.
103  *
104  * Revision 1.2  1994/03/20  01:53:08  markc
105  * Added a buffer to each process structure to allow for multiple writers on the
106  * traceStream.  Replaced old inst-pvm.C.  Changed addProcess to return type
107  * int.
108  *
109  * Revision 1.1  1994/01/27  20:31:24  hollings
110  * Iinital version of paradynd speaking dynRPC igend protocol.
111  *
112  * Revision 1.13  1993/12/15  21:02:42  hollings
113  * added PVM support.
114  *
115  * Revision 1.12  1993/12/13  19:54:59  hollings
116  * count operations.
117  *
118  * Revision 1.11  1993/10/19  15:27:54  hollings
119  * AST based mini-tramp code generator.
120  *
121  * Revision 1.10  1993/10/04  21:37:10  hollings
122  * re-enabled inst ordering directives.
123  *
124  * Revision 1.10  1993/10/04  21:37:10  hollings
125  * re-enabled inst ordering directives.
126  *
127  * Revision 1.9  1993/10/01  21:29:41  hollings
128  * Added resource discovery and filters.
129  *
130  * Revision 1.8  1993/08/23  23:11:19  hollings
131  * fixed removing tramps to work correctly.
132  *
133  * Revision 1.7  1993/08/11  01:31:57  hollings
134  * fixed call noargs & with args to be more general.
135  *
136  * Revision 1.6  1993/07/13  18:28:19  hollings
137  * new include file syntax.
138  *
139  * Revision 1.5  1993/06/28  23:13:18  hollings
140  * fixed process stopping.
141  *
142  * Revision 1.4  1993/06/24  16:18:06  hollings
143  * global fixes.
144  *
145  * Revision 1.3  1993/06/22  19:00:01  hollings
146  * global inst state.
147  *
148  * Revision 1.2  1993/06/08  20:14:34  hollings
149  * state prior to bc net ptrace replacement.
150  *
151  * Revision 1.1  1993/03/19  22:45:45  hollings
152  * Initial revision
153  *
154  *
155  */
156
157 #include <assert.h>
158 #include <sys/signal.h>
159 #include <sys/param.h>
160
161
162 #include "rtinst/h/rtinst.h"
163 #include "symtab.h"
164 #include "process.h"
165 #include "inst.h"
166 #include "instP.h"
167 #include "ast.h"
168 #include "util.h"
169 #include "internalMetrics.h"
170 #include <strstream.h>
171 #include "stats.h"
172 #include "init.h"
173 #include "showerror.h"
174
175 #define NS_TO_SEC       1000000000.0
176 dictionary_hash <string, unsigned> primitiveCosts(string::hash);
177 // dictionary_hash<string, unsigned> tagDict(string::hash);
178 process *nodePseudoProcess=NULL;
179
180 int getBaseBranchAddr(process *proc, instInstance *inst)
181 {
182     int fromAddr;
183
184     fromAddr = (int) inst->baseAddr;
185     if (inst->when == callPreInsn) {
186         fromAddr += proc->aggregate ? baseTemplate.globalPreOffset :
187             baseTemplate.localPreOffset;
188     } else {
189         fromAddr += proc->aggregate ? baseTemplate.globalPostOffset :
190             baseTemplate.localPostOffset;
191     }
192     return(fromAddr);
193 }
194
195 void clearBaseBranch(process *proc, instInstance *inst)
196 {
197     int addr;
198
199     addr = (int) inst->baseAddr;
200     if (inst->when == callPreInsn) {
201         addr += proc->aggregate ? baseTemplate.globalPreOffset :
202             baseTemplate.localPreOffset;
203     } else {
204         addr += proc->aggregate ? baseTemplate.globalPostOffset :
205             baseTemplate.localPostOffset;
206     }
207     generateNoOp(proc, addr);
208 }
209
210 // implicit assumption that tramps generate to less than 64K bytes!!!
211 static char insn[65536];
212
213 static dictionary_hash<instPoint*, point*> activePoints(ipHash);
214
215 instInstance *addInstFunc(process *proc, instPoint *location, AstNode *ast,
216     callWhen when, callOrder order)
217 {
218     int trampCost;
219     unsigned count;
220     unsigned fromAddr;
221     point *thePoint;
222     instInstance *ret;
223     instInstance *lastAtPoint;
224     instInstance *firstAtPoint;
225
226     assert(proc && location);
227
228     initTramps();
229
230     /* check if there are other inst points at this location. for this process
231        at the same pre/post mode */
232     firstAtPoint = NULL;
233     lastAtPoint = NULL;
234
235     if (!activePoints.defines(location)) {
236       thePoint = new point;
237       activePoints[location] = thePoint;
238     } else
239       thePoint = activePoints[location];
240
241     assert(thePoint);
242     for (ret= thePoint->inst; ret; ret = ret->next) {
243         if ((ret->proc == proc) && (ret->when == when)) {
244             if (!ret->nextAtPoint) lastAtPoint = ret;
245             if (!ret->prevAtPoint) firstAtPoint = ret;
246         }
247     }
248
249     ret = new instInstance;
250     assert(ret);
251     ret->proc = proc;
252
253     // must do this before findAndInstallBaseTramp, puts the tramp in to
254     // get the correct cost.
255     trampCost = getPointCost(proc, location);
256
257     /* make sure the base tramp has been installed for this point */
258     ret->baseAddr = findAndInstallBaseTramp(proc, location);
259
260     // 
261     // Generate the code for this tramp.
262     //
263     // return value is offset of return stmnt.
264     //
265     count = 0;
266     ret->returnAddr = ast->generateTramp(proc, insn, count, trampCost); 
267
268     ret->trampBase = inferiorMalloc(proc, count, textHeap);
269     trampBytes += count;
270     ret->returnAddr += ret->trampBase;
271
272     ret->when = when;
273     ret->location = location;
274
275     ret->next = thePoint->inst;
276     ret->prev = NULL;
277     if (thePoint->inst) thePoint->inst->prev = ret;
278     thePoint->inst = ret;
279
280     /* first inst. at this point so install the tramp */
281     fromAddr = ret->baseAddr;
282     if (ret->when == callPreInsn) {
283         fromAddr += proc->aggregate ? baseTemplate.globalPreOffset :
284             baseTemplate.localPreOffset;
285     } else {
286         fromAddr += proc->aggregate ? baseTemplate.globalPostOffset :
287             baseTemplate.localPostOffset;
288     }
289
290     /*
291      * Now make the call to actually put the code in place.
292      *
293      */
294     installTramp(ret, insn, count);
295
296     if (!lastAtPoint) {
297
298         fromAddr = getBaseBranchAddr(proc, ret);
299         generateBranch(proc, fromAddr, ret->trampBase);
300
301         generateBranch(proc, ret->returnAddr, fromAddr+4);
302
303         // just activated this slot.
304         activeSlots->value += 1.0;
305     } else if (order == orderLastAtPoint) {
306         /* patch previous tramp to call us rather than return */
307         generateBranch(proc, lastAtPoint->returnAddr, ret->trampBase);
308         lastAtPoint->nextAtPoint = ret;
309         ret->prevAtPoint = lastAtPoint;
310
311         generateBranch(proc, ret->returnAddr, fromAddr+4);
312     } else {
313         /* first at point */
314         firstAtPoint->prevAtPoint = ret;
315         ret->nextAtPoint = firstAtPoint;
316
317         /* branch to the old first one */
318         generateBranch(proc, ret->returnAddr, firstAtPoint->trampBase);
319
320         /* base tramp branches to us */
321         fromAddr = getBaseBranchAddr(proc, ret);
322         generateBranch(proc, fromAddr, ret->trampBase);
323     }
324
325     return(ret);
326 }
327
328 /*
329  * The tramps are chained together left to right, so we need to find the
330  *    tramps to the left anf right of the one to delete, and then patch the
331  *    call from the left one to the old to call the right one.
332  *    Also we need to patch the return from the right one to go to the left
333  *    one.
334  *
335  */
336 void deleteInst(instInstance *old)
337 {
338     point *thePoint;
339     instInstance *lag;
340     instInstance *left;
341     instInstance *right;
342     instInstance *othersAtPoint;
343
344     /* check if there are other inst points at this location. */
345     othersAtPoint = NULL;
346     left = right = NULL;
347
348     if (!activePoints.defines(old->location))
349       abort();
350     thePoint = activePoints[old->location];
351
352     for (lag= thePoint->inst; lag; lag = lag->next) {
353         if ((lag->location == old->location) && 
354             (lag->proc == old->proc) &&
355             (lag->when == old->when)) {
356             if (lag != old) {
357                 othersAtPoint = lag;
358                 left = old->prevAtPoint;
359                 right = old->nextAtPoint;
360                 assert(right || left);
361             }
362         }
363     }
364
365     if (!othersAtPoint) {
366         clearBaseBranch(old->proc, old);
367         activeSlots->value -= 1.0;
368     } else {
369         if (left) {
370             if (right) {
371                 /* set left's return insn to branch to tramp to the right */
372                 generateBranch(old->proc, left->returnAddr, right->trampBase);
373             } else {
374                 /* branch back to the correct point in the base tramp */
375                 int fromAddr;
376
377                 fromAddr = getBaseBranchAddr(old->proc, old);
378
379                 // this assumes sizeof(int) == sizeof(instruction)
380                 generateBranch(old->proc,left->returnAddr,fromAddr+sizeof(int));
381             }
382         } else {
383             /* old is first one make code call right tramp */
384             int fromAddr;
385
386             fromAddr = getBaseBranchAddr(old->proc, right);
387             generateBranch(old->proc, fromAddr, right->trampBase);
388         }
389     }
390
391     inferiorFree(old->proc, old->trampBase, textHeap);
392
393     /* remove old from atPoint linked list */
394     if (right) right->prevAtPoint = left;
395     if (left) left->nextAtPoint = right;
396
397     /* remove from doubly linked list for all insts */
398     if (old->prev) {
399         lag = old->prev;
400         lag->next = old->next;
401         if (old->next) old->next->prev = lag;
402     } else {
403         thePoint->inst = old->next;
404         if (old->next) old->next->prev = NULL;
405     }
406     free(old);
407 }
408
409
410 void installDefaultInst(process *proc, vector<instMapping*>& initialReqs)
411 {
412     AstNode *ast;
413     instMapping *item;
414
415     unsigned ir_size = initialReqs.size(); 
416     for (unsigned u=0; u<ir_size; u++) {
417       item = initialReqs[u];
418       // TODO this assumes only one instance of each function (no siblings)
419       // TODO - are failures safe here ?
420       pdFunction *func = (proc->symbols)->findOneFunction(item->func);
421       if (!func) {
422 //
423 //  it's ok to fail on an initial inst request if the request 
424 //  is for a programming model that is not used in this process 
425 //  (i.e. cmmd, cmf)
426 //          sprintf (errorLine, "unable to find %s\n", item->func);
427 //          logLine(errorLine);
428         continue;
429       }
430       assert(func);
431
432       if (item->where & FUNC_ARG) {
433         ast = new AstNode(item->inst, item->arg, NULL);
434       } else {
435         ast = new AstNode(item->inst, new AstNode(Constant, 0), NULL);
436       }
437       if (item->where & FUNC_EXIT) {
438         (void) addInstFunc(proc, func->funcReturn(), ast,
439                            callPreInsn, orderLastAtPoint);
440       }
441       if (item->where & FUNC_ENTRY) {
442         (void) addInstFunc(proc, func->funcEntry(), ast,
443                            callPreInsn, orderLastAtPoint);
444       }
445       if (item->where & FUNC_CALL) {
446         if (!func->calls.size()) {
447           ostrstream os(errorLine, 1024, ios::out);
448           os << "No function calls in procedure " << func->prettyName() <<
449             endl;
450           logLine(errorLine);
451           showErrorCallback(64, (const char *) errorLine);
452         } else {
453           for (unsigned i = 0; i < func->calls.size(); i++) {
454             (void) addInstFunc(proc, func->calls[i], ast,
455                                callPreInsn, orderLastAtPoint);
456           }
457         }
458       }
459       delete(ast);
460     }
461     // Supercomputing hack - mdc
462     // TODO
463     osDependentInst(proc);
464 }
465
466 /*
467  * return the time required to execute the passed primitive.
468  *
469  */
470 unsigned getPrimitiveCost(const string name)
471 {
472
473     static bool init=false;
474
475     if (!init) { init = 1; initPrimitiveCost(); }
476
477     if (!primitiveCosts.defines(name)) {
478       return 1;
479     } else
480       return (primitiveCosts[name]);
481 }
482
483
484 // find any tags to associate semantic meaning to function
485 unsigned findTags(const string funcName) {
486   return 0;
487 #ifdef notdef
488   if (tagDict.defines(funcName))
489     return (tagDict[funcName]);
490   else
491     return 0;
492 #endif
493 }