blob: 68342e90dbc035de42e61b2c56040afe998f22d7 [file] [log] [blame]
mostang.com!davidm824d6612003-02-08 10:10:59 +00001/* libunwind - a platform-independent unwind library
mostang.com!davidm64c702c2004-03-31 07:38:06 +00002 Copyright (C) 2003-2004 Hewlett-Packard Co
mostang.com!davidm824d6612003-02-08 10:10:59 +00003 Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
4
5This file is part of libunwind.
6
7Permission is hereby granted, free of charge, to any person obtaining
8a copy of this software and associated documentation files (the
9"Software"), to deal in the Software without restriction, including
10without limitation the rights to use, copy, modify, merge, publish,
11distribute, sublicense, and/or sell copies of the Software, and to
12permit persons to whom the Software is furnished to do so, subject to
13the following conditions:
14
15The above copyright notice and this permission notice shall be
16included in all copies or substantial portions of the Software.
17
18THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
22LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
24WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
25
26#ifndef os_linux_h
27#define os_linux_h
28
29struct map_iterator
30 {
mostang.com!davidm64c702c2004-03-31 07:38:06 +000031 off_t offset;
32 int fd;
mostang.com!davidm824d6612003-02-08 10:10:59 +000033 };
34
mostang.com!davidm64c702c2004-03-31 07:38:06 +000035static inline char *
36ltoa (char *buf, long val)
37{
38 char *cp = buf, tmp;
39 ssize_t i, len;
40
41 do
42 {
43 *cp++ = '0' + (val % 10);
44 val /= 10;
45 }
46 while (val);
47
48 /* reverse the order of the digits: */
49 len = cp - buf;
50 --cp;
51 for (i = 0; i < len / 2; ++i)
52 {
53 tmp = buf[i];
54 buf[i] = cp[-i];
55 cp[-i] = tmp;
56 }
57 return buf + len;
58}
59
mostang.com!davidm824d6612003-02-08 10:10:59 +000060static inline void
61maps_init (struct map_iterator *mi, pid_t pid)
62{
mostang.com!davidm64c702c2004-03-31 07:38:06 +000063 char path[PATH_MAX], *cp;
mostang.com!davidm824d6612003-02-08 10:10:59 +000064
mostang.com!davidm64c702c2004-03-31 07:38:06 +000065 memcpy (path, "/proc/", 6);
66 cp = ltoa (path + 6, pid);
67 memcpy (cp, "/maps", 6);
68
69 mi->fd = open (path, O_RDONLY);
70 mi->offset = 0;
71}
72
73static inline char *
74skip_whitespace (char *cp)
75{
76 if (!cp)
77 return NULL;
78
79 while (*cp == ' ' || *cp == '\t')
80 ++cp;
81 return cp;
82}
83
84static inline char *
85scan_hex (char *cp, unsigned long *valp)
86{
87 unsigned long num_digits = 0, digit, val = 0;
88
89 cp = skip_whitespace (cp);
90 if (!cp)
91 return NULL;
92
93 while (1)
94 {
95 digit = *cp;
96 if ((digit - '0') <= 9)
97 digit -= '0';
98 else if ((digit - 'a') < 6)
99 digit -= 'a' - 10;
100 else if ((digit - 'A') < 6)
101 digit -= 'A' - 10;
102 else
103 break;
104 val = (val << 4) | digit;
105 ++num_digits;
106 ++cp;
107 }
108 if (!num_digits)
109 return NULL;
110 *valp = val;
111 return cp;
112}
113
114static inline char *
115scan_dec (char *cp, unsigned long *valp)
116{
117 unsigned long num_digits = 0, digit, val = 0;
118
119 if (!(cp = skip_whitespace (cp)))
120 return NULL;
121
122 while (1)
123 {
124 digit = *cp++;
125 if ((digit - '0') <= 9)
126 digit -= '0';
127 else
128 break;
129 val = (10 * val) + digit;
130 ++num_digits;
131 }
132 if (!num_digits)
133 return NULL;
134 *valp = val;
135 return cp;
136}
137
138static inline char *
139scan_char (char *cp, char *valp)
140{
141 if (!cp)
142 return NULL;
143
144 *valp = *cp++;
145 return cp;
146}
147
148/* Scan a string delimited by white-space. Fails on empty string or
149 if string is doesn't fit in the specified buffer. */
150static inline char *
151scan_string (char *cp, char *valp, size_t buf_size)
152{
153 size_t i = 0;
154
155 if (!(cp = skip_whitespace (cp)))
156 return NULL;
157
158 while (*cp != ' ' && *cp != '\t' && *cp != '\0')
159 {
160 if (i < buf_size - 1)
161 valp[i++] = *cp;
162 ++cp;
163 }
164 if (i == 0 || i >= buf_size)
165 return NULL;
166 valp[i] = '\0';
167 return cp;
mostang.com!davidm824d6612003-02-08 10:10:59 +0000168}
169
170static inline int
171maps_next (struct map_iterator *mi,
172 unsigned long *low, unsigned long *high, unsigned long *offset,
mostang.com!davidm64c702c2004-03-31 07:38:06 +0000173 char *path, size_t path_size)
mostang.com!davidm824d6612003-02-08 10:10:59 +0000174{
mostang.com!davidm64c702c2004-03-31 07:38:06 +0000175 char line[256 + PATH_MAX], perm[16], dash, colon, *cp;
176 unsigned long major, minor, inum;
177 size_t to_read = 256; /* most lines fit in 256 characters easy */
178 ssize_t i, nread;
mostang.com!davidm824d6612003-02-08 10:10:59 +0000179
mostang.com!davidm64c702c2004-03-31 07:38:06 +0000180 if (mi->fd < 0)
mostang.com!davidm824d6612003-02-08 10:10:59 +0000181 return 0;
182
mostang.com!davidm64c702c2004-03-31 07:38:06 +0000183 while (1)
mostang.com!davidm824d6612003-02-08 10:10:59 +0000184 {
mostang.com!davidm64c702c2004-03-31 07:38:06 +0000185 lseek (mi->fd, mi->offset, SEEK_SET);
186
187 if ((nread = read (mi->fd, line, to_read)) <= 0)
188 return 0;
189 for (i = 0; i < nread && line[i] != '\n'; ++i)
190 /* skip */;
191 if (i < nread)
192 {
193 line[i] = '\0';
194 mi->offset += i + 1;
195 }
196 else
197 {
198 if (to_read < sizeof (line))
199 to_read = sizeof (line) - 1;
200 else
201 mi->offset += nread; /* not supposed to happen... */
202 continue; /* duh, no newline found */
203 }
204
205 /* scan: "LOW-HIGH PERM OFFSET MAJOR:MINOR INUM PATH" */
206 cp = scan_hex (line, low);
207 cp = scan_char (cp, &dash);
208 cp = scan_hex (cp, high);
209 cp = scan_string (cp, perm, sizeof (perm));
210 cp = scan_hex (cp, offset);
211 cp = scan_hex (cp, &major);
212 cp = scan_char (cp, &colon);
213 cp = scan_hex (cp, &minor);
214 cp = scan_dec (cp, &inum);
215 cp = scan_string (cp, path, path_size);
216 if (!cp || dash != '-' || colon != ':')
217 continue; /* skip line with unknown or bad format */
218 return 1;
mostang.com!davidm824d6612003-02-08 10:10:59 +0000219 }
220 return 0;
221}
222
223static inline void
224maps_close (struct map_iterator *mi)
225{
mostang.com!davidm64c702c2004-03-31 07:38:06 +0000226 if (mi->fd < 0)
hp.com!davidmcfded022003-03-29 07:32:50 +0000227 return;
mostang.com!davidm64c702c2004-03-31 07:38:06 +0000228 close (mi->fd);
229 mi->fd = -1;
mostang.com!davidm824d6612003-02-08 10:10:59 +0000230}
231
232#endif /* os_linux_h */