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