]>
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; | |
33 | int errors = 0; | |
34 | const char *p; | |
01ef6b9e | 35 | |
3ce3dd8c RH |
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 | } | |
01ef6b9e | 54 | |
3ce3dd8c RH |
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; | |
01ef6b9e AB |
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 | ||
3ce3dd8c RH |
67 | memcpy(e->dev, fields[3], dev_len); |
68 | if (path_len) { | |
69 | e->path = memcpy(e->dev + dev_len, p, path_len); | |
01ef6b9e | 70 | } |
01ef6b9e | 71 | |
3ce3dd8c RH |
72 | interval_tree_insert(&e->itree, root); |
73 | } | |
01ef6b9e | 74 | } |
3ce3dd8c | 75 | g_strfreev(fields); |
01ef6b9e | 76 | } |
3ce3dd8c RH |
77 | g_strfreev(lines); |
78 | g_free(maps); | |
01ef6b9e | 79 | |
3ce3dd8c | 80 | return root; |
01ef6b9e AB |
81 | } |
82 | ||
83 | /** | |
84 | * free_self_maps: | |
3ce3dd8c | 85 | * @root: an interval tree |
01ef6b9e | 86 | * |
3ce3dd8c RH |
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. | |
01ef6b9e | 90 | */ |
3ce3dd8c RH |
91 | |
92 | static void free_rbnode(RBNode *n) | |
01ef6b9e | 93 | { |
3ce3dd8c RH |
94 | if (n) { |
95 | free_rbnode(n->rb_left); | |
96 | free_rbnode(n->rb_right); | |
97 | g_free(n); | |
98 | } | |
01ef6b9e AB |
99 | } |
100 | ||
3ce3dd8c | 101 | void free_self_maps(IntervalTreeRoot *root) |
01ef6b9e | 102 | { |
3ce3dd8c RH |
103 | if (root) { |
104 | free_rbnode(root->rb_root.rb_node); | |
105 | g_free(root); | |
106 | } | |
01ef6b9e | 107 | } |