ProcMapEntry
Description
One line of /proc/self/maps. path is borrowed from the ProcMaps.raw buffer and stays valid until ProcMapsDeinit. May be empty for anonymous mappings (heap, stacks, vdso, etc.).
Usage example (Cross-references)
Usage examples (Cross-references)
- In
ProcMaps.h:43:
u64 file_offset; // offset within the backing file
Zstr path; // backing file path, or "" if anonymous
} ProcMapEntry;
typedef Vec(ProcMapEntry) ProcMapEntries;- In
ProcMaps.h:45:
} ProcMapEntry;
typedef Vec(ProcMapEntry) ProcMapEntries;
typedef struct ProcMaps {- In
ProcMaps.h:92:
/// TAGS: Sys, ProcMaps, Find, Lookup
///
const ProcMapEntry *ProcMapsFindByAddr(const ProcMaps *self, u64 addr);
#endif // MISRA_SYS_PROC_MAPS_H
u64 addr = (u64)runtime_addr;
const ProcMapEntry *entry = ProcMapsFindByAddr(&self->maps, addr);
if (!entry || !entry->path || entry->path[0] == '\0')
return false; u64 addr = (u64)runtime_addr;
const ProcMapEntry *entry = ProcMapsFindByAddr(&self->maps, addr);
if (!entry || !entry->path || entry->path[0] == '\0') {
return false;- In
ProcMaps.c:96:
// advanced past the line terminator so the next call resumes at the
// next line.
static bool parse_one_line(StrIter *si, ProcMapEntry *out) {
u64 start = 0, ende = 0, offset = 0;
if (!parse_hex_u64(si, &start))- In
ProcMaps.c:224:
StrIter si = StrIterFromStr(out->raw);
while (StrIterRemainingLength(&si)) {
ProcMapEntry e = {0};
if (!parse_one_line(&si, &e)) {
// Skip past whatever line we couldn't parse.
- In
ProcMaps.c:244:
// Cache the lowest mapped address so callers don't rescan the vector.
for (u64 i = 0; i < VecLen(&out->entries); ++i) {
const ProcMapEntry *e = VecPtrAt(&out->entries, i);
if (i == 0 || e->start < out->min_addr)
out->min_addr = e->start;- In
ProcMaps.c:260:
}
const ProcMapEntry *ProcMapsFindByAddr(const ProcMaps *self, u64 addr) {
if (!self)
return NULL;- In
ProcMaps.c:264:
return NULL;
for (u64 i = 0; i < VecLen(&self->entries); ++i) {
const ProcMapEntry *e = VecPtrAt(&self->entries, i);
if (addr >= e->start && addr < e->end) {
return e; if (ProcMapsLoad(&maps, ALLOCATOR_OF(&a))) {
for (u64 i = 0; i < VecLen(&maps.entries); ++i) {
const ProcMapEntry *m = VecPtrAt(&maps.entries, i);
if (m->path && m->path[0] == '/' && (m->perms & PROC_MAP_PERM_EXEC) &&
ZstrCompare(m->path, self_path) != 0) { pm.entries = VecInitT(pm.entries, ALLOCATOR_OF(&alloc));
ProcMapEntry e0 = {.start = 0x1000, .end = 0x2000, .perms = 0, .file_offset = 0, .path = ""};
ProcMapEntry e1 = {.start = 0x3000, .end = 0x4000, .perms = 0, .file_offset = 0, .path = ""};
ProcMapEntry e2 = {.start = 0x5000, .end = 0x6000, .perms = 0, .file_offset = 0, .path = ""};
ProcMapEntry e0 = {.start = 0x1000, .end = 0x2000, .perms = 0, .file_offset = 0, .path = ""};
ProcMapEntry e1 = {.start = 0x3000, .end = 0x4000, .perms = 0, .file_offset = 0, .path = ""};
ProcMapEntry e2 = {.start = 0x5000, .end = 0x6000, .perms = 0, .file_offset = 0, .path = ""}; ProcMapEntry e0 = {.start = 0x1000, .end = 0x2000, .perms = 0, .file_offset = 0, .path = ""};
ProcMapEntry e1 = {.start = 0x3000, .end = 0x4000, .perms = 0, .file_offset = 0, .path = ""};
ProcMapEntry e2 = {.start = 0x5000, .end = 0x6000, .perms = 0, .file_offset = 0, .path = ""};
bool pushed = VecPushBackR(&pm.entries, e0) && VecPushBackR(&pm.entries, e1) && VecPushBackR(&pm.entries, e2);
// 0x5500 is inside the stale e2 range only — must be unreachable.
const ProcMapEntry *hit = ProcMapsFindByAddr(&pm, 0x5500);
bool ok = (hit == NULL);
// Sanity: live entries are still found at the right slots.
const ProcMapEntry *h0 = ProcMapsFindByAddr(&pm, 0x1500);
const ProcMapEntry *h1 = ProcMapsFindByAddr(&pm, 0x3500);
ok = ok && h0 != NULL && h0->start == 0x1000 && h1 != NULL && h1->start == 0x3000; // Sanity: live entries are still found at the right slots.
const ProcMapEntry *h0 = ProcMapsFindByAddr(&pm, 0x1500);
const ProcMapEntry *h1 = ProcMapsFindByAddr(&pm, 0x3500);
ok = ok && h0 != NULL && h0->start == 0x1000 && h1 != NULL && h1->start == 0x3000; u64 n = copy_line(buf, sizeof(buf), "1000-2000 r-xp 0000dead 08:01 12345 /x/y\n");
StrIter si = StrIterFromCstr(buf, n); // includes trailing '\n'
ProcMapEntry e = {0};
bool ok = parse_one_line(&si, &e);
if (!ok) u64 n = copy_line(buf, sizeof(buf), "0-1 rw-s 0 0:0 0 \n");
StrIter si = StrIterFromCstr(buf, n);
ProcMapEntry e = {0};
if (!parse_one_line(&si, &e))
return false; u64 n = copy_line(buf, sizeof(buf), "0-1 ---p 0 0:0 0 \n");
StrIter si = StrIterFromCstr(buf, n);
ProcMapEntry e = {0};
if (!parse_one_line(&si, &e))
return false; u64 n = copy_line(buf, sizeof(buf), "0-1 r--s 0 0:0 0 \n");
StrIter si = StrIterFromCstr(buf, n);
ProcMapEntry e = {0};
if (!parse_one_line(&si, &e))
return false; u64 n = copy_line(buf, sizeof(buf), "0-1 -w-s 0 0:0 0 \n");
StrIter si = StrIterFromCstr(buf, n);
ProcMapEntry e = {0};
if (!parse_one_line(&si, &e))
return false; u64 n = copy_line(buf, sizeof(buf), "0-1 --xs 0 0:0 0 \n");
StrIter si = StrIterFromCstr(buf, n);
ProcMapEntry e = {0};
if (!parse_one_line(&si, &e))
return false; u64 n = copy_line(buf, sizeof(buf), "0-1 ---p 0 0:0 0 \n");
StrIter si = StrIterFromCstr(buf, n);
ProcMapEntry e = {0};
if (!parse_one_line(&si, &e))
return false; u64 n = copy_line(buf, sizeof(buf), "0-1 ---p 0 0:0 0 \n");
StrIter si = StrIterFromCstr(buf, n);
ProcMapEntry e = {0};
if (!parse_one_line(&si, &e))
return false; u64 n = copy_line(buf, sizeof(buf), "0-1 ---p 0 0:0 0 [stack]\n");
StrIter si = StrIterFromCstr(buf, n);
ProcMapEntry e = {0};
if (!parse_one_line(&si, &e))
return false; u64 n = copy_line(buf, sizeof(buf), "0-1 ---p 0 0:0 0 /a b/c\n");
StrIter si = StrIterFromCstr(buf, n);
ProcMapEntry e = {0};
if (!parse_one_line(&si, &e))
return false; u64 n = copy_line(buf, sizeof(buf), "7f8b8c000000-7f8b8c021000 r-xp 00001000 08:01 1234 /lib/libc.so.6\n");
StrIter si = StrIterFromCstr(buf, n);
ProcMapEntry e = {0};
if (!parse_one_line(&si, &e))
return false; u64 n = copy_line(buf, sizeof(buf), "1000 2000 r-xp 0 0:0 0 \n");
StrIter si = StrIterFromCstr(buf, n);
ProcMapEntry e = {0};
return !parse_one_line(&si, &e);
} u64 n = copy_line(buf, sizeof(buf), "xyz-2000 r-xp 0 0:0 0 \n");
StrIter si = StrIterFromCstr(buf, n);
ProcMapEntry e = {0};
return !parse_one_line(&si, &e);
} u64 n = copy_line(buf, sizeof(buf), "1000-2000 rw");
StrIter si = StrIterFromCstr(buf, n);
ProcMapEntry e = {0};
return !parse_one_line(&si, &e);
} u64 n = copy_line(buf, sizeof(buf), "1000-2000 r-xp dead 08:01 99 /z");
StrIter si = StrIterFromCstr(buf, n);
ProcMapEntry e = {0};
if (!parse_one_line(&si, &e))
return false; u64 n = copy_line(buf, sizeof(buf), "1000-2000 r-xp 0 0:0 0 /a\n3000-4000 rw-p 0 0:0 0 /b\n");
StrIter si = StrIterFromCstr(buf, n);
ProcMapEntry e1 = {0};
ProcMapEntry e2 = {0};
if (!parse_one_line(&si, &e1)) StrIter si = StrIterFromCstr(buf, n);
ProcMapEntry e1 = {0};
ProcMapEntry e2 = {0};
if (!parse_one_line(&si, &e1))
return false; u64 n = copy_line(buf, sizeof(buf), "1000-2000 r-xp 0 0:0 0 /first\n3000-4000 rw-p 0 0:0 0 /second\n");
StrIter si = StrIterFromCstr(buf, n);
ProcMapEntry e1 = {0};
if (!parse_one_line(&si, &e1))
return false;- In
ProcMaps.c:53:
// mapping of the test binary itself.
u64 self_addr = (u64)&test_procmaps_find_self;
const ProcMapEntry *entry = ProcMapsFindByAddr(&maps, self_addr);
bool ok = entry != NULL && (entry->perms & PROC_MAP_PERM_EXEC) != 0;- In
ProcMaps.c:101:
u64 fn_addr = (u64)&pm2_marker_fn;
const ProcMapEntry *e = ProcMapsFindByAddr(&maps, fn_addr);
bool ok = e != NULL;- In
ProcMaps.c:130:
u64 stack_addr = (u64)&local;
const ProcMapEntry *e = ProcMapsFindByAddr(&maps, stack_addr);
bool ok = e != NULL;- In
ProcMaps.c:161:
if (ok) {
// Pick a non-degenerate region and query its exact start.
const ProcMapEntry *region = NULL;
for (u64 i = 0; i < VecLen(&maps.entries); ++i) {
const ProcMapEntry *cand = VecPtrAt(&maps.entries, i);- In
ProcMaps.c:163:
const ProcMapEntry *region = NULL;
for (u64 i = 0; i < VecLen(&maps.entries); ++i) {
const ProcMapEntry *cand = VecPtrAt(&maps.entries, i);
if (cand->end > cand->start) {
region = cand;- In
ProcMaps.c:172:
if (ok) {
u64 start = region->start;
const ProcMapEntry *hit = ProcMapsFindByAddr(&maps, start);
// The start address must resolve, and to a region whose
// start is exactly that address.
- In
ProcMaps.c:200:
if (ok) {
// The entry with the highest `end` -- `end` itself maps to nothing.
const ProcMapEntry *top = VecPtrAt(&maps.entries, 0);
for (u64 i = 1; i < VecLen(&maps.entries); ++i) {
const ProcMapEntry *cand = VecPtrAt(&maps.entries, i);- In
ProcMaps.c:202:
const ProcMapEntry *top = VecPtrAt(&maps.entries, 0);
for (u64 i = 1; i < VecLen(&maps.entries); ++i) {
const ProcMapEntry *cand = VecPtrAt(&maps.entries, i);
if (cand->end > top->end)
top = cand;- In
ProcMaps.c:211:
// end - 1 is the last byte inside the region: must resolve to it.
if (ok) {
const ProcMapEntry *last_in = ProcMapsFindByAddr(&maps, top->end - 1);
ok = last_in != NULL && last_in->end == top->end;
}- In
ProcMaps.c:216:
// end is one-past the top region and above all mappings: NULL.
if (ok) {
const ProcMapEntry *past = ProcMapsFindByAddr(&maps, top->end);
ok = past == NULL;
}- In
ProcMaps.c:242:
// Address 0 / a tiny address is never mapped in a normal process.
const ProcMapEntry *e = ProcMapsFindByAddr(&maps, (u64)0x1);
bool ok = e == NULL;- In
ProcMaps.c:272:
bool inside = false;
for (u64 j = 0; j < VecLen(&maps.entries); ++j) {
const ProcMapEntry *e = VecPtrAt(&maps.entries, j);
if (hole >= e->start && hole < e->end) {
inside = true;- In
ProcMaps.c:280:
if (!inside) {
found_gap = true;
const ProcMapEntry *at_gap = ProcMapsFindByAddr(&maps, hole);
ok = at_gap == NULL;
}- In
ProcMaps.c:288:
// definitely-unmapped high canonical-hole address.
if (!found_gap) {
const ProcMapEntry *at = ProcMapsFindByAddr(&maps, (u64)0x0000800000000000ULL);
ok = at == NULL;
}
Last updated on