qemu with hax to log dma reads & writes jcs.org/2018/11/12/vfio

linux-user: factor out reading of /proc/self/maps

Unfortunately reading /proc/self/maps is still considered the gold
standard for a process finding out about it's own memory layout. As we
will want this data in other contexts soon factor out the code to read
and parse the data. Rather than just blindly copying the existing
sscanf based code we use a more modern glib version of the parsing
code to make a more general purpose map structure.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
Message-Id: <20200403191150.863-9-alex.bennee@linaro.org>

+151 -30
+44
include/qemu/selfmap.h
··· 1 + /* 2 + * Utility functions to read our own memory map 3 + * 4 + * Copyright (c) 2020 Linaro Ltd 5 + * 6 + * SPDX-License-Identifier: GPL-2.0-or-later 7 + */ 8 + 9 + #ifndef _SELFMAP_H_ 10 + #define _SELFMAP_H_ 11 + 12 + typedef struct { 13 + unsigned long start; 14 + unsigned long end; 15 + 16 + /* flags */ 17 + bool is_read; 18 + bool is_write; 19 + bool is_exec; 20 + bool is_priv; 21 + 22 + unsigned long offset; 23 + gchar *dev; 24 + uint64_t inode; 25 + gchar *path; 26 + } MapInfo; 27 + 28 + 29 + /** 30 + * read_self_maps: 31 + * 32 + * Read /proc/self/maps and return a list of MapInfo structures. 33 + */ 34 + GSList *read_self_maps(void); 35 + 36 + /** 37 + * free_self_maps: 38 + * @info: a GSlist 39 + * 40 + * Free a list of MapInfo structures. 41 + */ 42 + void free_self_maps(GSList *info); 43 + 44 + #endif /* _SELFMAP_H_ */
+28 -30
linux-user/syscall.c
··· 117 117 118 118 #include "qemu.h" 119 119 #include "qemu/guest-random.h" 120 + #include "qemu/selfmap.h" 120 121 #include "user/syscall-trace.h" 121 122 #include "qapi/error.h" 122 123 #include "fd-trans.h" ··· 7232 7233 { 7233 7234 CPUState *cpu = env_cpu((CPUArchState *)cpu_env); 7234 7235 TaskState *ts = cpu->opaque; 7235 - FILE *fp; 7236 - char *line = NULL; 7237 - size_t len = 0; 7238 - ssize_t read; 7236 + GSList *map_info = read_self_maps(); 7237 + GSList *s; 7238 + 7239 + for (s = map_info; s; s = g_slist_next(s)) { 7240 + MapInfo *e = (MapInfo *) s->data; 7239 7241 7240 - fp = fopen("/proc/self/maps", "r"); 7241 - if (fp == NULL) { 7242 - return -1; 7243 - } 7242 + if (h2g_valid(e->start)) { 7243 + unsigned long min = e->start; 7244 + unsigned long max = e->end; 7245 + int flags = page_get_flags(h2g(min)); 7246 + const char *path; 7244 7247 7245 - while ((read = getline(&line, &len, fp)) != -1) { 7246 - int fields, dev_maj, dev_min, inode; 7247 - uint64_t min, max, offset; 7248 - char flag_r, flag_w, flag_x, flag_p; 7249 - char path[512] = ""; 7250 - fields = sscanf(line, "%"PRIx64"-%"PRIx64" %c%c%c%c %"PRIx64" %x:%x %d" 7251 - " %512s", &min, &max, &flag_r, &flag_w, &flag_x, 7252 - &flag_p, &offset, &dev_maj, &dev_min, &inode, path); 7248 + max = h2g_valid(max - 1) ? 7249 + max : (uintptr_t) g2h(GUEST_ADDR_MAX) + 1; 7253 7250 7254 - if ((fields < 10) || (fields > 11)) { 7255 - continue; 7256 - } 7257 - if (h2g_valid(min)) { 7258 - int flags = page_get_flags(h2g(min)); 7259 - max = h2g_valid(max - 1) ? max : (uintptr_t)g2h(GUEST_ADDR_MAX) + 1; 7260 7251 if (page_check_range(h2g(min), max - min, flags) == -1) { 7261 7252 continue; 7262 7253 } 7254 + 7263 7255 if (h2g(min) == ts->info->stack_limit) { 7264 - pstrcpy(path, sizeof(path), " [stack]"); 7256 + path = " [stack]"; 7257 + } else { 7258 + path = e->path; 7265 7259 } 7260 + 7266 7261 dprintf(fd, TARGET_ABI_FMT_ptr "-" TARGET_ABI_FMT_ptr 7267 - " %c%c%c%c %08" PRIx64 " %02x:%02x %d %s%s\n", 7268 - h2g(min), h2g(max - 1) + 1, flag_r, flag_w, 7269 - flag_x, flag_p, offset, dev_maj, dev_min, inode, 7270 - path[0] ? " " : "", path); 7262 + " %c%c%c%c %08" PRIx64 " %s %"PRId64" %s%s\n", 7263 + h2g(min), h2g(max - 1) + 1, 7264 + e->is_read ? 'r' : '-', 7265 + e->is_write ? 'w' : '-', 7266 + e->is_exec ? 'x' : '-', 7267 + e->is_priv ? 'p' : '-', 7268 + (uint64_t) e->offset, e->dev, e->inode, 7269 + path ? " " : "", path ? path : ""); 7271 7270 } 7272 7271 } 7272 + 7273 + free_self_maps(map_info); 7273 7274 7274 7275 #ifdef TARGET_VSYSCALL_PAGE 7275 7276 /* ··· 7280 7281 " --xp 00000000 00:00 0 [vsyscall]\n", 7281 7282 TARGET_VSYSCALL_PAGE, TARGET_VSYSCALL_PAGE + TARGET_PAGE_SIZE); 7282 7283 #endif 7283 - 7284 - free(line); 7285 - fclose(fp); 7286 7284 7287 7285 return 0; 7288 7286 }
+1
util/Makefile.objs
··· 63 63 util-obj-$(CONFIG_GIO) += dbus.o 64 64 dbus.o-cflags = $(GIO_CFLAGS) 65 65 dbus.o-libs = $(GIO_LIBS) 66 + util-obj-$(CONFIG_USER_ONLY) += selfmap.o
+78
util/selfmap.c
··· 1 + /* 2 + * Utility function to get QEMU's own process map 3 + * 4 + * Copyright (c) 2020 Linaro Ltd 5 + * 6 + * SPDX-License-Identifier: GPL-2.0-or-later 7 + */ 8 + 9 + #include "qemu/osdep.h" 10 + #include "qemu/cutils.h" 11 + #include "qemu/selfmap.h" 12 + 13 + GSList *read_self_maps(void) 14 + { 15 + gchar *maps; 16 + GSList *map_info = NULL; 17 + 18 + if (g_file_get_contents("/proc/self/maps", &maps, NULL, NULL)) { 19 + gchar **lines = g_strsplit(maps, "\n", 0); 20 + int i, entries = g_strv_length(lines); 21 + 22 + for (i = 0; i < entries; i++) { 23 + gchar **fields = g_strsplit(lines[i], " ", 6); 24 + if (g_strv_length(fields) > 4) { 25 + MapInfo *e = g_new0(MapInfo, 1); 26 + int errors; 27 + const char *end; 28 + 29 + errors = qemu_strtoul(fields[0], &end, 16, &e->start); 30 + errors += qemu_strtoul(end + 1, NULL, 16, &e->end); 31 + 32 + e->is_read = fields[1][0] == 'r'; 33 + e->is_write = fields[1][1] == 'w'; 34 + e->is_exec = fields[1][2] == 'x'; 35 + e->is_priv = fields[1][3] == 'p'; 36 + 37 + errors += qemu_strtoul(fields[2], NULL, 16, &e->offset); 38 + e->dev = g_strdup(fields[3]); 39 + errors += qemu_strtou64(fields[4], NULL, 10, &e->inode); 40 + 41 + /* 42 + * The last field may have leading spaces which we 43 + * need to strip. 44 + */ 45 + if (g_strv_length(fields) == 6) { 46 + e->path = g_strdup(g_strchug(fields[5])); 47 + } 48 + map_info = g_slist_prepend(map_info, e); 49 + } 50 + 51 + g_strfreev(fields); 52 + } 53 + g_strfreev(lines); 54 + g_free(maps); 55 + } 56 + 57 + /* ensure the map data is in the same order we collected it */ 58 + return g_slist_reverse(map_info); 59 + } 60 + 61 + /** 62 + * free_self_maps: 63 + * @info: a GSlist 64 + * 65 + * Free a list of MapInfo structures. 66 + */ 67 + static void free_info(gpointer data) 68 + { 69 + MapInfo *e = (MapInfo *) data; 70 + g_free(e->dev); 71 + g_free(e->path); 72 + g_free(e); 73 + } 74 + 75 + void free_self_maps(GSList *info) 76 + { 77 + g_slist_free_full(info, &free_info); 78 + }