// modules.cpp — /proc/self/maps parsing and module discovery #include "hl2h.h" static bool basename_is(const char *path, const char *base) { size_t pl = strlen(path), bl = strlen(base); if (pl < bl || strcmp(path + pl - bl, base) != 0) return false; return pl == bl || path[pl - bl - 1] == '/'; } void find_modules() { g_client = Module(); g_engine = Module(); g_server = Module(); FILE *f = fopen("/proc/self/maps", "r"); if (!f) return; char line[1024]; while (fgets(line, sizeof(line), f)) { unsigned long lo, hi; char perms[8]; int consumed = 0; if (sscanf(line, "%lx-%lx %7s %*x %*x:%*x %*u%n", &lo, &hi, perms, &consumed) < 3) continue; if (perms[0] == '-' && perms[1] == '-' && perms[2] == '-') continue; // PROT_NONE const char *path = line + consumed; while (*path == ' ' || *path == '\t') path++; size_t pl = strlen(path); while (pl && (path[pl - 1] == '\n' || path[pl - 1] == '\r')) pl--; Module *m = nullptr; char clean[1024]; if (pl && pl < sizeof(clean)) { memcpy(clean, path, pl); clean[pl] = 0; if (basename_is(clean, "client.so")) m = &g_client; else if (basename_is(clean, "engine.so")) m = &g_engine; else if (basename_is(clean, "server.so")) m = &g_server; } else { // anon: absorb only as .bss tail after a file-backed range if (g_client.valid() && g_client.ranges.back().file && lo == g_client.ranges.back().hi && hi - lo <= 0x1000000) m = &g_client; else if (g_engine.valid() && g_engine.ranges.back().file && lo == g_engine.ranges.back().hi && hi - lo <= 0x1000000) m = &g_engine; } if (!m) continue; if (m->ranges.empty()) { if (!pl) continue; m->path = clean; } bool file = pl != 0; if (!m->ranges.empty() && lo == m->ranges.back().hi) { m->ranges.back().hi = hi; m->ranges.back().file = m->ranges.back().file && file; } else { m->ranges.push_back({lo, hi, file}); } } fclose(f); }