blob: e3ec68eedb18af3091b08da2f1df6d1471dbd4fa [file] [log] [blame]
sewardjde4a1d02002-03-22 01:27:54 +00001
2/*--------------------------------------------------------------------*/
3/*--- A simple parser for /proc/self/maps on Linux 2.4.X ---*/
4/*--- vg_procselfmaps.c ---*/
5/*--------------------------------------------------------------------*/
6
7/*
njnb9c427c2004-12-01 14:14:42 +00008 This file is part of Valgrind, a dynamic binary instrumentation
9 framework.
sewardjde4a1d02002-03-22 01:27:54 +000010
njn53612422005-03-12 16:22:54 +000011 Copyright (C) 2000-2005 Julian Seward
sewardjde4a1d02002-03-22 01:27:54 +000012 jseward@acm.org
sewardjde4a1d02002-03-22 01:27:54 +000013
14 This program is free software; you can redistribute it and/or
15 modify it under the terms of the GNU General Public License as
16 published by the Free Software Foundation; either version 2 of the
17 License, or (at your option) any later version.
18
19 This program is distributed in the hope that it will be useful, but
20 WITHOUT ANY WARRANTY; without even the implied warranty of
21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 General Public License for more details.
23
24 You should have received a copy of the GNU General Public License
25 along with this program; if not, write to the Free Software
26 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
27 02111-1307, USA.
28
njn25e49d8e72002-09-23 09:36:25 +000029 The GNU General Public License is contained in the file COPYING.
sewardjde4a1d02002-03-22 01:27:54 +000030*/
31
32
nethercotef1e5e152004-09-01 23:58:16 +000033#include "core.h"
sewardjde4a1d02002-03-22 01:27:54 +000034
njn14319cc2005-03-13 06:26:22 +000035/* Size of a smallish table used to read /proc/self/map entries. */
36#define M_PROCMAP_BUF 50000
37
sewardjde4a1d02002-03-22 01:27:54 +000038/* static ... to keep it out of the stack frame. */
sewardjde4a1d02002-03-22 01:27:54 +000039static Char procmap_buf[M_PROCMAP_BUF];
40
njn3e884182003-04-15 13:03:23 +000041/* Records length of /proc/self/maps read into procmap_buf. */
42static Int buf_n_tot;
43
sewardjde4a1d02002-03-22 01:27:54 +000044
45/* Helper fns. */
46
47static Int hexdigit ( Char c )
48{
49 if (c >= '0' && c <= '9') return (Int)(c - '0');
50 if (c >= 'a' && c <= 'f') return 10 + (Int)(c - 'a');
51 if (c >= 'A' && c <= 'F') return 10 + (Int)(c - 'A');
52 return -1;
53}
54
fitzhardinge98abfc72003-12-16 02:05:15 +000055static Int decdigit ( Char c )
56{
57 if (c >= '0' && c <= '9') return (Int)(c - '0');
58 return -1;
59}
60
sewardjb5f6f512005-03-10 23:59:00 +000061static Int readchar ( const Char* buf, Char* ch )
sewardjde4a1d02002-03-22 01:27:54 +000062{
63 if (*buf == 0) return 0;
64 *ch = *buf;
65 return 1;
66}
67
sewardjb5f6f512005-03-10 23:59:00 +000068static Int readhex ( const Char* buf, UWord* val )
sewardjde4a1d02002-03-22 01:27:54 +000069{
70 Int n = 0;
71 *val = 0;
72 while (hexdigit(*buf) >= 0) {
73 *val = (*val << 4) + hexdigit(*buf);
74 n++; buf++;
75 }
76 return n;
77}
78
sewardjb5f6f512005-03-10 23:59:00 +000079static Int readdec ( const Char* buf, UInt* val )
fitzhardinge98abfc72003-12-16 02:05:15 +000080{
81 Int n = 0;
82 *val = 0;
83 while (hexdigit(*buf) >= 0) {
84 *val = (*val * 10) + decdigit(*buf);
85 n++; buf++;
86 }
87 return n;
88}
89
sewardjde4a1d02002-03-22 01:27:54 +000090
sewardjb5f6f512005-03-10 23:59:00 +000091/* Read /proc/self/maps, store the contents into a static buffer. If
92 there's a syntax error or other failure, just abort. */
93
94static void read_procselfmaps ( void )
njn3e884182003-04-15 13:03:23 +000095{
96 Int n_chunk, fd;
97
98 /* Read the initial memory mapping from the /proc filesystem. */
99 fd = VG_(open) ( "/proc/self/maps", VKI_O_RDONLY, 0 );
jsgff3c3f1a2003-10-14 22:13:28 +0000100 if (fd < 0) {
njn3e884182003-04-15 13:03:23 +0000101 VG_(message)(Vg_UserMsg, "FATAL: can't open /proc/self/maps");
102 VG_(exit)(1);
103 }
104 buf_n_tot = 0;
105 do {
sewardjb5f6f512005-03-10 23:59:00 +0000106 n_chunk = VG_(read) ( fd, &procmap_buf[buf_n_tot],
njn3e884182003-04-15 13:03:23 +0000107 M_PROCMAP_BUF - buf_n_tot );
108 buf_n_tot += n_chunk;
109 } while ( n_chunk > 0 && buf_n_tot < M_PROCMAP_BUF );
110 VG_(close)(fd);
111 if (buf_n_tot >= M_PROCMAP_BUF-5) {
112 VG_(message)(Vg_UserMsg, "FATAL: M_PROCMAP_BUF is too small; "
113 "increase it and recompile");
114 VG_(exit)(1);
115 }
116 if (buf_n_tot == 0) {
117 VG_(message)(Vg_UserMsg, "FATAL: I/O error on /proc/self/maps" );
118 VG_(exit)(1);
119 }
120 procmap_buf[buf_n_tot] = 0;
121}
sewardjde4a1d02002-03-22 01:27:54 +0000122
njn3e884182003-04-15 13:03:23 +0000123/* Parse /proc/self/maps. For each map entry, call
sewardjde4a1d02002-03-22 01:27:54 +0000124 record_mapping, passing it, in this order:
125
126 start address in memory
127 length
sewardjb5f6f512005-03-10 23:59:00 +0000128 page protections (using the VKI_PROT_* flags)
129 mapped file device and inode
sewardjde4a1d02002-03-22 01:27:54 +0000130 offset in file, or zero if no file
131 filename, zero terminated, or NULL if no file
132
133 So the sig of the called fn might be
134
sewardjb5f6f512005-03-10 23:59:00 +0000135 void (*record_mapping)( Addr start, SizeT size, UInt prot,
136 UInt dev, UInt info,
nethercoted9255482004-10-26 10:19:30 +0000137 ULong foffset, UChar* filename )
sewardjde4a1d02002-03-22 01:27:54 +0000138
139 Note that the supplied filename is transiently stored; record_mapping
140 should make a copy if it wants to keep it.
141
njn3e884182003-04-15 13:03:23 +0000142 Nb: it is important that this function does not alter the contents of
143 procmap_buf!
sewardjde4a1d02002-03-22 01:27:54 +0000144*/
njnfa1016e2003-09-25 17:54:11 +0000145void VG_(parse_procselfmaps) (
sewardjb5f6f512005-03-10 23:59:00 +0000146 void (*record_mapping)( Addr addr, SizeT len, UInt prot,
fitzhardinge98abfc72003-12-16 02:05:15 +0000147 UInt dev, UInt ino, ULong foff, const UChar* filename )
148 )
sewardjde4a1d02002-03-22 01:27:54 +0000149{
njn3e884182003-04-15 13:03:23 +0000150 Int i, j, i_eol;
sewardjde4a1d02002-03-22 01:27:54 +0000151 Addr start, endPlusOne;
152 UChar* filename;
njn3e884182003-04-15 13:03:23 +0000153 UChar rr, ww, xx, pp, ch, tmp;
sewardjb5f6f512005-03-10 23:59:00 +0000154 UInt ino, prot;
nethercote6a27d832004-09-07 10:17:02 +0000155 UWord foffset, maj, min;
sewardjde4a1d02002-03-22 01:27:54 +0000156
sewardjb5f6f512005-03-10 23:59:00 +0000157 read_procselfmaps();
158
njnca82cc02004-11-22 17:18:48 +0000159 tl_assert( '\0' != procmap_buf[0] && 0 != buf_n_tot);
njn3e884182003-04-15 13:03:23 +0000160
sewardjde4a1d02002-03-22 01:27:54 +0000161 if (0)
162 VG_(message)(Vg_DebugMsg, "raw:\n%s", procmap_buf );
163
164 /* Ok, it's safely aboard. Parse the entries. */
sewardjde4a1d02002-03-22 01:27:54 +0000165 i = 0;
166 while (True) {
njn3e884182003-04-15 13:03:23 +0000167 if (i >= buf_n_tot) break;
sewardjde4a1d02002-03-22 01:27:54 +0000168
sewardj0a54cef2005-02-17 09:29:33 +0000169 /* Read (without fscanf :) the pattern %16x-%16x %c%c%c%c %16x %2x:%2x %d */
sewardjde4a1d02002-03-22 01:27:54 +0000170 j = readhex(&procmap_buf[i], &start);
171 if (j > 0) i += j; else goto syntaxerror;
172 j = readchar(&procmap_buf[i], &ch);
173 if (j == 1 && ch == '-') i += j; else goto syntaxerror;
174 j = readhex(&procmap_buf[i], &endPlusOne);
175 if (j > 0) i += j; else goto syntaxerror;
176
177 j = readchar(&procmap_buf[i], &ch);
178 if (j == 1 && ch == ' ') i += j; else goto syntaxerror;
179
180 j = readchar(&procmap_buf[i], &rr);
181 if (j == 1 && (rr == 'r' || rr == '-')) i += j; else goto syntaxerror;
182 j = readchar(&procmap_buf[i], &ww);
183 if (j == 1 && (ww == 'w' || ww == '-')) i += j; else goto syntaxerror;
184 j = readchar(&procmap_buf[i], &xx);
185 if (j == 1 && (xx == 'x' || xx == '-')) i += j; else goto syntaxerror;
fitzhardinge98abfc72003-12-16 02:05:15 +0000186 /* This field is the shared/private flag */
sewardjde4a1d02002-03-22 01:27:54 +0000187 j = readchar(&procmap_buf[i], &pp);
188 if (j == 1 && (pp == 'p' || pp == '-' || pp == 's'))
189 i += j; else goto syntaxerror;
190
191 j = readchar(&procmap_buf[i], &ch);
192 if (j == 1 && ch == ' ') i += j; else goto syntaxerror;
193
194 j = readhex(&procmap_buf[i], &foffset);
195 if (j > 0) i += j; else goto syntaxerror;
fitzhardinge98abfc72003-12-16 02:05:15 +0000196
197 j = readchar(&procmap_buf[i], &ch);
198 if (j == 1 && ch == ' ') i += j; else goto syntaxerror;
199
200 j = readhex(&procmap_buf[i], &maj);
201 if (j > 0) i += j; else goto syntaxerror;
202 j = readchar(&procmap_buf[i], &ch);
203 if (j == 1 && ch == ':') i += j; else goto syntaxerror;
204 j = readhex(&procmap_buf[i], &min);
205 if (j > 0) i += j; else goto syntaxerror;
206
207 j = readchar(&procmap_buf[i], &ch);
208 if (j == 1 && ch == ' ') i += j; else goto syntaxerror;
209
210 j = readdec(&procmap_buf[i], &ino);
211 if (j > 0) i += j; else goto syntaxerror;
212
sewardjde4a1d02002-03-22 01:27:54 +0000213 goto read_line_ok;
214
215 syntaxerror:
216 VG_(message)(Vg_UserMsg, "FATAL: syntax error reading /proc/self/maps");
217 { Int k;
218 VG_(printf)("last 50 chars: `");
219 for (k = i-50; k <= i; k++) VG_(printf)("%c", procmap_buf[k]);
220 VG_(printf)("'\n");
221 }
sewardjb5f6f512005-03-10 23:59:00 +0000222 VG_(exit)(1);
sewardjde4a1d02002-03-22 01:27:54 +0000223
224 read_line_ok:
njn25e49d8e72002-09-23 09:36:25 +0000225
sewardjde4a1d02002-03-22 01:27:54 +0000226 /* Try and find the name of the file mapped to this segment, if
227 it exists. */
sewardjb5f6f512005-03-10 23:59:00 +0000228 while (procmap_buf[i] != '\n' && i < buf_n_tot-1) i++;
sewardjde4a1d02002-03-22 01:27:54 +0000229 i_eol = i;
230 i--;
231 while (!VG_(isspace)(procmap_buf[i]) && i >= 0) i--;
232 i++;
233 if (i < i_eol-1 && procmap_buf[i] == '/') {
njn3e884182003-04-15 13:03:23 +0000234 /* Minor hack: put a '\0' at the filename end for the call to
235 `record_mapping', then restore the old char with `tmp'. */
sewardjde4a1d02002-03-22 01:27:54 +0000236 filename = &procmap_buf[i];
njn3e884182003-04-15 13:03:23 +0000237 tmp = filename[i_eol - i];
sewardjde4a1d02002-03-22 01:27:54 +0000238 filename[i_eol - i] = '\0';
239 } else {
sewardjb5f6f512005-03-10 23:59:00 +0000240 tmp = 0;
sewardjde4a1d02002-03-22 01:27:54 +0000241 filename = NULL;
242 foffset = 0;
243 }
244
sewardjb5f6f512005-03-10 23:59:00 +0000245 prot = 0;
246 if (rr == 'r') prot |= VKI_PROT_READ;
247 if (ww == 'w') prot |= VKI_PROT_WRITE;
248 if (xx == 'x') prot |= VKI_PROT_EXEC;
249
250 //if (start < VG_(valgrind_last))
sewardjde4a1d02002-03-22 01:27:54 +0000251 (*record_mapping) ( start, endPlusOne-start,
sewardjb5f6f512005-03-10 23:59:00 +0000252 prot, maj * 256 + min, ino,
sewardjde4a1d02002-03-22 01:27:54 +0000253 foffset, filename );
254
njn3e884182003-04-15 13:03:23 +0000255 if ('\0' != tmp) {
256 filename[i_eol - i] = tmp;
257 }
258
sewardjde4a1d02002-03-22 01:27:54 +0000259 i = i_eol + 1;
260 }
sewardjde4a1d02002-03-22 01:27:54 +0000261}
262
263/*--------------------------------------------------------------------*/
264/*--- end vg_procselfmaps.c ---*/
265/*--------------------------------------------------------------------*/