summaryrefslogtreecommitdiff
path: root/src/procfs.c
diff options
context:
space:
mode:
authorraven <citrons@mondecitronne.com>2026-04-08 22:51:39 -0500
committerraven <citrons@mondecitronne.com>2026-04-08 22:51:39 -0500
commit18a86e1038b20cb6f8922beead08dcc24ba2a4d3 (patch)
tree85cb74210d67d42763a4709d18af93aa60a8f400 /src/procfs.c
parent4a3429a96b5b5ea7468540349aeb4535d5738053 (diff)
rewrite and port to SDL3
Diffstat (limited to 'src/procfs.c')
-rw-r--r--src/procfs.c130
1 files changed, 130 insertions, 0 deletions
diff --git a/src/procfs.c b/src/procfs.c
new file mode 100644
index 0000000..d377e02
--- /dev/null
+++ b/src/procfs.c
@@ -0,0 +1,130 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include "procfs.h"
+
+int procfs_open(pid_t pid) {
+ char path[2048];
+ sprintf(path, "/proc/%d/mem", pid);
+ return open(path, O_RDWR);
+}
+
+ssize_t procfs_maps(pid_t pid, struct procfs_map **maps) {
+ char path[2048];
+ sprintf(path, "/proc/%d/maps", pid);
+ FILE *f = fopen(path, "r");
+ if (!f) return -1;
+
+ int n = 0;
+ int capacity = 2;
+ if (*maps) {
+ free(*maps);
+ }
+ *maps = calloc(capacity, sizeof(**maps));
+ if (!*maps) return -1;
+ while (1) {
+ void *base, *max;
+ char prot_str[4];
+ char name[4096] = {0};
+ void *unused;
+ int matches = fscanf(
+ f, "%p-%p %4c %p %p:%p %d",
+ &base, &max, &prot_str, &unused, &unused, &unused, &unused
+ );
+ if (matches == EOF) goto eof;
+ if (matches < 7) goto err;
+
+ int c = ' ';
+ while (c == ' ') {
+ c = fgetc(f);
+ }
+ if (c == EOF) goto err;
+ ungetc(c, f);
+ if (fgets(name, 4096, f) == NULL) goto err;
+ name[strlen(name) - 1] = '\0'; // remove newline
+
+ int prot = 0;
+ for (int i = 0; i < 4; i++) {
+ switch (prot_str[i]) {
+ case 'r':
+ prot |= PROT_READ;
+ break;
+ case 'w':
+ prot |= PROT_WRITE;
+ break;
+ case 'x':
+ prot |= PROT_EXEC;
+ break;
+ default:
+ break;
+ }
+ }
+ if (prot == 0) prot = PROT_NONE;
+
+ if (n > 0) {
+ procfs_map *prev = *maps + (n - 1);
+ if ((strlen(name) == 0 || strncmp(prev->name, name, 1024) == 0) &&
+ prev->max == (uintptr_t)base) {
+ prev->max = (uintptr_t)max;
+ continue;
+ }
+ }
+
+ n++;
+ if (n > capacity) {
+ capacity <<= 1;
+ struct procfs_map *r = reallocarray(*maps, capacity, sizeof(*r));
+ if (!r) goto err;
+ *maps = r;
+ }
+ procfs_map *new = *maps + (n - 1);
+ new->base = (uintptr_t)base;
+ new->max = (uintptr_t)max;
+ new->prot = prot;
+ strncpy(new->name, name, sizeof(new->name) - 1);
+ }
+eof:
+ if (ferror(f)) goto err;
+ fclose(f);
+ if (n == 0) {
+ free(*maps);
+ *maps = NULL;
+ }
+ return n;
+err:
+ fclose(f);
+ free(*maps);
+ *maps = NULL;
+ return -1;
+}
+
+// mmap does not work on /proc/pid/mem, so we issue reads/writes instead
+int read_mem(int fd, uintptr_t addr, uint8_t *data, size_t size) {
+ if (lseek(fd, addr, SEEK_SET) == -1) return -1;
+ size_t n = 0;
+ while (n < size) {
+ ssize_t result = read(fd, data + n, size - n);
+ if (result <= 0) return -1;
+ n += result;
+ }
+ return 0;
+}
+
+int write_mem(int fd, uintptr_t addr, uint8_t *data, size_t size) {
+ if (lseek(fd, addr, SEEK_SET) == -1) return -1;
+ size_t n = 0;
+ while (n < size) {
+ ssize_t result = write(fd, data + n, size - n);
+ if (result <= 0) return -1;
+ n += result;
+ }
+ return 0;
+}