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