/* $Id$ */ #include #include #include #include #include #include #include #include "maps.h" #include "common.h" #include "hook.h" struct range { void *start; void *end; }; /* FIXME: Dynamic allocation. */ static struct range ranges[PAGE_SIZE * 8 / sizeof (struct range)]; static struct range *ranges_static_end = ranges; static struct range *ranges_end = ranges; /* = ranges_static_end */ /* Returns 0 on readable start..end-1. */ /* TODO: Sort + binary search. */ INTERNAL int maps_verify (void *start, void *end) { int changed; do { struct range *range; changed = 0; for (range = ranges; start < end && range < ranges_end; range++) if (start >= range->start && start < range->end) { start = range->end; changed = 1; } } while (start < end && changed); if (start < end) return -1; /* Success. */ return 0; } INTERNAL void maps_static_setup (void *start, void *end) { if (ranges_static_end >= ranges + N_ELEMENTS (ranges)) return; ranges_static_end->start = start; ranges_static_end->end = end; ranges_static_end++; if (debug >= 1) fprintf (stderr,"static: %p - %p\n", start, end); } INTERNAL void maps_read (void) { int fd; ssize_t bytes_read; char *s; /* Reset. */ ranges_end = ranges_static_end; /* Do not use level 3 I/O as it may be too SIGSEGV intrusive. */ fd = open (MAPS_FILENAME, O_RDONLY); if (fd == -1) return; bytes_read = read (fd, ranges_end, (char *) ranges + sizeof (ranges) - (char *) ranges_end - 1); if (close (fd)) return; if (bytes_read <= 0) return; s = (char *) ranges_end; s[bytes_read] = 0; while (*s) { unsigned long start, end; char prot_read, prot_write, prot_exec, prot_mayshare; int offset, i; const char *vdso_name = " [vdso]"; const size_t vdso_len = strlen (vdso_name); i = sscanf (s, "%lx-%lx %c%c%c%c %n", &start, &end, &prot_read, &prot_write, &prot_exec, &prot_mayshare, &offset); if (i != 6) break; s += offset; /* Reuse the trailing absolute pathname? Currently we use the relative one from dl_iterate_phdr(3). */ while (*s && *s != '\n') s++; /* Skip [vdso] entry to discard its dl_iterate_phdr(3) which has the same name as the main executable - "". */ if (s >= (char *) ranges + vdso_len && memcmp (s - vdso_len, vdso_name, vdso_len) == 0) continue; if (prot_read != 'r') continue; if (prot_write != '-') continue; if (prot_exec != 'x') continue; if (prot_mayshare != 'p') continue; ranges_end->start = (void *) start; ranges_end->end = (void *) end; ranges_end++; if (debug >= 1) fprintf (stderr,"range: %p - %p\n", (void *) start, (void *) end); if (ranges_end >= ranges + N_ELEMENTS (ranges)) return; } }