1 /* libunwind - a platform-independent unwind library
2 Copyright (C) 2003-2004 Hewlett-Packard Co
3 Copyright (C) 2007 David Mosberger-Tang
4 Contributed by David Mosberger-Tang <dmosberger@gmail.com>
6 This file is part of libunwind.
8 Permission is hereby granted, free of charge, to any person obtaining
9 a copy of this software and associated documentation files (the
10 "Software"), to deal in the Software without restriction, including
11 without limitation the rights to use, copy, modify, merge, publish,
12 distribute, sublicense, and/or sell copies of the Software, and to
13 permit persons to whom the Software is furnished to do so, subject to
14 the following conditions:
16 The above copyright notice and this permission notice shall be
17 included in all copies or substantial portions of the Software.
19 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
22 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
23 LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
24 OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
25 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
41 ltoa (char *buf
, long val
)
48 *cp
++ = '0' + (val
% 10);
53 /* reverse the order of the digits: */
56 for (i
= 0; i
< len
/ 2; ++i
)
66 maps_init (struct map_iterator
*mi
, pid_t pid
)
68 char path
[sizeof ("/proc/0123456789/maps")], *cp
;
70 memcpy (path
, "/proc/", 6);
71 cp
= ltoa (path
+ 6, pid
);
72 assert (cp
+ 6 < path
+ sizeof (path
));
73 memcpy (cp
, "/maps", 6);
75 mi
->fd
= open (path
, O_RDONLY
);
78 /* Try to allocate a page-sized buffer. */
79 mi
->buf_size
= getpagesize ();
80 cp
= mmap (NULL
, mi
->buf_size
, PROT_READ
| PROT_WRITE
,
81 MAP_PRIVATE
| MAP_ANONYMOUS
, -1, 0);
91 mi
->buf
= mi
->buf_end
= cp
+ mi
->buf_size
;
99 skip_whitespace (char *cp
)
104 while (*cp
== ' ' || *cp
== '\t')
110 scan_hex (char *cp
, unsigned long *valp
)
112 unsigned long num_digits
= 0, digit
, val
= 0;
114 cp
= skip_whitespace (cp
);
121 if ((digit
- '0') <= 9)
123 else if ((digit
- 'a') < 6)
125 else if ((digit
- 'A') < 6)
129 val
= (val
<< 4) | digit
;
140 scan_dec (char *cp
, unsigned long *valp
)
142 unsigned long num_digits
= 0, digit
, val
= 0;
144 if (!(cp
= skip_whitespace (cp
)))
150 if ((digit
- '0') <= 9)
157 val
= (10 * val
) + digit
;
167 scan_char (char *cp
, char *valp
)
174 /* don't step over NUL terminator */
180 /* Scan a string delimited by white-space. Fails on empty string or
181 if string is doesn't fit in the specified buffer. */
183 scan_string (char *cp
, char *valp
, size_t buf_size
)
187 if (!(cp
= skip_whitespace (cp
)))
190 while (*cp
!= ' ' && *cp
!= '\t' && *cp
!= '\0')
192 if ((valp
!= NULL
) && (i
< buf_size
- 1))
196 if (i
== 0 || i
>= buf_size
)
203 maps_next (struct map_iterator
*mi
,
204 unsigned long *low
, unsigned long *high
, unsigned long *offset
)
206 char perm
[16], dash
= 0, colon
= 0, *cp
;
207 unsigned long major
, minor
, inum
;
215 ssize_t bytes_left
= mi
->buf_end
- mi
->buf
;
218 for (i
= 0; i
< bytes_left
; ++i
)
220 if (mi
->buf
[i
] == '\n')
225 else if (mi
->buf
[i
] == '\0')
230 /* copy down the remaining bytes, if any */
232 memmove (mi
->buf_end
- mi
->buf_size
, mi
->buf
, bytes_left
);
234 mi
->buf
= mi
->buf_end
- mi
->buf_size
;
235 nread
= read (mi
->fd
, mi
->buf
+ bytes_left
,
236 mi
->buf_size
- bytes_left
);
239 else if ((size_t) (nread
+ bytes_left
) < mi
->buf_size
)
241 /* Move contents to the end of the buffer so we
242 maintain the invariant that all bytes between
243 mi->buf and mi->buf_end are valid. */
244 memmove (mi
->buf_end
- nread
- bytes_left
, mi
->buf
,
246 mi
->buf
= mi
->buf_end
- nread
- bytes_left
;
249 eol
= mi
->buf
+ bytes_left
+ nread
- 1;
251 for (i
= bytes_left
; i
< bytes_left
+ nread
; ++i
)
252 if (mi
->buf
[i
] == '\n')
262 /* scan: "LOW-HIGH PERM OFFSET MAJOR:MINOR INUM PATH" */
263 cp
= scan_hex (cp
, low
);
264 cp
= scan_char (cp
, &dash
);
265 cp
= scan_hex (cp
, high
);
266 cp
= scan_string (cp
, perm
, sizeof (perm
));
267 cp
= scan_hex (cp
, offset
);
268 cp
= scan_hex (cp
, &major
);
269 cp
= scan_char (cp
, &colon
);
270 cp
= scan_hex (cp
, &minor
);
271 cp
= scan_dec (cp
, &inum
);
272 cp
= mi
->path
= skip_whitespace (cp
);
275 cp
= scan_string (cp
, NULL
, 0);
276 if (dash
!= '-' || colon
!= ':')
277 continue; /* skip line with unknown or bad format */
284 maps_close (struct map_iterator
*mi
)
292 munmap (mi
->buf_end
- mi
->buf_size
, mi
->buf_size
);
293 mi
->buf
= mi
->buf_end
= NULL
;
297 #endif /* os_linux_h */