summaryrefslogtreecommitdiffstats
path: root/src/modules.cpp
blob: 70e2dffc4a8496963c430f72ec5b71def01f86df (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
// 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);
}