| /* |
| * Utility function to get QEMU's own process map |
| * |
| * Copyright (c) 2020 Linaro Ltd |
| * |
| * SPDX-License-Identifier: GPL-2.0-or-later |
| */ |
| |
| #include "qemu/osdep.h" |
| #include "qemu/cutils.h" |
| #include "qemu/selfmap.h" |
| |
| IntervalTreeRoot *read_self_maps(void) |
| { |
| IntervalTreeRoot *root; |
| gchar *maps, **lines; |
| guint i, nlines; |
| |
| if (!g_file_get_contents("/proc/self/maps", &maps, NULL, NULL)) { |
| return NULL; |
| } |
| |
| root = g_new0(IntervalTreeRoot, 1); |
| lines = g_strsplit(maps, "\n", 0); |
| nlines = g_strv_length(lines); |
| |
| for (i = 0; i < nlines; i++) { |
| gchar **fields = g_strsplit(lines[i], " ", 6); |
| guint nfields = g_strv_length(fields); |
| |
| if (nfields > 4) { |
| uint64_t start, end, offset, inode; |
| unsigned dev_maj, dev_min; |
| int errors = 0; |
| const char *p; |
| |
| errors |= qemu_strtou64(fields[0], &p, 16, &start); |
| errors |= qemu_strtou64(p + 1, NULL, 16, &end); |
| errors |= qemu_strtou64(fields[2], NULL, 16, &offset); |
| errors |= qemu_strtoui(fields[3], &p, 16, &dev_maj); |
| errors |= qemu_strtoui(p + 1, NULL, 16, &dev_min); |
| errors |= qemu_strtou64(fields[4], NULL, 10, &inode); |
| |
| if (!errors) { |
| size_t path_len; |
| MapInfo *e; |
| |
| if (nfields == 6) { |
| p = fields[5]; |
| p += strspn(p, " "); |
| path_len = strlen(p) + 1; |
| } else { |
| p = NULL; |
| path_len = 0; |
| } |
| |
| e = g_malloc0(sizeof(*e) + path_len); |
| |
| e->itree.start = start; |
| e->itree.last = end - 1; |
| e->offset = offset; |
| e->dev = makedev(dev_maj, dev_min); |
| e->inode = inode; |
| |
| e->is_read = fields[1][0] == 'r'; |
| e->is_write = fields[1][1] == 'w'; |
| e->is_exec = fields[1][2] == 'x'; |
| e->is_priv = fields[1][3] == 'p'; |
| |
| if (path_len) { |
| e->path = memcpy(e + 1, p, path_len); |
| } |
| |
| interval_tree_insert(&e->itree, root); |
| } |
| } |
| g_strfreev(fields); |
| } |
| g_strfreev(lines); |
| g_free(maps); |
| |
| return root; |
| } |
| |
| /** |
| * free_self_maps: |
| * @root: an interval tree |
| * |
| * Free a tree of MapInfo structures. |
| * Since we allocated each MapInfo in one chunk, we need not consider the |
| * contents and can simply free each RBNode. |
| */ |
| |
| static void free_rbnode(RBNode *n) |
| { |
| if (n) { |
| free_rbnode(n->rb_left); |
| free_rbnode(n->rb_right); |
| g_free(n); |
| } |
| } |
| |
| void free_self_maps(IntervalTreeRoot *root) |
| { |
| if (root) { |
| free_rbnode(root->rb_root.rb_node); |
| g_free(root); |
| } |
| } |