master
c 156 lines 4.01 KB
Raw
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 "user/selfmap.h"
12 #ifdef __FreeBSD__
13 #include <sys/sysctl.h>
14 #include <sys/user.h>
15 #endif
16
17 IntervalTreeRoot *read_self_maps(void)
18 {
19 #ifdef __linux__
20 IntervalTreeRoot *root;
21 gchar *maps, **lines;
22 guint i, nlines;
23
24 if (!g_file_get_contents("/proc/self/maps", &maps, NULL, NULL)) {
25 return NULL;
26 }
27
28 root = g_new0(IntervalTreeRoot, 1);
29 lines = g_strsplit(maps, "\n", 0);
30 nlines = g_strv_length(lines);
31
32 for (i = 0; i < nlines; i++) {
33 gchar **fields = g_strsplit(lines[i], " ", 6);
34 guint nfields = g_strv_length(fields);
35
36 if (nfields > 4) {
37 uint64_t start, end, offset, inode;
38 unsigned dev_maj, dev_min;
39 int errors = 0;
40 const char *p;
41
42 errors |= qemu_strtou64(fields[0], &p, 16, &start);
43 errors |= qemu_strtou64(p + 1, NULL, 16, &end);
44 errors |= qemu_strtou64(fields[2], NULL, 16, &offset);
45 errors |= qemu_strtoui(fields[3], &p, 16, &dev_maj);
46 errors |= qemu_strtoui(p + 1, NULL, 16, &dev_min);
47 errors |= qemu_strtou64(fields[4], NULL, 10, &inode);
48
49 if (!errors) {
50 size_t path_len;
51 MapInfo *e;
52
53 if (nfields == 6) {
54 p = fields[5];
55 p += strspn(p, " ");
56 path_len = strlen(p) + 1;
57 } else {
58 p = NULL;
59 path_len = 0;
60 }
61
62 e = g_malloc0(sizeof(*e) + path_len);
63
64 e->itree.start = start;
65 e->itree.last = end - 1;
66 e->offset = offset;
67 e->dev = makedev(dev_maj, dev_min);
68 e->inode = inode;
69
70 e->is_read = fields[1][0] == 'r';
71 e->is_write = fields[1][1] == 'w';
72 e->is_exec = fields[1][2] == 'x';
73 e->is_priv = fields[1][3] == 'p';
74
75 if (path_len) {
76 e->path = memcpy(e + 1, p, path_len);
77 }
78
79 interval_tree_insert(&e->itree, root);
80 }
81 }
82 g_strfreev(fields);
83 }
84 g_strfreev(lines);
85 g_free(maps);
86
87 return root;
88 #elif defined(__FreeBSD__)
89 int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_VMMAP, getpid() };
90 size_t len = 0;
91 g_autofree void *buf = NULL;
92 IntervalTreeRoot *root;
93
94 /* Probe for buffer size. */
95 if (sysctl(mib, ARRAY_SIZE(mib), NULL, &len, NULL, 0) < 0) {
96 return NULL;
97 }
98
99 buf = g_malloc(len);
100 if (sysctl(mib, ARRAY_SIZE(mib), buf, &len, NULL, 0) < 0) {
101 return NULL;
102 }
103
104 root = g_new0(IntervalTreeRoot, 1);
105
106 for (size_t i = 0; i < len; ) {
107 struct kinfo_vmentry *k = buf + i;
108 MapInfo *e = g_new0(MapInfo, 1);
109
110 e->itree.start = k->kve_start;
111 e->itree.last = k->kve_end - 1;
112
113 /*
114 * TODO: The rest of the fields in MapInfo are used by linux-user
115 * for the implementation of open_self_maps(). These fields are
116 * quite specific to the textual format of /proc/self/maps.
117 *
118 * We may need something different to emulate KERN_PROC_VMMAP
119 * in bsd-user, but so far they're unused -- leave them zeroed.
120 */
121
122 interval_tree_insert(&e->itree, root);
123 i += k->kve_structsize;
124 }
125
126 return root;
127 #else
128 # error
129 #endif
130 }
131
132 /**
133 * free_self_maps:
134 * @root: an interval tree
135 *
136 * Free a tree of MapInfo structures.
137 * Since we allocated each MapInfo in one chunk, we need not consider the
138 * contents and can simply free each RBNode.
139 */
140
141 static void free_rbnode(RBNode *n)
142 {
143 if (n) {
144 free_rbnode(n->rb_left);
145 free_rbnode(n->rb_right);
146 g_free(n);
147 }
148 }
149
150 void free_self_maps(IntervalTreeRoot *root)
151 {
152 if (root) {
153 free_rbnode(root->rb_root.rb_node);
154 g_free(root);
155 }
156 }