strscan: make it work properly
[tools.git] / tools / strscan.c
index 613319a..dff214d 100644 (file)
@@ -7,15 +7,23 @@
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <sys/wait.h>
-#include <sys/ptrace.h>
 #include <fcntl.h>
 #include <jh.h>
 #include <stdbool.h>
 #include <string.h>
+#include <sys/uio.h>
+
+ssize_t getmem(pid_t pid, void *dst, void *src, size_t len) {
+  assert(len > 0);
+  struct iovec local = {.iov_base = dst, .iov_len = len};
+  struct iovec remote = {.iov_base = src, .iov_len = len};
+  return process_vm_readv(pid, &local, 1, &remote, 1, 0);
+}
 
 struct range {
   void *a, *b;
   char *line;
+  char readable;
 };
 
 struct range *mappings;
@@ -34,24 +42,7 @@ int main(int argc, char **argv) {
   TPRINTF(maps_path, "/proc/%s/maps", argv[1])
   char *maps = CHK_PTR(slurp_file(maps_path, NULL, JH_SLURP_NO_STAT), "unable to read /proc/$pid/maps", 1);
 
-/*
-  char argbuf[8192];
-  size_t arglen = strlen(argv[2])*4;
-  for (int i=0; i<strlen(argv[2]); i++) {
-    argbuf[i*4] = argv[2][i];
-    argbuf[i*4+1] = 0;
-    argbuf[i*4+2] = 0;
-    argbuf[i*4+3] = 0;
-  }*/
-
-  if (ptrace(PTRACE_ATTACH, atoi(argv[1]), NULL, NULL)) {
-    fputs("warning: unable to ptrace\n", stderr);
-  } else {
-    wait(NULL);
-  }
-
-  TPRINTF(mem_path, "/proc/%s/mem", argv[1])
-  int memfd = fail_on_neg(open(mem_path, O_RDONLY), "unable to open /proc/$pid/mem", 1);
+  pid_t target = atoi(argv[1]);
 
   size_t n_mappings = count_char_occurences(maps, '\n');
   mappings = CHK_PTR(calloc(n_mappings+1, sizeof(struct range)), "memory allocation failed", 1);
@@ -60,26 +51,31 @@ int main(int argc, char **argv) {
   for (char *line = strtok(maps, "\n"); line != NULL; line = strtok(NULL, "\n")) {
     struct range *mapping = &mappings[mappings_used++];
     mapping->line = CHK_PTR(strdup(line), "memory allocation failed", 1);
-    if (sscanf(line, "%p-%p", &mapping->a, &mapping->b) != 2) xperror("sscanf failed", 0);
+    if (sscanf(line, "%p-%p %c", &mapping->a, &mapping->b, &mapping->readable) != 3) xperror("sscanf failed", 0);
+    assert(mapping->readable == 'r' || mapping->readable == '-');
   }
 
   FOR_EACH_MAPPING {
+    //fprintf(stderr, "%s\n", mapping->line);
+    if (mapping->readable == '-') continue; /* guard page */
+    if (strchr(mapping->line, '/') == NULL && strstr(mapping->line, "[vvar]") != NULL) continue; /* vvar mapping is weird */
     size_t len = mapping->b - mapping->a;
+    //printf("a=0x%llx b=0x%llx len=0x%llx\n", (unsigned long long)mapping->a, (unsigned long long)mapping->b, (unsigned long long)len);
     char *copy = CHK_PTR(malloc(len), "malloc failed", 1);
     ssize_t read_res;
-    size_t read_done = 0;
-read_more:;
-    if ((read_res=pread(memfd, copy+read_done, len-read_done, (off_t)mapping->a-read_done)) != (ssize_t)len) {
-      if (read_res <= 0) {
+    if ((read_res=getmem(target, copy, mapping->a, len)) != len) {
+      if (read_res == 0) {
         fputs("warning: some read failed\n", stderr);
         continue;
       }
-      read_done += read_res;
-      goto read_more;
+      if (read_res == -1) {
+        perror("warning: some read failed");
+        continue;
+      }
     }
     size_t pos = 0;
     while (1) {
-      char *ptr = memmem(copy + pos, len, argv[2], strlen(argv[2]));
+      char *ptr = memmem(copy + pos, len - pos, argv[2], strlen(argv[2]));
       if (ptr == NULL) break;
       pos = ptr - copy;
       printf("at %p in %s\n", mapping->a + pos, mapping->line);