blob: ceba7b3bf0b43a683fb117b8d6c60993c098e2bd [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/*
8 This file is part of Valgrind, an x86 protected-mode emulator
9 designed for debugging and profiling binaries on x86-Unixes.
10
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
29 The GNU General Public License is contained in the file LICENSE.
30*/
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. */
105 fd = VG_(open_read) ( "/proc/self/maps" );
106 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:
175 /* Try and find the name of the file mapped to this segment, if
176 it exists. */
177 while (procmap_buf[i] != '\n' && i < M_PROCMAP_BUF-1) i++;
178 i_eol = i;
179 i--;
180 while (!VG_(isspace)(procmap_buf[i]) && i >= 0) i--;
181 i++;
182 if (i < i_eol-1 && procmap_buf[i] == '/') {
183 filename = &procmap_buf[i];
184 filename[i_eol - i] = '\0';
185 } else {
186 filename = NULL;
187 foffset = 0;
188 }
189
190 (*record_mapping) ( start, endPlusOne-start,
191 rr, ww, xx,
192 foffset, filename );
193
194 i = i_eol + 1;
195 }
196}
197
198/*--------------------------------------------------------------------*/
199/*--- end vg_procselfmaps.c ---*/
200/*--------------------------------------------------------------------*/