#ifndef os_linux_h
#define os_linux_h
struct map_iterator
{
off_t offset;
int fd;
size_t buf_size;
char *buf;
char *buf_end;
char *path;
};
static inline char *
unw_ltoa (char *buf, long val)
{
char *cp = buf, tmp;
ssize_t i, len;
do
{
*cp++ = '0' + (val % 10);
val /= 10;
}
while (val);
len = cp - buf;
--cp;
for (i = 0; i < len / 2; ++i)
{
tmp = buf[i];
buf[i] = cp[-i];
cp[-i] = tmp;
}
return buf + len;
}
static inline int
maps_init (struct map_iterator *mi, pid_t pid)
{
char path[sizeof ("/proc/0123456789/maps")], *cp;
memcpy (path, "/proc/", 6);
cp = unw_ltoa (path + 6, pid);
assert (cp + 6 < path + sizeof (path));
memcpy (cp, "/maps", 6);
mi->fd = open (path, O_RDONLY);
if (mi->fd >= 0)
{
mi->buf_size = getpagesize ();
GET_MEMORY (cp, mi->buf_size);
if (!cp)
{
close(mi->fd);
mi->fd = -1;
return -1;
}
else
{
mi->offset = 0;
mi->buf = mi->buf_end = cp + mi->buf_size;
return 0;
}
}
return -1;
}
static inline char *
skip_whitespace (char *cp)
{
if (!cp)
return NULL;
while (*cp == ' ' || *cp == '\t')
++cp;
return cp;
}
static inline char *
scan_hex (char *cp, unsigned long *valp)
{
unsigned long num_digits = 0, digit, val = 0;
cp = skip_whitespace (cp);
if (!cp)
return NULL;
while (1)
{
digit = *cp;
if ((digit - '0') <= 9)
digit -= '0';
else if ((digit - 'A') < 6)
digit -= 'A' - 10;
else if ((digit - 'a') < 6)
digit -= 'a' - 10;
else
break;
val = (val << 4) | digit;
++num_digits;
++cp;
}
if (!num_digits)
return NULL;
*valp = val;
return cp;
}
static inline char *
scan_dec (char *cp, unsigned long *valp)
{
unsigned long num_digits = 0, digit, val = 0;
if (!(cp = skip_whitespace (cp)))
return NULL;
while (1)
{
digit = *cp;
if ((digit - '0') <= 9)
{
digit -= '0';
++cp;
}
else
break;
val = (10 * val) + digit;
++num_digits;
}
if (!num_digits)
return NULL;
*valp = val;
return cp;
}
static inline char *
scan_char (char *cp, char *valp)
{
if (!cp)
return NULL;
*valp = *cp;
if (*cp)
++cp;
return cp;
}
static inline char *
scan_string (char *cp, char *valp, size_t buf_size)
{
size_t i = 0;
if (!(cp = skip_whitespace (cp)))
return NULL;
while (*cp != ' ' && *cp != '\t' && *cp != '\0')
{
if ((valp != NULL) && (i < buf_size - 1))
valp[i++] = *cp;
++cp;
}
if (i == 0 || i >= buf_size)
return NULL;
valp[i] = '\0';
return cp;
}
static inline int
maps_next (struct map_iterator *mi,
unsigned long *low, unsigned long *high, unsigned long *offset,
unsigned long *flags)
{
char perm[16], dash = 0, colon = 0, *cp;
unsigned long major, minor, inum;
ssize_t i, nread;
if (mi->fd < 0)
return 0;
while (1)
{
ssize_t bytes_left = mi->buf_end - mi->buf;
char *eol = NULL;
for (i = 0; i < bytes_left; ++i)
{
if (mi->buf[i] == '\n')
{
eol = mi->buf + i;
break;
}
else if (mi->buf[i] == '\0')
break;
}
if (!eol)
{
if (bytes_left > 0)
memmove (mi->buf_end - mi->buf_size, mi->buf, bytes_left);
mi->buf = mi->buf_end - mi->buf_size;
nread = read (mi->fd, mi->buf + bytes_left,
mi->buf_size - bytes_left);
if (nread <= 0)
return 0;
else if ((size_t) (nread + bytes_left) < mi->buf_size)
{
memmove (mi->buf_end - nread - bytes_left, mi->buf,
nread + bytes_left);
mi->buf = mi->buf_end - nread - bytes_left;
}
eol = mi->buf + bytes_left + nread - 1;
for (i = bytes_left; i < bytes_left + nread; ++i)
if (mi->buf[i] == '\n')
{
eol = mi->buf + i;
break;
}
}
cp = mi->buf;
mi->buf = eol + 1;
*eol = '\0';
cp = scan_hex (cp, low);
cp = scan_char (cp, &dash);
cp = scan_hex (cp, high);
cp = scan_string (cp, perm, sizeof (perm));
cp = scan_hex (cp, offset);
cp = scan_hex (cp, &major);
cp = scan_char (cp, &colon);
cp = scan_hex (cp, &minor);
cp = scan_dec (cp, &inum);
cp = mi->path = skip_whitespace (cp);
if (!cp)
continue;
cp = scan_string (cp, NULL, 0);
if (dash != '-' || colon != ':')
continue;
if (flags)
{
*flags = 0;
if (perm[0] == 'r')
{
*flags |= PROT_READ;
}
if (perm[1] == 'w')
{
*flags |= PROT_WRITE;
}
if (perm[2] == 'x')
{
*flags |= PROT_EXEC;
}
}
return 1;
}
return 0;
}
static inline void
maps_close (struct map_iterator *mi)
{
if (mi->fd < 0)
return;
close (mi->fd);
mi->fd = -1;
if (mi->buf)
{
mi_munmap (mi->buf_end - mi->buf_size, mi->buf_size);
mi->buf = mi->buf_end = NULL;
}
}
#endif