added way to request unique resource name.
[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.6 1994/05/16 22:31:53 hollings Exp $";
11 #endif
12
13 /*
14  * process.C - Code to control a process.
15  *
16  * $Log: process.C,v $
17  * Revision 1.6  1994/05/16 22:31:53  hollings
18  * added way to request unique resource name.
19  *
20  * Revision 1.5  1994/03/31  02:00:35  markc
21  * Changed to fork for paradyndPVM since client calls pvmendtask which writes
22  * to the address space.
23  *
24  * Revision 1.4  1994/03/22  21:03:15  hollings
25  * Made it possible to add new processes (& paradynd's) via addExecutable.
26  *
27  * Revision 1.3  1994/03/20  01:53:11  markc
28  * Added a buffer to each process structure to allow for multiple writers on the
29  * traceStream.  Replaced old inst-pvm.C.  Changed addProcess to return type
30  * int.
31  *
32  * Revision 1.2  1994/02/05  23:09:56  hollings
33  * Added extern for sys_errlist[] (g++ version 2.5.7).
34  *
35  * Revision 1.1  1994/01/27  20:31:38  hollings
36  * Iinital version of paradynd speaking dynRPC igend protocol.
37  *
38  * Revision 1.8  1993/10/04  21:38:41  hollings
39  * round inferrior mallocs to cache line size.
40  *
41  * Revision 1.7  1993/08/23  23:15:25  hollings
42  * added code to third parameter to findInternalAddress calls.
43  *
44  * Revision 1.6  1993/08/11  01:47:09  hollings
45  * added copyInferrior heap for UNIX fork.
46  *
47  * Revision 1.5  1993/07/13  18:29:38  hollings
48  * new include file syntax.
49  *
50  * Revision 1.4  1993/06/28  23:13:18  hollings
51  * fixed process stopping.
52  *
53  * Revision 1.3  1993/06/22  19:00:01  hollings
54  * global inst state.
55  *
56  * Revision 1.2  1993/06/08  20:14:34  hollings
57  * state prior to bc net ptrace replacement.
58  *
59  * Revision 1.1  1993/03/19  22:45:45  hollings
60  * Initial revision
61  *
62  *
63  */
64
65 #include <assert.h>
66 #include <stdio.h>
67 #include <stdlib.h>
68 #include <unistd.h>
69 #include <sys/socket.h>
70 #include <sys/param.h>
71 #include <sys/ptrace.h>
72 #include <errno.h>
73
74 #include "rtinst/h/rtinst.h"
75 #include "rtinst/h/trace.h"
76 #include "dyninst.h"
77 #include "symtab.h"
78 #include "process.h"
79 #include "util.h"
80
81 List<process*> processList;
82
83 extern char *sys_errlist[];
84
85 /* root of process resource list */
86 resource processResource;
87 resource machineResource;
88
89 extern "C" ptrace();
90
91 #define INFERRIOR_HEAP_BASE     "DYNINSTdata"
92 #define GLOBAL_HEAP_BASE        "DYNINSTglobalData"
93
94 void initInferiorHeap(process *proc, Boolean globalHeap)
95 {
96     assert(proc->symbols);
97
98     proc->heap = (freeListEntry*) xcalloc(sizeof(freeListEntry), 1);
99     if (globalHeap) {
100         proc->heap->addr = 
101             findInternalAddress(proc->symbols, GLOBAL_HEAP_BASE, True);
102     } else {
103         proc->heap->addr = 
104             findInternalAddress(proc->symbols, INFERRIOR_HEAP_BASE, True);
105     }
106     proc->heap->length = SYN_INST_BUF_SIZE;
107     proc->heap->next = NULL;
108     proc->status = HEAPfree;
109 }
110
111 void copyInferriorHeap(process *from, process *to)
112 {
113     freeListEntry *curr;
114     freeListEntry *newEntry;
115
116     assert(from->symbols);
117     assert(to->symbols);
118
119     to->heap = NULL;
120     /* copy individual elements */
121     for (curr=from->heap; curr; curr=curr->next) {
122         newEntry = (freeListEntry*) xcalloc(sizeof(freeListEntry), 1);
123         *newEntry = *curr;
124
125         /* setup next pointers */
126         newEntry->next = to->heap;
127         to->heap = newEntry;
128     }
129     to->status = HEAPfree;
130 }
131
132 int inferriorMalloc(process *proc, int size)
133 {
134     freeListEntry *newEntry;
135     freeListEntry *curr;
136
137     /* round to next cache line size */
138     /* 32 bytes on a SPARC */
139     size = (size + 0x1f) & ~0x1f; 
140     for (curr=proc->heap; curr; curr=curr->next) {
141         if ((curr->status == HEAPfree) && (curr->length >= size)) break;
142     }
143
144     if (!curr) {
145         printf("Inferrior heap overflow\n");
146         abort();
147     }
148
149     if (curr->length != size) {
150         newEntry = (freeListEntry *) xcalloc(sizeof(freeListEntry), 1);
151         newEntry->length = curr->length - size;
152         newEntry->addr = curr->addr + size;
153         newEntry->next = curr->next;
154         newEntry->status = HEAPfree;
155
156         /* now split curr */
157         curr->status = HEAPallocated;
158         curr->length = size;
159         curr->next = newEntry;
160     }
161     return(curr->addr);
162 }
163
164 void inferriorFree(process *proc, int pointer)
165 {
166 #ifdef notdef
167     freeListEntry *curr;
168
169     /* free is currently disabled because we can't handle the case of an
170      *  inst function being deleted while active.  Not freeing the memory means
171      *  it stil contains the tramp and will get itself out safely.
172      */
173
174     for (curr=proc->heap; curr; curr=curr->next) {
175         if (curr->addr == pointer) break;
176     }
177
178     if (!curr) {
179         printf("unable to find heap entry %x\n", pointer);
180         abort();
181     }
182
183     if (curr->status != HEAPallocated) {
184         printf("attempt to free already free heap entry %x\n", pointer);
185         abort();
186     }
187     curr->status = HEAPfree;
188 #endif
189 }
190
191 process *allocateProcess(int pid, char *name)
192 {
193     process *ret;
194
195     ret = (process *) xcalloc(sizeof(process), 1);
196     processList.add(ret, (void *) pid);
197
198     if (!machineResource) {
199         char hostName[80];
200
201         gethostname(hostName, sizeof(hostName));
202         resource machineRoot;
203         machineRoot = newResource(rootResource, NULL, "Machine", 0.0,FALSE);
204         machineResource = newResource(machineRoot, NULL, hostName, 0.0, FALSE);
205     }
206
207     ret->pid = pid;
208     if (!processResource) {
209         processResource = newResource(rootResource, NULL, "Process", 0.0,FALSE);
210     }
211     ret->rid = newResource(processResource, ret, name, 0.0, TRUE);
212
213     ret->bufEnd = 0;
214     return(ret);
215 }
216
217 /*
218  * Create a new instance of the named process.  Read the symbols and start
219  *   the program
220  */
221 process *createProcess(char *file, char *argv[], int nenv, char *envp[])
222 {
223     int pid;
224     int r;
225     image *i;
226     process *ret;
227     char name[20];
228     int tracePipe[2];
229
230     r = socketpair(AF_UNIX, SOCK_STREAM, (int) NULL, tracePipe);
231     if (r) {
232         perror("socketpair");
233         return(NULL);
234     }
235     //
236     // WARNING This code assumes that vfork is used, and a failed exec will
237     //   corectly change failed in the parent process.
238     //
239     errno = 0;
240 #ifdef PARADYND_PVM
241 // must use fork, since pvmendtask will do some writing in the address space
242     pid = fork();
243 #else
244     pid = vfork();
245 #endif
246     if (pid > 0) {
247         if (errno) {
248             printf("Unable to start %s: %s\n", file, sys_errlist[errno]);
249             return(NULL);
250         }
251
252         i = parseImage(file, 0);
253         if (!i) return(NULL);
254
255         /* parent */
256         sprintf(name, "%s", i->name);
257         ret = allocateProcess(pid, name);
258         ret->symbols = i;
259         initInferiorHeap(ret, False);
260
261         ret->status = neonatal;
262         ret->traceLink = tracePipe[0];
263         close(tracePipe[1]);
264         return(ret);
265     } else if (pid == 0) {
266 #ifdef PARADYND_PVM
267         pvmendtask(); 
268 #endif   
269         close(tracePipe[0]);
270         if (dup2(tracePipe[1], 3) != 3)
271           {
272             fprintf (stderr, "dup2 failed\n");
273             abort();
274           }
275
276         /* close if higher */
277         if (tracePipe[1] > 3) close(tracePipe[1]);
278
279         /* indicate our desire to be trace */
280         errno = 0;
281         ptrace(0, 0, 0, 0);
282         if (errno != 0) {
283           perror("ptrace error\n");
284           _exit(-1);
285         }
286 #ifdef PARADYND_PVM
287         while (nenv-- > 0)
288                 pvmputenv(envp[nenv]);
289 #endif
290         execv(file, argv);
291         perror("exev");
292         _exit(-1);
293     } else {
294         perror("vfork");
295         free(ret);
296         return(NULL);
297     }
298 }
299
300 process *findProcess(int pid)
301 {
302    return(processList.find((void *) pid));
303    return(NULL);
304 }