Find steamclient.so's executable mapping (r-xp) range by scanning /proc/self/maps.
| 394 | |
| 395 | // Find steamclient.so's executable mapping (r-xp) range by scanning /proc/self/maps. |
| 396 | static bool SteamclientExecRange(uintptr_t& lo, uintptr_t& hi) |
| 397 | { |
| 398 | lo = hi = 0; |
| 399 | int fd = open("/proc/self/maps", O_RDONLY | O_CLOEXEC); |
| 400 | if (fd < 0) return false; |
| 401 | char buf[8192], line[512]; |
| 402 | size_t lineLen = 0; |
| 403 | ssize_t n; |
| 404 | bool found = false; |
| 405 | while ((n = read(fd, buf, sizeof(buf))) > 0) { |
| 406 | for (ssize_t i = 0; i < n; ++i) { |
| 407 | char c = buf[i]; |
| 408 | if (c != '\n') { if (lineLen < sizeof(line) - 1) line[lineLen++] = c; continue; } |
| 409 | line[lineLen] = '\0'; lineLen = 0; |
| 410 | // need executable + steamclient.so |
| 411 | bool isExec = false; |
| 412 | for (const char* q = line; *q && *q != '\n'; ++q) { |
| 413 | if (q[0] == ' ' && q[1] == 'r') { isExec = (q[3] == 'x'); break; } |
| 414 | } |
| 415 | bool isSc = false; |
| 416 | for (const char* q = line; *q; ++q) |
| 417 | if (q[0]=='s'&&q[1]=='t'&&q[2]=='e'&&q[3]=='a'&&q[4]=='m'&&q[5]=='c') { isSc = true; break; } |
| 418 | if (isExec && isSc) { |
| 419 | uintptr_t s = 0, e = 0; const char* p = line; |
| 420 | while (*p && *p != '-') { s = s*16 + (*p<='9'?*p-'0':(*p|0x20)-'a'+10); ++p; } |
| 421 | if (*p=='-') ++p; |
| 422 | while (*p && *p != ' ') { e = e*16 + (*p<='9'?*p-'0':(*p|0x20)-'a'+10); ++p; } |
| 423 | if (!found) { lo = s; hi = e; found = true; } |
| 424 | else { if (s < lo) lo = s; if (e > hi) hi = e; } |
| 425 | } |
| 426 | } |
| 427 | } |
| 428 | close(fd); |
| 429 | return found; |
| 430 | } |
| 431 | |
| 432 | // Recover the call chain on stripped, fomit-frame-pointer i386 code: EBP-chaining is |
| 433 | // unreliable, so also scan the stack for words pointing into steamclient.so's .text. |