Update copyright to LGPL on all files
[dyninst.git] / dyninstAPI_RT / src / RTheap-linux.c
1 /*
2  * Copyright (c) 1996-2009 Barton P. Miller
3  * 
4  * We provide the Paradyn Parallel Performance Tools (below
5  * described as "Paradyn") on an AS IS basis, and do not warrant its
6  * validity or performance.  We reserve the right to update, modify,
7  * or discontinue this software at any time.  We shall have no
8  * obligation to supply such updates or modifications or any other
9  * form of support to you.
10  * 
11  * By your use of Paradyn, you understand and agree that we (or any
12  * other person or entity with proprietary rights in Paradyn) are
13  * under no obligation to provide either maintenance services,
14  * update services, notices of latent defects, or correction of
15  * defects for Paradyn.
16  * 
17  * This library is free software; you can redistribute it and/or
18  * modify it under the terms of the GNU Lesser General Public
19  * License as published by the Free Software Foundation; either
20  * version 2.1 of the License, or (at your option) any later version.
21  * 
22  * This library is distributed in the hope that it will be useful,
23  * but WITHOUT ANY WARRANTY; without even the implied warranty of
24  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
25  * Lesser General Public License for more details.
26  * 
27  * You should have received a copy of the GNU Lesser General Public
28  * License along with this library; if not, write to the Free Software
29  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
30  */
31
32 /* $Id: RTheap-linux.c,v 1.9 2008/01/31 18:01:54 legendre Exp $ */
33 /* RTheap-linux.c: Linux-specific heap components */
34
35 #include <stdlib.h>
36 #include <stdio.h>
37 #include <string.h>                   /* str* */
38 #include <assert.h>
39 #include <sys/types.h>
40 #include <sys/uio.h>                  /* read() */
41 #include <sys/stat.h>                 /* open() */
42 #include <fcntl.h>                    /* open() */
43 #include <unistd.h>                   /* sbrk(), read(), mmap */
44 #include <sys/mman.h>                 /* mmap() */
45 #include "RTheap.h"
46
47 #if defined( ia64_unknown_linux2_4 )
48 /* Align the heap at the IP granularity. */
49 int     DYNINSTheap_align = 16;
50
51 /* Try to stay away from the mutatee's stack and heap.
52    For now, stash everything in what's supposed to
53    be the shared memory region. */
54 Address DYNINSTheap_loAddr = 0x2000000000000000;
55 Address DYNINSTheap_hiAddr = 0x3fffffffffffffff;
56 #elif defined(MUTATEE64)
57
58 int     DYNINSTheap_align = 4; /* heaps are word-aligned */
59
60 Address DYNINSTheap_loAddr = 0x4096;
61 Address DYNINSTheap_hiAddr = ~0x0;
62 #elif defined(arch_power)
63 int     DYNINSTheap_align  = 4; /* heaps are word-aligned */
64 Address DYNINSTheap_loAddr = ~(Address)0; // should be defined by getpagesize() when used.
65 Address DYNINSTheap_hiAddr = ~(Address)0;
66 #else
67 int     DYNINSTheap_align = 4; /* heaps are word-aligned */
68
69 Address DYNINSTheap_loAddr = 0x50000000;
70 Address DYNINSTheap_hiAddr = 0xb0000000;
71 #endif
72
73 int     DYNINSTheap_mmapFlags = MAP_FIXED | MAP_PRIVATE;
74
75
76 RT_Boolean DYNINSTheap_useMalloc(void *lo, void *hi)
77 {
78   /* We do not save footprint space by allocating in
79      the user's heap on this platform, so we stay out of it. */
80   return RT_FALSE;
81 }
82
83 int DYNINSTheap_mmapFdOpen(void)
84 {
85   int fd = open("/dev/zero", O_RDWR);
86   return fd;
87 }
88
89 void DYNINSTheap_mmapFdClose(int fd)
90 {
91   close(fd);
92 }
93
94 /* Linux /proc/PID/maps is unreliable when it is read with more than one
95 read call (it can show pages that are not actually allocated).  We
96 read it all in one call into this buffer.
97
98 linux-2.4: reading /proc/PID/maps now returns after each line in the maps,
99 so we must loop to get everything.
100 */
101 static char procAsciiMap[1<<15];
102
103 int
104 DYNINSTgetMemoryMap(unsigned *nump, dyninstmm_t **mapp)
105 {
106    int fd;
107    ssize_t ret, length;
108    char *p;
109    dyninstmm_t *ms;
110    unsigned i, num;
111
112    /* 
113       Here are two lines from 'cat /proc/self/maps' on Linux 2.2.  Each
114       describes a segment of the address space.  We parse out the first
115       two addresses for the start address and length of the segment.  We
116       throw away the rest.
117
118       |SADDR-| |EADDR-|
119       0804a000-0804c000 rw-p 00001000 08:09 12089      /bin/cat
120       0804c000-0804f000 rwxp 00000000 00:00 0
121    */
122
123    fd = open("/proc/self/maps", O_RDONLY);
124    if (0 > fd) {
125       perror("open /proc");
126       return -1;
127    }
128    length = 0;
129    while (1)
130    {
131       ret = read(fd, procAsciiMap + length, sizeof(procAsciiMap) - length);
132       if (0 == ret) break;
133       if (0 > ret) {
134               perror("read /proc");
135               return -1;
136       }
137       length += ret;
138       if (length >= sizeof(procAsciiMap)) {
139               fprintf(stderr, "DYNINSTgetMemoryMap: memory map buffer overflow\n");
140               return -1;
141       }
142    }
143    procAsciiMap[length] = '\0'; /* Now string processing works */
144
145    close(fd);
146
147    /* Count lines, which is the same as the number of segments.
148       Newline characters separating lines are converted to nulls. */
149    for (num = 0, p = strtok(procAsciiMap, "\n");
150         p != NULL;
151         num++, p = strtok(NULL, "\n"))
152       ;
153      
154    ms = (dyninstmm_t *) malloc(num * sizeof(dyninstmm_t));
155    if (! ms) {
156       fprintf(stderr, "DYNINSTgetMemoryMap: Out of memory\n");
157       return -1;
158    }
159
160    p = procAsciiMap;
161    for (i = 0; i < num; i++) {
162       char *next = p + strlen(p) + 1; /* start of next line */
163       Address saddr, eaddr;
164
165       /* parse start address */
166       p = strtok(p, "-");
167       if (! p) goto parseerr;
168       saddr = strtoul(p, &p, 16);
169       ++p; /* skip '-' */
170
171       /* parse end address */
172       p = strtok(NULL, " ");
173       if (! p) goto parseerr;
174       eaddr = strtoul(p, NULL, 16);
175
176       ms[i].pr_vaddr = saddr;
177       ms[i].pr_size = eaddr - saddr;
178
179       p = next;
180    }
181
182    *nump = num;
183    *mapp = ms;
184    return 0;
185  parseerr:
186    free(ms);
187    fprintf(stderr, "DYNINSTgetMemoryMap: /proc/self/maps parse error\n");
188    return -1;
189 }