Changed *allocs to news
[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: /home/jaw/CVSROOT_20081103/CVSROOT/core/paradynd/src/Attic/inst.C,v 1.9 1994/09/22 02:00:02 markc Exp $";
11 #endif
12
13 /*
14  * inst.C - Code to install and remove inst funcs from a running process.
15  *
16  * $Log: inst.C,v $
17  * Revision 1.9  1994/09/22 02:00:02  markc
18  * Changed *allocs to news
19  * cast stringHandles for printing
20  * cast args to PCptrace
21  *
22  * Revision 1.8  1994/08/17  18:13:31  markc
23  * Changed variable names in installDefaultInst to quiet compiler warnings.
24  * Added reachedFirstBreak check to avoid stopping processes that have yet
25  * to reach their initial SIGSTOP.
26  *
27  * Revision 1.7  1994/07/28  22:40:39  krisna
28  * changed definitions/declarations of xalloc functions to conform to alloc.
29  *
30  * Revision 1.6  1994/07/20  23:23:36  hollings
31  * added insn generated metric.
32  *
33  * Revision 1.5  1994/07/12  19:48:46  jcargill
34  * Added warning for functions not found in initialRequests set
35  *
36  * Revision 1.4  1994/06/29  02:52:30  hollings
37  * Added metricDefs-common.{C,h}
38  * Added module level performance data
39  * cleanedup types of inferrior addresses instrumentation defintions
40  * added firewalls for large branch displacements due to text+data over 2meg.
41  * assorted bug fixes.
42  *
43  * Revision 1.3  1994/06/27  18:56:51  hollings
44  * removed printfs.  Now use logLine so it works in the remote case.
45  * added internalMetric class.
46  * added extra paramter to metric info for aggregation.
47  *
48  * Revision 1.2  1994/03/20  01:53:08  markc
49  * Added a buffer to each process structure to allow for multiple writers on the
50  * traceStream.  Replaced old inst-pvm.C.  Changed addProcess to return type
51  * int.
52  *
53  * Revision 1.1  1994/01/27  20:31:24  hollings
54  * Iinital version of paradynd speaking dynRPC igend protocol.
55  *
56  * Revision 1.13  1993/12/15  21:02:42  hollings
57  * added PVM support.
58  *
59  * Revision 1.12  1993/12/13  19:54:59  hollings
60  * count operations.
61  *
62  * Revision 1.11  1993/10/19  15:27:54  hollings
63  * AST based mini-tramp code generator.
64  *
65  * Revision 1.10  1993/10/04  21:37:10  hollings
66  * re-enabled inst ordering directives.
67  *
68  * Revision 1.10  1993/10/04  21:37:10  hollings
69  * re-enabled inst ordering directives.
70  *
71  * Revision 1.9  1993/10/01  21:29:41  hollings
72  * Added resource discovery and filters.
73  *
74  * Revision 1.8  1993/08/23  23:11:19  hollings
75  * fixed removing tramps to work correctly.
76  *
77  * Revision 1.7  1993/08/11  01:31:57  hollings
78  * fixed call noargs & with args to be more general.
79  *
80  * Revision 1.6  1993/07/13  18:28:19  hollings
81  * new include file syntax.
82  *
83  * Revision 1.5  1993/06/28  23:13:18  hollings
84  * fixed process stopping.
85  *
86  * Revision 1.4  1993/06/24  16:18:06  hollings
87  * global fixes.
88  *
89  * Revision 1.3  1993/06/22  19:00:01  hollings
90  * global inst state.
91  *
92  * Revision 1.2  1993/06/08  20:14:34  hollings
93  * state prior to bc net ptrace replacement.
94  *
95  * Revision 1.1  1993/03/19  22:45:45  hollings
96  * Initial revision
97  *
98  *
99  */
100
101 extern "C" {
102 #include <stdio.h>
103 #include <stdlib.h>
104 #include <assert.h>
105 #include <sys/ptrace.h>
106 #include <sys/signal.h>
107 #include <sys/param.h>
108 #include <errno.h>
109 }
110
111 #include "rtinst/h/rtinst.h"
112 #include "symtab.h"
113 #include "process.h"
114 #include "inst.h"
115 #include "instP.h"
116 #include "ast.h"
117 #include "util.h"
118 #include "internalMetrics.h"
119
120 extern int trampBytes;
121 extern trampTemplate baseTemplate;
122 extern trampTemplate noArgsTemplate;
123 extern trampTemplate withArgsTemplate;
124 extern internalMetric activeSlots;
125
126 int getBaseBranchAddr(process *proc, instInstance *inst)
127 {
128     int fromAddr;
129
130     fromAddr = (int) inst->baseAddr;
131     if (inst->when == callPreInsn) {
132         fromAddr += proc->aggregate ? baseTemplate.globalPreOffset :
133             baseTemplate.localPreOffset;
134     } else {
135         fromAddr += proc->aggregate ? baseTemplate.globalPostOffset :
136             baseTemplate.localPostOffset;
137     }
138     return(fromAddr);
139 }
140
141 void clearBaseBranch(process *proc, instInstance *inst)
142 {
143     int addr;
144
145     addr = (int) inst->baseAddr;
146     if (inst->when == callPreInsn) {
147         addr += proc->aggregate ? baseTemplate.globalPreOffset :
148             baseTemplate.localPreOffset;
149     } else {
150         addr += proc->aggregate ? baseTemplate.globalPostOffset :
151             baseTemplate.localPostOffset;
152     }
153     generateNoOp(proc, addr);
154 }
155
156 // implicit assumption that tramps generate to less than 64K bytes!!!
157 static char insn[65536];
158
159 static HTable<point*> activePoints;
160
161 instInstance *addInstFunc(process *proc, instPoint *location, AstNode *ast,
162     callWhen when, callOrder order)
163 {
164     int count;
165     int fromAddr;
166     point *thePoint;
167     instInstance *ret;
168     instInstance *lastAtPoint;
169     instInstance *firstAtPoint;
170
171     assert(proc && location);
172
173     initTramps();
174
175     /* check if there are other inst points at this location. for this process
176        at the same pre/post mode */
177     firstAtPoint = NULL;
178     lastAtPoint = NULL;
179
180     thePoint = activePoints.find(location);
181     if (!thePoint) {
182         thePoint = new point;
183         activePoints.add(thePoint, location);
184     }
185     for (ret= thePoint->inst; ret; ret = ret->next) {
186         if ((ret->proc == proc) && (ret->when == when)) {
187             if (!ret->nextAtPoint) lastAtPoint = ret;
188             if (!ret->prevAtPoint) firstAtPoint = ret;
189         }
190     }
191
192     ret = new instInstance;
193     ret->proc = proc;
194
195     /* make sure the base tramp has been installed for this point */
196     ret->baseAddr = findAndInstallBaseTramp(proc, location);
197
198     // 
199     // Generate the code for this tramp.
200     //
201     // return value is offset of return stmnt.
202     //
203     count = 0;
204     ret->returnAddr = ast->generateTramp(proc, insn, (caddr_t *) &count); 
205
206     ret->trampBase = inferriorMalloc(proc, count);
207     trampBytes += count;
208     ret->returnAddr += ret->trampBase;
209
210     ret->when = when;
211     ret->location = location;
212
213     ret->next = thePoint->inst;
214     ret->prev = NULL;
215     if (thePoint->inst) thePoint->inst->prev = ret;
216     thePoint->inst = ret;
217
218     /* first inst. at this point so install the tramp */
219     fromAddr = (int) ret->baseAddr;
220     if (ret->when == callPreInsn) {
221         fromAddr += proc->aggregate ? baseTemplate.globalPreOffset :
222             baseTemplate.localPreOffset;
223     } else {
224         fromAddr += proc->aggregate ? baseTemplate.globalPostOffset :
225             baseTemplate.localPostOffset;
226     }
227
228     /*
229      * Now make the call to actually put the code in place.
230      *
231      */
232     installTramp(ret, insn, count);
233
234     if (!lastAtPoint) {
235         int fromAddr;
236
237         fromAddr = getBaseBranchAddr(proc, ret);
238         generateBranch(proc, fromAddr, ret->trampBase);
239
240         generateBranch(proc, ret->returnAddr, fromAddr+4);
241
242         // just activated this slot.
243         activeSlots.value += 1.0;
244     } else if (order == orderLastAtPoint) {
245         /* patch previous tramp to call us rather than return */
246         generateBranch(proc, lastAtPoint->returnAddr, ret->trampBase);
247         lastAtPoint->nextAtPoint = ret;
248         ret->prevAtPoint = lastAtPoint;
249
250         generateBranch(proc, ret->returnAddr, fromAddr+4);
251     } else {
252         /* first at point */
253         firstAtPoint->prevAtPoint = ret;
254         ret->nextAtPoint = firstAtPoint;
255
256         /* branch to the old first one */
257         generateBranch(proc, ret->returnAddr, firstAtPoint->trampBase);
258
259         /* base tramp branches to us */
260         fromAddr = getBaseBranchAddr(proc, ret);
261         generateBranch(proc, fromAddr, ret->trampBase);
262     }
263
264     return(ret);
265 }
266
267 /*
268  * The tramps are chained together left to right, so we need to find the
269  *    tramps to the left anf right of the one to delete, and then patch the
270  *    call from the left one to the old to call the right one.
271  *    Also we need to patch the return from the right one to go to the left
272  *    one.
273  *
274  */
275 void deleteInst(instInstance *old)
276 {
277     point *thePoint;
278     instInstance *lag;
279     instInstance *left;
280     instInstance *right;
281     instInstance *othersAtPoint;
282
283     /* check if there are other inst points at this location. */
284     othersAtPoint = NULL;
285     left = right = NULL;
286
287     thePoint = activePoints.find(old->location);
288     assert(thePoint);
289
290     for (lag= thePoint->inst; lag; lag = lag->next) {
291         if ((lag->location == old->location) && 
292             (lag->proc == old->proc) &&
293             (lag->when == old->when)) {
294             if (lag != old) {
295                 othersAtPoint = lag;
296                 left = old->prevAtPoint;
297                 right = old->nextAtPoint;
298                 assert(right || left);
299             }
300         }
301     }
302
303     if (!othersAtPoint) {
304         clearBaseBranch(old->proc, old);
305         activeSlots.value -= 1.0;
306     } else {
307         if (left) {
308             if (right) {
309                 /* set left's return insn to branch to tramp to the right */
310                 generateBranch(old->proc, left->returnAddr, right->trampBase);
311             } else {
312                 /* branch back to the correct point in the base tramp */
313                 int fromAddr;
314
315                 fromAddr = getBaseBranchAddr(old->proc, old);
316
317                 // this assumes sizeof(int) == sizeof(instruction)
318                 generateBranch(old->proc,left->returnAddr,fromAddr+sizeof(int));
319             }
320         } else {
321             /* old is first one make code call right tramp */
322             int fromAddr;
323
324             fromAddr = getBaseBranchAddr(old->proc, right);
325             generateBranch(old->proc, fromAddr, right->trampBase);
326         }
327     }
328
329     inferriorFree(old->proc, old->trampBase);
330
331     /* remove old from atPoint linked list */
332     if (right) right->prevAtPoint = left;
333     if (left) left->nextAtPoint = right;
334
335     /* remove from doubly linked list for all insts */
336     if (old->prev) {
337         lag = old->prev;
338         lag->next = old->next;
339         if (old->next) old->next->prev = lag;
340     } else {
341         thePoint->inst = old->next;
342         if (old->next) old->next->prev = NULL;
343     }
344     free(old);
345 }
346
347
348 void installDefaultInst(process *proc, instMaping *initialReqs)
349 {
350     int i;
351     AstNode *ast;
352     pdFunction *func;
353     instMaping *item;
354
355     for (item = initialReqs; item->func; item++) {
356         func = findFunction(proc->symbols, item->func);
357         if (!func) {
358             sprintf (errorLine, "unable to find %s\n", item->func);
359             logLine(errorLine);
360             continue;
361         }
362
363         if (item->where & FUNC_ARG) {
364             ast = new AstNode(item->inst, item->arg, NULL);
365         } else {
366             ast = new AstNode(item->inst, new AstNode(Constant, 0), NULL);
367         }
368         if (item->where & FUNC_EXIT) {
369             (void) addInstFunc(proc, func->funcReturn, ast,
370                 callPreInsn, orderLastAtPoint);
371         }
372         if (item->where & FUNC_ENTRY) {
373             (void) addInstFunc(proc, func->funcEntry, ast,
374                 callPreInsn, orderLastAtPoint);
375         }
376         if (item->where & FUNC_CALL) {
377             if (!func->callCount) {
378                 sprintf(errorLine, "no function calls in procedure %s\n", (char*)func->prettyName);
379                 logLine(errorLine);
380             } else {
381                 for (i = 0; i < func->callCount; i++) {
382                     (void) addInstFunc(proc, func->calls[i], ast,
383                         callPreInsn, orderLastAtPoint);
384                 }
385             }
386         }
387         delete(ast);
388     }
389 }
390
391 void pauseProcess(process *proc)
392 {
393     if (proc->status == running && proc->reachedFirstBreak) {
394         (void) PCptrace(PTRACE_INTERRUPT, proc, (void*)1, 0, 0);
395         proc->status = stopped;
396     }
397 }
398
399 void continueProcess(process *proc)
400 {
401     if (proc->status == stopped) {
402         (void) PCptrace(PTRACE_CONT, proc, (void*)1, 0, 0);
403         proc->status = running;
404     }
405 }
406
407 void dumpCore(process *proc)
408 {
409     (void) PCptrace(PTRACE_DUMPCORE, proc, (void*) "core.out", 0, 0);
410 }
411
412 /*
413  * Copy data from controller process to the named process.
414  *
415  */
416 void copyToProcess(process *proc, void *from, void *to, int size)
417 {
418     (void) PCptrace(PTRACE_WRITEDATA, proc, to, size, from);
419 }
420
421 void copyFromProcess(process *proc, void *from, void *to, int size)
422 {
423     (void) PCptrace(PTRACE_READDATA, proc, from, size, to);
424 }