blob: 7998927b795240e2b2b0a07a7571b3f544ce412c [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
11 Copyright (C) 2000-2002 Julian Seward
12 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
33#include "vg_include.h"
34
35
36/* static ... to keep it out of the stack frame. */
37
38static Char procmap_buf[M_PROCMAP_BUF];
39
40
41/* Helper fns. */
42
43static Int hexdigit ( Char c )
44{
45 if (c >= '0' && c <= '9') return (Int)(c - '0');
46 if (c >= 'a' && c <= 'f') return 10 + (Int)(c - 'a');
47 if (c >= 'A' && c <= 'F') return 10 + (Int)(c - 'A');
48 return -1;
49}
50
51static Int readchar ( Char* buf, Char* ch )
52{
53 if (*buf == 0) return 0;
54 *ch = *buf;
55 return 1;
56}
57
58static Int readhex ( Char* buf, UInt* val )
59{
60 Int n = 0;
61 *val = 0;
62 while (hexdigit(*buf) >= 0) {
63 *val = (*val << 4) + hexdigit(*buf);
64 n++; buf++;
65 }
66 return n;
67}
68
69
70
71/* Read /proc/self/maps. For each map entry, call
72 record_mapping, passing it, in this order:
73
74 start address in memory
75 length
76 r permissions char; either - or r
77 w permissions char; either - or w
78 x permissions char; either - or x
79 offset in file, or zero if no file
80 filename, zero terminated, or NULL if no file
81
82 So the sig of the called fn might be
83
84 void (*record_mapping)( Addr start, UInt size,
85 Char r, Char w, Char x,
86 UInt foffset, UChar* filename )
87
88 Note that the supplied filename is transiently stored; record_mapping
89 should make a copy if it wants to keep it.
90
91 If there's a syntax error or other failure, just abort.
92*/
93
94void VG_(read_procselfmaps) (
95 void (*record_mapping)( Addr, UInt, Char, Char, Char, UInt, UChar* )
96)
97{
98 Int i, j, n_tot, n_chunk, fd, i_eol;
99 Addr start, endPlusOne;
100 UChar* filename;
101 UInt foffset;
102 UChar rr, ww, xx, pp, ch;
103
104 /* Read the initial memory mapping from the /proc filesystem. */
njn25e49d8e72002-09-23 09:36:25 +0000105 fd = VG_(open) ( "/proc/self/maps", VKI_O_RDONLY, 0 );
sewardjde4a1d02002-03-22 01:27:54 +0000106 if (fd == -1) {
107 VG_(message)(Vg_UserMsg, "FATAL: can't open /proc/self/maps");
108 VG_(exit)(1);
109 }
110 n_tot = 0;
111 do {
112 n_chunk = VG_(read) ( fd, &procmap_buf[n_tot], M_PROCMAP_BUF - n_tot );
113 n_tot += n_chunk;
114 } while ( n_chunk > 0 && n_tot < M_PROCMAP_BUF );
115 VG_(close)(fd);
116 if (n_tot >= M_PROCMAP_BUF-5) {
117 VG_(message)(Vg_UserMsg, "FATAL: M_PROCMAP_BUF is too small; "
118 "increase it and recompile");
119 VG_(exit)(1);
120 }
121 if (n_tot == 0) {
122 VG_(message)(Vg_UserMsg, "FATAL: I/O error on /proc/self/maps" );
123 VG_(exit)(1);
124 }
125 procmap_buf[n_tot] = 0;
126 if (0)
127 VG_(message)(Vg_DebugMsg, "raw:\n%s", procmap_buf );
128
129 /* Ok, it's safely aboard. Parse the entries. */
130
131 i = 0;
132 while (True) {
133 if (i >= n_tot) break;
134
135 /* Read (without fscanf :) the pattern %8x-%8x %c%c%c%c %8x */
136 j = readhex(&procmap_buf[i], &start);
137 if (j > 0) i += j; else goto syntaxerror;
138 j = readchar(&procmap_buf[i], &ch);
139 if (j == 1 && ch == '-') i += j; else goto syntaxerror;
140 j = readhex(&procmap_buf[i], &endPlusOne);
141 if (j > 0) i += j; else goto syntaxerror;
142
143 j = readchar(&procmap_buf[i], &ch);
144 if (j == 1 && ch == ' ') i += j; else goto syntaxerror;
145
146 j = readchar(&procmap_buf[i], &rr);
147 if (j == 1 && (rr == 'r' || rr == '-')) i += j; else goto syntaxerror;
148 j = readchar(&procmap_buf[i], &ww);
149 if (j == 1 && (ww == 'w' || ww == '-')) i += j; else goto syntaxerror;
150 j = readchar(&procmap_buf[i], &xx);
151 if (j == 1 && (xx == 'x' || xx == '-')) i += j; else goto syntaxerror;
152 /* I haven't a clue what this last field means. */
153 j = readchar(&procmap_buf[i], &pp);
154 if (j == 1 && (pp == 'p' || pp == '-' || pp == 's'))
155 i += j; else goto syntaxerror;
156
157 j = readchar(&procmap_buf[i], &ch);
158 if (j == 1 && ch == ' ') i += j; else goto syntaxerror;
159
160 j = readhex(&procmap_buf[i], &foffset);
161 if (j > 0) i += j; else goto syntaxerror;
162
163 goto read_line_ok;
164
165 syntaxerror:
166 VG_(message)(Vg_UserMsg, "FATAL: syntax error reading /proc/self/maps");
167 { Int k;
168 VG_(printf)("last 50 chars: `");
169 for (k = i-50; k <= i; k++) VG_(printf)("%c", procmap_buf[k]);
170 VG_(printf)("'\n");
171 }
172 VG_(exit)(1);
173
174 read_line_ok:
njn25e49d8e72002-09-23 09:36:25 +0000175
sewardjde4a1d02002-03-22 01:27:54 +0000176 /* Try and find the name of the file mapped to this segment, if
177 it exists. */
178 while (procmap_buf[i] != '\n' && i < M_PROCMAP_BUF-1) i++;
179 i_eol = i;
180 i--;
181 while (!VG_(isspace)(procmap_buf[i]) && i >= 0) i--;
182 i++;
183 if (i < i_eol-1 && procmap_buf[i] == '/') {
184 filename = &procmap_buf[i];
185 filename[i_eol - i] = '\0';
186 } else {
187 filename = NULL;
188 foffset = 0;
189 }
190
191 (*record_mapping) ( start, endPlusOne-start,
192 rr, ww, xx,
193 foffset, filename );
194
195 i = i_eol + 1;
196 }
197}
198
199/*--------------------------------------------------------------------*/
200/*--- end vg_procselfmaps.c ---*/
201/*--------------------------------------------------------------------*/