Remove non-emergency prints
[dyninst.git] / dyninstAPI / src / process.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/process.C,v 1.22 1994/11/11 10:44:12 markc Exp $";
11 #endif
12
13 /*
14  * process.C - Code to control a process.
15  *
16  * $Log: process.C,v $
17  * Revision 1.22  1994/11/11 10:44:12  markc
18  * Remove non-emergency prints
19  * Changed others to use statusLine
20  *
21  * Revision 1.21  1994/11/09  18:40:33  rbi
22  * the "Don't Blame Me" commit
23  *
24  * Revision 1.20  1994/11/02  11:15:17  markc
25  * Started to make process into a class.
26  *
27  * Revision 1.19  1994/10/13  07:24:56  krisna
28  * solaris porting and updates
29  *
30  * Revision 1.18  1994/09/22  02:23:17  markc
31  * changed *allocs to new
32  *
33  * Revision 1.17  1994/08/17  18:17:43  markc
34  * Changed execv to execvp.
35  *
36  * Revision 1.16  1994/07/26  20:01:41  hollings
37  * fixed heap allocation to use hash tables.
38  *
39  * Revision 1.15  1994/07/20  23:23:39  hollings
40  * added insn generated metric.
41  *
42  * Revision 1.14  1994/07/14  23:29:03  hollings
43  * Corrected file mask on io redirection.
44  *
45  * Revision 1.13  1994/06/29  02:52:47  hollings
46  * Added metricDefs-common.{C,h}
47  * Added module level performance data
48  * cleanedup types of inferrior addresses instrumentation defintions
49  * added firewalls for large branch displacements due to text+data over 2meg.
50  * assorted bug fixes.
51  *
52  * Revision 1.12  1994/06/27  21:28:18  rbi
53  * Abstraction-specific resources and mapping info
54  *
55  * Revision 1.11  1994/06/27  18:57:07  hollings
56  * removed printfs.  Now use logLine so it works in the remote case.
57  * added internalMetric class.
58  * added extra paramter to metric info for aggregation.
59  *
60  * Revision 1.10  1994/06/22  03:46:32  markc
61  * Removed compiler warnings.
62  *
63  * Revision 1.9  1994/06/22  01:43:18  markc
64  * Removed warnings.  Changed bcopy in inst-sparc.C to memcpy.  Changed process.C
65  * reference to proc->status to use proc->heap->status.
66  *
67  * Revision 1.8  1994/05/31  17:59:05  markc
68  * Closed iopipe fd that had been dup'd if the fd was greater than 2.
69  *
70  * Revision 1.7  1994/05/18  00:52:31  hollings
71  * added ability to gather IO from application processes and forward it to
72  * the paradyn proces.
73  *
74  * Revision 1.6  1994/05/16  22:31:53  hollings
75  * added way to request unique resource name.
76  *
77  * Revision 1.5  1994/03/31  02:00:35  markc
78  * Changed to fork for paradyndPVM since client calls pvmendtask which writes
79  * to the address space.
80  *
81  * Revision 1.4  1994/03/22  21:03:15  hollings
82  * Made it possible to add new processes (& paradynd's) via addExecutable.
83  *
84  * Revision 1.3  1994/03/20  01:53:11  markc
85  * Added a buffer to each process structure to allow for multiple writers on the
86  * traceStream.  Replaced old inst-pvm.C.  Changed addProcess to return type
87  * int.
88  *
89  * Revision 1.2  1994/02/05  23:09:56  hollings
90  * Added extern for sys_errlist[] (g++ version 2.5.7).
91  *
92  * Revision 1.1  1994/01/27  20:31:38  hollings
93  * Iinital version of paradynd speaking dynRPC igend protocol.
94  *
95  * Revision 1.8  1993/10/04  21:38:41  hollings
96  * round inferrior mallocs to cache line size.
97  *
98  * Revision 1.7  1993/08/23  23:15:25  hollings
99  * added code to third parameter to findInternalAddress calls.
100  *
101  * Revision 1.6  1993/08/11  01:47:09  hollings
102  * added copyInferrior heap for UNIX fork.
103  *
104  * Revision 1.5  1993/07/13  18:29:38  hollings
105  * new include file syntax.
106  *
107  * Revision 1.4  1993/06/28  23:13:18  hollings
108  * fixed process stopping.
109  *
110  * Revision 1.3  1993/06/22  19:00:01  hollings
111  * global inst state.
112  *
113  * Revision 1.2  1993/06/08  20:14:34  hollings
114  * state prior to bc net ptrace replacement.
115  *
116  * Revision 1.1  1993/03/19  22:45:45  hollings
117  * Initial revision
118  *
119  *
120  */
121
122 #include "util/h/kludges.h"
123
124 extern "C" {
125 #ifdef PARADYND_PVM
126 int pvmputenv (char *);
127 int pvmendtask();
128 #endif
129 }
130
131 #include "rtinst/h/rtinst.h"
132 #include "rtinst/h/trace.h"
133 #include "symtab.h"
134 #include "process.h"
135 #include "util.h"
136 #include "inst.h"
137 #include "dyninstP.h"
138 #include "os.h"
139 #include "util/h/kludges.h"
140
141 dictionary_hash<int, process*> processMap(intHash);
142
143 /* root of process resource list */
144 resource *processResource;
145 resource *machineResource;
146
147 void initInferiorHeap(process *proc, bool globalHeap)
148 {
149     heapItem *np;
150     bool err;
151
152     assert(proc->symbols);
153
154     np = new heapItem;
155     if (globalHeap) {
156         np->addr = 
157           (proc->symbols)->findInternalAddress(GLOBAL_HEAP_BASE, true,err);
158         if (err)
159           abort();
160     } else {
161         np->addr = 
162           (proc->symbols)->findInternalAddress(INFERIOR_HEAP_BASE, true, err);
163         if (err)
164           abort();
165     }
166     np->length = SYN_INST_BUF_SIZE;
167     np->status = HEAPfree;
168
169     // make the heap double-word aligned
170     Address base = np->addr & ~0x1f;
171     Address diff = np->addr - base;
172     if (diff) {
173       np->addr = base + 32;
174       np->length -= (32 - diff);
175     }
176
177
178     proc->heapFree += np;
179 }
180
181 void copyInferiorHeap(process *from, process *to)
182 {
183     abort();
184
185 #ifdef notdef
186     heapItem *curr;
187     heapItem *newEntry;
188
189     // not done jkh 7/22/94
190
191     assert(from->symbols);
192     assert(to->symbols);
193
194     // to->heapActive = NULL;
195     /* copy individual elements */
196     for (curr=from->heap; curr; curr=curr->next) {
197         newEntry = new heapItem;
198         *newEntry = *curr;
199
200         /* setup next pointers */
201         newEntry->next = to->heap;
202         to->heap = newEntry;
203     }
204     to->heap->status = HEAPfree;
205 #endif
206 }
207
208 unsigned inferiorMalloc(process *proc, int size)
209 {
210     heapItem *np=NULL, *newEntry = NULL;
211     
212     assert(size > 0);
213     /* round to next cache line size */
214     /* 32 bytes on a SPARC */
215     size = (size + 0x1f) & ~0x1f; 
216
217     int i, foundIndex=-1; bool found=false; 
218     for (i=0; i < proc->heapFree.size(); i++) {
219       if ((proc->heapFree[i])->length >= size) {
220         np = proc->heapFree[i];
221         found = true;
222         foundIndex = i;
223         break;
224       }
225     }
226
227     if (!found) {
228         logLine("Inferior heap overflow\n");
229         sprintf(errorLine, "%d bytes freed\n", proc->freed);
230         sprintf(errorLine, "%d bytes requested\n", size);
231         logLine(errorLine);
232         abort();
233     }
234
235     if (np->length != size) {
236         // divide it up.
237         newEntry = new heapItem;
238         newEntry->length = np->length - size;
239         newEntry->addr = np->addr + size;
240         
241         // overwrite the old entry
242         proc->heapFree[foundIndex] = newEntry;
243
244         /* now split curr */
245         np->length = size;
246     } else {
247       i = proc->heapFree.size();
248       // copy the last element over this element
249       if (foundIndex < (i-1)) {
250         proc->heapFree[foundIndex] = proc->heapFree[i-1];
251         proc->heapFree.resize(i-1);
252       } else if (i == 1) {
253         logLine("Inferior heap overflow\n");
254         abort();
255       }
256     }
257
258     // mark it used
259     np->status = HEAPallocated;
260
261     // onto in use list
262     proc->heapActive[np->addr] = np;
263     return(np->addr);
264 }
265
266 void inferiorFree(process *proc, unsigned pointer)
267 {
268     heapItem *np;
269
270     if (!proc->heapActive.defines(pointer))
271       abort();
272     np = proc->heapActive[pointer];
273     proc->freed += np->length;
274 #ifdef notdef
275     /* free is currently disabled because we can't handle the case of an
276      *  inst function being deleted while active.  Not freeing the memory means
277      *  it stil contains the tramp and will get itself out safely.
278      */
279
280     if (np->status != HEAPallocated) {
281       logLine("attempt to free already free heap entry %x\n", pointer);
282       abort();
283     }
284     np->status = HEAPfree;
285
286     // remove from active list.
287     proc->heapActive.undef(pointer);
288
289     // back onto free list.
290     proc->heapFree += pointer;
291 #endif
292 }
293
294 process *allocateProcess(int pid, const string name)
295 {
296     process *ret;
297
298     ret = new process;
299     processMap[pid] = ret;
300
301     if (!machineResource) {
302         char hostName[80];
303
304         gethostname(hostName, sizeof(hostName));
305         resource *machineRoot;
306         machineRoot = newResource(rootResource, NULL, nullString, "Machine",
307                                   0.0, false);
308         machineResource = newResource(machineRoot, NULL, nullString, hostName,
309                                       0.0, false);
310     }
311
312     ret->pid = pid;
313     if (!processResource) {
314         processResource = newResource(rootResource, NULL, nullString, "Process",
315                                       0.0, false);
316     }
317     ret->rid = newResource(processResource, (void*)ret, nullString, name,
318                            0.0, true);
319
320     ret->bufEnd = 0;
321
322     // this process won't be paused until this flag is set
323     ret->reachedFirstBreak = 0;
324     return(ret);
325 }
326
327 /*
328  * Create a new instance of the named process.  Read the symbols and start
329  *   the program
330  */
331 process *createProcess(char *file, int argvCount, char *argv[],
332                        int nenv, char *envp[])
333 {
334     int r;
335     int fd;
336     int pid;
337     image *img;
338     int i, j, k;
339     process *ret=0;
340
341     int ioPipe[2];
342     int tracePipe[2];
343     FILE *childError;
344     char *inputFile = NULL;
345     char *outputFile = NULL;
346
347     // TODO - mdc
348     // argv[] won't be null terminated if passed in via string_Array
349     // check for I/O redirection in arg list.
350     for (i=0; i<argvCount; i++) {
351         if (argv[i] && !strcmp("<", argv[i])) {
352             inputFile = argv[i+1];
353             for (j=i+2, k=i; argv[j]; j++, k++) {
354                 argv[k] = argv[j];
355             }
356             argv[k] = NULL;
357         }
358         if (argv[i] && !strcmp(">", argv[i])) {
359             outputFile = argv[++i];
360             for (j=i+2, k=i; argv[j]; j++, k++) {
361                 argv[k] = argv[j];
362             }
363             argv[k] = NULL;
364         }
365     }
366
367     r = socketpair(AF_UNIX, SOCK_STREAM, (int) NULL, tracePipe);
368     if (r) {
369         perror("socketpair");
370         return(NULL);
371     }
372
373     r = socketpair(AF_UNIX, SOCK_STREAM, (int) NULL, ioPipe);
374     if (r) {
375         perror("socketpair");
376         return(NULL);
377     }
378     //
379     // WARNING This code assumes that vfork is used, and a failed exec will
380     //   corectly change failed in the parent process.
381     //
382     errno = 0;
383 #ifdef PARADYND_PVM
384 // must use fork, since pvmendtask will do some writing in the address space
385     pid = fork();
386     // fprintf(stderr, "FORK: pid=%d\n", pid);
387 #else
388     pid = vfork();
389 #endif
390     if (pid > 0) {
391         if (errno) {
392             sprintf(errorLine, "Unable to start %s: %s\n", file, sys_errlist[errno]);
393             logLine(errorLine);
394             return(NULL);
395         }
396
397         img = parseImage(file);
398         if (!img) {
399             // destory child process
400             kill(pid, 9);
401
402             return(NULL);
403         }
404
405         /* parent */
406         statusLine("initializing process data structures");
407         // sprintf(name, "%s", (char*)img->name);
408         ret = allocateProcess(pid, img->name);
409         ret->symbols = img;
410         initInferiorHeap(ret, false);
411
412         ret->status = neonatal;
413         ret->traceLink = tracePipe[0];
414         ret->ioLink = ioPipe[0];
415         close(tracePipe[1]);
416         close(ioPipe[1]);
417         statusLine("ready");
418         return(ret);
419     } else if (pid == 0) {
420 #ifdef PARADYND_PVM
421         pvmendtask(); 
422 #endif   
423         // handle stdio.
424         close(ioPipe[0]);
425         dup2(ioPipe[1], 1);
426         dup2(ioPipe[1], 2);
427         if (ioPipe[1] > 2) close (ioPipe[1]);
428
429         // setup stderr for rest of exec try.
430         childError = fdopen(2, "w");
431
432         close(tracePipe[0]);
433         if (dup2(tracePipe[1], 3) != 3) {
434             fprintf(childError, "dup2 failed\n");
435             fflush(childError);
436             _exit(-1);
437         }
438
439         /* close if higher */
440         if (tracePipe[1] > 3) close(tracePipe[1]);
441
442         /* see if I/O needs to be redirected */
443         if (inputFile) {
444             fd = open(inputFile, O_RDONLY, 0);
445             if (fd < 0) {
446                 fprintf(childError, "stdin open of %s failed\n", inputFile);
447                 fflush(childError);
448                 _exit(-1);
449             } else {
450                 dup2(fd, 0);
451                 close(fd);
452             }
453         }
454
455         if (outputFile) {
456             fd = open(outputFile, O_WRONLY|O_CREAT, 0444);
457             if (fd < 0) {
458                 fprintf(childError, "stdout open of %s failed\n", inputFile);
459                 fflush(childError);
460                 _exit(-1);
461             } else {
462                 dup2(fd, 1);
463                 close(fd);
464             }
465         }
466
467         /* indicate our desire to be trace */
468         errno = 0;
469         osTraceMe();
470         if (errno != 0) {
471           sprintf(errorLine, "ptrace error, exiting, errno=%d\n", errno);
472           logLine(errorLine);
473           logLine(sys_errlist[errno]);
474           _exit(-1);
475         }
476 #ifdef PARADYND_PVM
477         while (nenv-- > 0)
478                 pvmputenv(envp[nenv]);
479 #endif
480         execvp(file, argv);
481
482         sprintf(errorLine, "execv failed, exiting, errno=%d\n", errno);
483         logLine(errorLine);
484         sprintf(errorLine, "file = %s, av[0] = %s\n", file, argv[0]);
485         logLine(errorLine);
486
487         logLine(sys_errlist[errno]);
488         int i=0;
489         while (argv[i]) {
490           sprintf(errorLine, "argv %d = %s\n", i, argv[i]);
491           logLine(errorLine);
492           i++;
493         }
494         _exit(-1);
495         return(NULL);
496     } else {
497         sprintf(errorLine, "vfork failed, errno=%d\n", errno);
498         logLine(errorLine);
499         free(ret);
500         return(NULL);
501     }
502 }
503