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