blob: 19f9ecc06fb3237271849d2201f15c0cc5b0bf32 [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/*
njnc9539842002-10-02 13:26:35 +00008 This file is part of Valgrind, an extensible x86 protected-mode
9 emulator for monitoring program execution on x86-Unixes.
sewardjde4a1d02002-03-22 01:27:54 +000010
nethercotebb1c9912004-01-04 16:43:23 +000011 Copyright (C) 2000-2004 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
35
36/* static ... to keep it out of the stack frame. */
sewardjde4a1d02002-03-22 01:27:54 +000037static Char procmap_buf[M_PROCMAP_BUF];
38
njn3e884182003-04-15 13:03:23 +000039/* Records length of /proc/self/maps read into procmap_buf. */
40static Int buf_n_tot;
41
sewardjde4a1d02002-03-22 01:27:54 +000042
43/* Helper fns. */
44
45static Int hexdigit ( Char c )
46{
47 if (c >= '0' && c <= '9') return (Int)(c - '0');
48 if (c >= 'a' && c <= 'f') return 10 + (Int)(c - 'a');
49 if (c >= 'A' && c <= 'F') return 10 + (Int)(c - 'A');
50 return -1;
51}
52
fitzhardinge98abfc72003-12-16 02:05:15 +000053static Int decdigit ( Char c )
54{
55 if (c >= '0' && c <= '9') return (Int)(c - '0');
56 return -1;
57}
58
sewardjde4a1d02002-03-22 01:27:54 +000059static Int readchar ( Char* buf, Char* ch )
60{
61 if (*buf == 0) return 0;
62 *ch = *buf;
63 return 1;
64}
65
nethercote6a27d832004-09-07 10:17:02 +000066static Int readhex ( Char* buf, UWord* val )
sewardjde4a1d02002-03-22 01:27:54 +000067{
68 Int n = 0;
69 *val = 0;
70 while (hexdigit(*buf) >= 0) {
71 *val = (*val << 4) + hexdigit(*buf);
72 n++; buf++;
73 }
74 return n;
75}
76
fitzhardinge98abfc72003-12-16 02:05:15 +000077static Int readdec ( Char* buf, UInt* val )
78{
79 Int n = 0;
80 *val = 0;
81 while (hexdigit(*buf) >= 0) {
82 *val = (*val * 10) + decdigit(*buf);
83 n++; buf++;
84 }
85 return n;
86}
87
sewardjde4a1d02002-03-22 01:27:54 +000088
njn3e884182003-04-15 13:03:23 +000089/* Read /proc/self/maps, store the contents in a static buffer. If there's
90 a syntax error or other failure, just abort. */
njnfa1016e2003-09-25 17:54:11 +000091void VG_(read_procselfmaps)(void)
njn3e884182003-04-15 13:03:23 +000092{
93 Int n_chunk, fd;
94
95 /* Read the initial memory mapping from the /proc filesystem. */
96 fd = VG_(open) ( "/proc/self/maps", VKI_O_RDONLY, 0 );
jsgff3c3f1a2003-10-14 22:13:28 +000097 if (fd < 0) {
njn3e884182003-04-15 13:03:23 +000098 VG_(message)(Vg_UserMsg, "FATAL: can't open /proc/self/maps");
99 VG_(exit)(1);
100 }
101 buf_n_tot = 0;
102 do {
103 n_chunk = VG_(read) ( fd, &procmap_buf[buf_n_tot],
104 M_PROCMAP_BUF - buf_n_tot );
105 buf_n_tot += n_chunk;
106 } while ( n_chunk > 0 && buf_n_tot < M_PROCMAP_BUF );
107 VG_(close)(fd);
108 if (buf_n_tot >= M_PROCMAP_BUF-5) {
109 VG_(message)(Vg_UserMsg, "FATAL: M_PROCMAP_BUF is too small; "
110 "increase it and recompile");
111 VG_(exit)(1);
112 }
113 if (buf_n_tot == 0) {
114 VG_(message)(Vg_UserMsg, "FATAL: I/O error on /proc/self/maps" );
115 VG_(exit)(1);
116 }
117 procmap_buf[buf_n_tot] = 0;
118}
sewardjde4a1d02002-03-22 01:27:54 +0000119
njn3e884182003-04-15 13:03:23 +0000120/* Parse /proc/self/maps. For each map entry, call
sewardjde4a1d02002-03-22 01:27:54 +0000121 record_mapping, passing it, in this order:
122
123 start address in memory
124 length
125 r permissions char; either - or r
126 w permissions char; either - or w
127 x permissions char; either - or x
128 offset in file, or zero if no file
129 filename, zero terminated, or NULL if no file
130
131 So the sig of the called fn might be
132
nethercote8991d5a2004-11-03 17:07:46 +0000133 void (*record_mapping)( Addr start, SizeT size,
sewardjde4a1d02002-03-22 01:27:54 +0000134 Char r, Char w, Char x,
nethercoted9255482004-10-26 10:19:30 +0000135 ULong foffset, UChar* filename )
sewardjde4a1d02002-03-22 01:27:54 +0000136
137 Note that the supplied filename is transiently stored; record_mapping
138 should make a copy if it wants to keep it.
139
njn3e884182003-04-15 13:03:23 +0000140 Nb: it is important that this function does not alter the contents of
141 procmap_buf!
sewardjde4a1d02002-03-22 01:27:54 +0000142*/
njnfa1016e2003-09-25 17:54:11 +0000143void VG_(parse_procselfmaps) (
nethercote8991d5a2004-11-03 17:07:46 +0000144 void (*record_mapping)( Addr addr, SizeT len, Char rr, Char ww, Char xx,
fitzhardinge98abfc72003-12-16 02:05:15 +0000145 UInt dev, UInt ino, ULong foff, const UChar* filename )
146 )
sewardjde4a1d02002-03-22 01:27:54 +0000147{
njn3e884182003-04-15 13:03:23 +0000148 Int i, j, i_eol;
sewardjde4a1d02002-03-22 01:27:54 +0000149 Addr start, endPlusOne;
150 UChar* filename;
njn3e884182003-04-15 13:03:23 +0000151 UChar rr, ww, xx, pp, ch, tmp;
nethercote6a27d832004-09-07 10:17:02 +0000152 UInt ino;
153 UWord foffset, maj, min;
sewardjde4a1d02002-03-22 01:27:54 +0000154
njnfa1016e2003-09-25 17:54:11 +0000155 sk_assert( '\0' != procmap_buf[0] && 0 != buf_n_tot);
njn3e884182003-04-15 13:03:23 +0000156
sewardjde4a1d02002-03-22 01:27:54 +0000157 if (0)
158 VG_(message)(Vg_DebugMsg, "raw:\n%s", procmap_buf );
159
160 /* Ok, it's safely aboard. Parse the entries. */
sewardjde4a1d02002-03-22 01:27:54 +0000161 i = 0;
162 while (True) {
njn3e884182003-04-15 13:03:23 +0000163 if (i >= buf_n_tot) break;
sewardjde4a1d02002-03-22 01:27:54 +0000164
fitzhardinge98abfc72003-12-16 02:05:15 +0000165 /* Read (without fscanf :) the pattern %8x-%8x %c%c%c%c %8x %2x:%2x %d */
sewardjde4a1d02002-03-22 01:27:54 +0000166 j = readhex(&procmap_buf[i], &start);
167 if (j > 0) i += j; else goto syntaxerror;
168 j = readchar(&procmap_buf[i], &ch);
169 if (j == 1 && ch == '-') i += j; else goto syntaxerror;
170 j = readhex(&procmap_buf[i], &endPlusOne);
171 if (j > 0) i += j; else goto syntaxerror;
172
173 j = readchar(&procmap_buf[i], &ch);
174 if (j == 1 && ch == ' ') i += j; else goto syntaxerror;
175
176 j = readchar(&procmap_buf[i], &rr);
177 if (j == 1 && (rr == 'r' || rr == '-')) i += j; else goto syntaxerror;
178 j = readchar(&procmap_buf[i], &ww);
179 if (j == 1 && (ww == 'w' || ww == '-')) i += j; else goto syntaxerror;
180 j = readchar(&procmap_buf[i], &xx);
181 if (j == 1 && (xx == 'x' || xx == '-')) i += j; else goto syntaxerror;
fitzhardinge98abfc72003-12-16 02:05:15 +0000182 /* This field is the shared/private flag */
sewardjde4a1d02002-03-22 01:27:54 +0000183 j = readchar(&procmap_buf[i], &pp);
184 if (j == 1 && (pp == 'p' || pp == '-' || pp == 's'))
185 i += j; else goto syntaxerror;
186
187 j = readchar(&procmap_buf[i], &ch);
188 if (j == 1 && ch == ' ') i += j; else goto syntaxerror;
189
190 j = readhex(&procmap_buf[i], &foffset);
191 if (j > 0) i += j; else goto syntaxerror;
fitzhardinge98abfc72003-12-16 02:05:15 +0000192
193 j = readchar(&procmap_buf[i], &ch);
194 if (j == 1 && ch == ' ') i += j; else goto syntaxerror;
195
196 j = readhex(&procmap_buf[i], &maj);
197 if (j > 0) i += j; else goto syntaxerror;
198 j = readchar(&procmap_buf[i], &ch);
199 if (j == 1 && ch == ':') i += j; else goto syntaxerror;
200 j = readhex(&procmap_buf[i], &min);
201 if (j > 0) i += j; else goto syntaxerror;
202
203 j = readchar(&procmap_buf[i], &ch);
204 if (j == 1 && ch == ' ') i += j; else goto syntaxerror;
205
206 j = readdec(&procmap_buf[i], &ino);
207 if (j > 0) i += j; else goto syntaxerror;
208
sewardjde4a1d02002-03-22 01:27:54 +0000209 goto read_line_ok;
210
211 syntaxerror:
212 VG_(message)(Vg_UserMsg, "FATAL: syntax error reading /proc/self/maps");
213 { Int k;
214 VG_(printf)("last 50 chars: `");
215 for (k = i-50; k <= i; k++) VG_(printf)("%c", procmap_buf[k]);
216 VG_(printf)("'\n");
217 }
218 VG_(exit)(1);
219
220 read_line_ok:
njn25e49d8e72002-09-23 09:36:25 +0000221
sewardjde4a1d02002-03-22 01:27:54 +0000222 /* Try and find the name of the file mapped to this segment, if
223 it exists. */
224 while (procmap_buf[i] != '\n' && i < M_PROCMAP_BUF-1) i++;
225 i_eol = i;
226 i--;
227 while (!VG_(isspace)(procmap_buf[i]) && i >= 0) i--;
228 i++;
229 if (i < i_eol-1 && procmap_buf[i] == '/') {
njn3e884182003-04-15 13:03:23 +0000230 /* Minor hack: put a '\0' at the filename end for the call to
231 `record_mapping', then restore the old char with `tmp'. */
sewardjde4a1d02002-03-22 01:27:54 +0000232 filename = &procmap_buf[i];
njn3e884182003-04-15 13:03:23 +0000233 tmp = filename[i_eol - i];
sewardjde4a1d02002-03-22 01:27:54 +0000234 filename[i_eol - i] = '\0';
235 } else {
njn3e884182003-04-15 13:03:23 +0000236 tmp = '\0';
sewardjde4a1d02002-03-22 01:27:54 +0000237 filename = NULL;
238 foffset = 0;
239 }
240
241 (*record_mapping) ( start, endPlusOne-start,
fitzhardinge98abfc72003-12-16 02:05:15 +0000242 rr, ww, xx, maj * 256 + min, ino,
sewardjde4a1d02002-03-22 01:27:54 +0000243 foffset, filename );
244
njn3e884182003-04-15 13:03:23 +0000245 if ('\0' != tmp) {
246 filename[i_eol - i] = tmp;
247 }
248
sewardjde4a1d02002-03-22 01:27:54 +0000249 i = i_eol + 1;
250 }
sewardjde4a1d02002-03-22 01:27:54 +0000251}
252
253/*--------------------------------------------------------------------*/
254/*--- end vg_procselfmaps.c ---*/
255/*--------------------------------------------------------------------*/