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