xref: /openbmc/qemu/util/selfmap.c (revision 4b3520fd)
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 IntervalTreeRoot *read_self_maps(void)
14 {
15     IntervalTreeRoot *root;
16     gchar *maps, **lines;
17     guint i, nlines;
18 
19     if (!g_file_get_contents("/proc/self/maps", &maps, NULL, NULL)) {
20         return NULL;
21     }
22 
23     root = g_new0(IntervalTreeRoot, 1);
24     lines = g_strsplit(maps, "\n", 0);
25     nlines = g_strv_length(lines);
26 
27     for (i = 0; i < nlines; i++) {
28         gchar **fields = g_strsplit(lines[i], " ", 6);
29         guint nfields = g_strv_length(fields);
30 
31         if (nfields > 4) {
32             uint64_t start, end, offset, inode;
33             int errors = 0;
34             const char *p;
35 
36             errors |= qemu_strtou64(fields[0], &p, 16, &start);
37             errors |= qemu_strtou64(p + 1, NULL, 16, &end);
38             errors |= qemu_strtou64(fields[2], NULL, 16, &offset);
39             errors |= qemu_strtou64(fields[4], NULL, 10, &inode);
40 
41             if (!errors) {
42                 size_t dev_len, path_len;
43                 MapInfo *e;
44 
45                 dev_len = strlen(fields[3]) + 1;
46                 if (nfields == 6) {
47                     p = fields[5];
48                     p += strspn(p, " ");
49                     path_len = strlen(p) + 1;
50                 } else {
51                     p = NULL;
52                     path_len = 0;
53                 }
54 
55                 e = g_malloc0(sizeof(*e) + dev_len + path_len);
56 
57                 e->itree.start = start;
58                 e->itree.last = end - 1;
59                 e->offset = offset;
60                 e->inode = inode;
61 
62                 e->is_read  = fields[1][0] == 'r';
63                 e->is_write = fields[1][1] == 'w';
64                 e->is_exec  = fields[1][2] == 'x';
65                 e->is_priv  = fields[1][3] == 'p';
66 
67                 memcpy(e->dev, fields[3], dev_len);
68                 if (path_len) {
69                     e->path = memcpy(e->dev + dev_len, p, path_len);
70                 }
71 
72                 interval_tree_insert(&e->itree, root);
73             }
74         }
75         g_strfreev(fields);
76     }
77     g_strfreev(lines);
78     g_free(maps);
79 
80     return root;
81 }
82 
83 /**
84  * free_self_maps:
85  * @root: an interval tree
86  *
87  * Free a tree of MapInfo structures.
88  * Since we allocated each MapInfo in one chunk, we need not consider the
89  * contents and can simply free each RBNode.
90  */
91 
92 static void free_rbnode(RBNode *n)
93 {
94     if (n) {
95         free_rbnode(n->rb_left);
96         free_rbnode(n->rb_right);
97         g_free(n);
98     }
99 }
100 
101 void free_self_maps(IntervalTreeRoot *root)
102 {
103     if (root) {
104         free_rbnode(root->rb_root.rb_node);
105         g_free(root);
106     }
107 }
108