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