aboutsummaryrefslogtreecommitdiffstats
path: root/memory.c
diff options
context:
space:
mode:
authorMattias Andrée <maandree@kth.se>2020-05-30 17:34:29 +0200
committerMattias Andrée <maandree@kth.se>2020-05-30 17:34:29 +0200
commit712f56fe3369c59d32b9000830b4ed7b25ed24b5 (patch)
tree27ddf931fd2d980d0c4dcdfb025f26f5380fb5d6 /memory.c
parentPrint errno names and strings (diff)
downloadsctrace-712f56fe3369c59d32b9000830b4ed7b25ed24b5.tar.gz
sctrace-712f56fe3369c59d32b9000830b4ed7b25ed24b5.tar.bz2
sctrace-712f56fe3369c59d32b9000830b4ed7b25ed24b5.tar.xz
Add support for tracing fork children
Signed-off-by: Mattias Andrée <maandree@kth.se>
Diffstat (limited to 'memory.c')
-rw-r--r--memory.c189
1 files changed, 189 insertions, 0 deletions
diff --git a/memory.c b/memory.c
new file mode 100644
index 0000000..1af854f
--- /dev/null
+++ b/memory.c
@@ -0,0 +1,189 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+
+
+char *
+get_string(pid_t pid, unsigned long int addr, size_t *lenp, const char **errorp)
+{
+ struct iovec inv, outv;
+ size_t off = 0, size = 0, page_off, read_size;
+ char *out = NULL, *in = (char *)addr, *p;
+ page_off = (size_t)addr % sizeof(PAGE_SIZE);
+ read_size = PAGE_SIZE - page_off;
+ *errorp = NULL;
+ for (;; read_size = PAGE_SIZE) {
+ out = realloc(out, size + PAGE_SIZE);
+ if (!out)
+ eprintf("realloc:");
+ inv.iov_base = &in[off];
+ inv.iov_len = read_size;
+ outv.iov_base = &out[off];
+ outv.iov_len = read_size;
+ if (process_vm_readv(pid, &outv, 1, &inv, 1, 0) != (ssize_t)read_size) {
+ *errorp = errno == EFAULT ? "<invalid address>" : "<an error occured during reading of string>";
+ *lenp = 0;
+ return 0;
+ }
+ p = memchr(&out[off], 0, read_size);
+ if (p) {
+ *lenp = (size_t)(p - out);
+ return out;
+ }
+ off += read_size;
+ }
+}
+
+
+int
+get_struct(pid_t pid, unsigned long int addr, void *out, size_t size, const char **errorp)
+{
+ struct iovec inv, outv;
+ *errorp = NULL;
+ inv.iov_base = (void *)addr;
+ inv.iov_len = size;
+ outv.iov_base = out;
+ outv.iov_len = size;
+ if (process_vm_readv(pid, &outv, 1, &inv, 1, 0) == (ssize_t)size)
+ return 0;
+ *errorp = errno == EFAULT ? "<invalid address>" : "<an error occured during reading of string>";
+ return -1;
+}
+
+
+char *
+get_memory(pid_t pid, unsigned long int addr, size_t n, const char **errorp)
+{
+ char *out = malloc(n + (size_t)!n);
+ if (!out)
+ eprintf("malloc:");
+ if (get_struct(pid, addr, out, n, errorp)) {
+ free(out);
+ return NULL;
+ }
+ return out;
+}
+
+
+
+static void
+add_char(char **strp, size_t *sizep, size_t *lenp, char c)
+{
+ if (*lenp == *sizep) {
+ *strp = realloc(*strp, *sizep += 128);
+ if (!*strp)
+ eprintf("realloc:");
+ }
+ (*strp)[(*lenp)++] = c;
+}
+
+
+static size_t
+utf8len(char *str)
+{
+ size_t ext, i, len;
+ uint32_t code;
+ uint8_t *s = (uint8_t *)str;
+
+ struct {
+ uint8_t lower;
+ uint8_t upper;
+ uint8_t mask;
+ uint32_t lowest;
+ } lookup[] = {
+ { 0x00, 0x7F, 0x7F, UINT32_C(0x000000) },
+ { 0xC0, 0xDF, 0x1F, UINT32_C(0x000080) },
+ { 0xE0, 0xEF, 0x0F, UINT32_C(0x000800) },
+ { 0xF0, 0xF7, 0x07, UINT32_C(0x010000) }
+ };
+
+ for (ext = 0; ext < sizeof(lookup) / sizeof(*lookup); ext++)
+ if (lookup[ext].lower <= s[0] && s[0] <= lookup[ext].upper)
+ goto found;
+ return 0;
+
+found:
+ code = s[0] & lookup[ext].mask;
+ len = ext + 1;
+ for (i = 1; i < len; i++) {
+ if ((s[i] & 0xC0) != 0x80)
+ return 0;
+ code = (code << 6) | (s[i] ^ 0x80);
+ }
+
+ if (code < lookup[ext].lowest || (0xD800 <= code && code <= 0xDFFF) || code > UINT32_C(0x10FFFF))
+ return 0;
+ return len;
+}
+
+
+char *
+escape_memory(char *str, size_t m)
+{
+ char *ret = NULL, *s, *end;
+ size_t size = 0;
+ size_t len = 0;
+ size_t n = 0;
+ int need_new_string = 0;
+ if (!str) {
+ str = strdup("NULL");
+ if (!str)
+ eprintf("strdup:");
+ return str;
+ }
+ add_char(&ret, &size, &len, '"');
+ for (s = str, end = &str[m]; s != end; s++) {
+ if (n) {
+ add_char(&ret, &size, &len, *s);
+ n -= 1;
+ } else if (*s == '\r') {
+ add_char(&ret, &size, &len, '\\');
+ add_char(&ret, &size, &len, 'r');
+ } else if (*s == '\t') {
+ add_char(&ret, &size, &len, '\\');
+ add_char(&ret, &size, &len, 't');
+ } else if (*s == '\a') {
+ add_char(&ret, &size, &len, '\\');
+ add_char(&ret, &size, &len, 'a');
+ } else if (*s == '\f') {
+ add_char(&ret, &size, &len, '\\');
+ add_char(&ret, &size, &len, 'f');
+ } else if (*s == '\v') {
+ add_char(&ret, &size, &len, '\\');
+ add_char(&ret, &size, &len, 'v');
+ } else if (*s == '\b') {
+ add_char(&ret, &size, &len, '\\');
+ add_char(&ret, &size, &len, 'b');
+ } else if (*s == '\n') {
+ add_char(&ret, &size, &len, '\\');
+ add_char(&ret, &size, &len, 'n');
+ } else if (*s == '\"') {
+ add_char(&ret, &size, &len, '\\');
+ add_char(&ret, &size, &len, '"');
+ } else if (*s < ' ' || *s >= 127) {
+ n = utf8len(s);
+ if (n > 1) {
+ add_char(&ret, &size, &len, *s);
+ n -= 1;
+ } else {
+ n = 0;
+ add_char(&ret, &size, &len, '\\');
+ add_char(&ret, &size, &len, 'x');
+ add_char(&ret, &size, &len, "0123456789abcdef"[(int)*(unsigned char *)s >> 4]);
+ add_char(&ret, &size, &len, "0123456789abcdef"[(int)*(unsigned char *)s & 15]);
+ need_new_string = 1;
+ continue;
+ }
+ } else {
+ if (need_new_string && isxdigit(*s)) {
+ add_char(&ret, &size, &len, '"');
+ add_char(&ret, &size, &len, '"');
+ }
+ add_char(&ret, &size, &len, *s);
+ }
+ need_new_string = 0;
+ }
+ add_char(&ret, &size, &len, '"');
+ add_char(&ret, &size, &len, '\0');
+ free(str);
+ return ret;
+}