|  | /* | 
|  | * 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); | 
|  | } | 
|  | } |