xref: /openbmc/qemu/util/selfmap.c (revision 79be812b)
101ef6b9eSAlex Bennée /*
201ef6b9eSAlex Bennée  * Utility function to get QEMU's own process map
301ef6b9eSAlex Bennée  *
401ef6b9eSAlex Bennée  * Copyright (c) 2020 Linaro Ltd
501ef6b9eSAlex Bennée  *
601ef6b9eSAlex Bennée  * SPDX-License-Identifier: GPL-2.0-or-later
701ef6b9eSAlex Bennée  */
801ef6b9eSAlex Bennée 
901ef6b9eSAlex Bennée #include "qemu/osdep.h"
1001ef6b9eSAlex Bennée #include "qemu/cutils.h"
1101ef6b9eSAlex Bennée #include "qemu/selfmap.h"
1201ef6b9eSAlex Bennée 
read_self_maps(void)133ce3dd8cSRichard Henderson IntervalTreeRoot *read_self_maps(void)
1401ef6b9eSAlex Bennée {
153ce3dd8cSRichard Henderson     IntervalTreeRoot *root;
163ce3dd8cSRichard Henderson     gchar *maps, **lines;
173ce3dd8cSRichard Henderson     guint i, nlines;
1801ef6b9eSAlex Bennée 
193ce3dd8cSRichard Henderson     if (!g_file_get_contents("/proc/self/maps", &maps, NULL, NULL)) {
203ce3dd8cSRichard Henderson         return NULL;
213ce3dd8cSRichard Henderson     }
2201ef6b9eSAlex Bennée 
233ce3dd8cSRichard Henderson     root = g_new0(IntervalTreeRoot, 1);
243ce3dd8cSRichard Henderson     lines = g_strsplit(maps, "\n", 0);
253ce3dd8cSRichard Henderson     nlines = g_strv_length(lines);
263ce3dd8cSRichard Henderson 
273ce3dd8cSRichard Henderson     for (i = 0; i < nlines; i++) {
2801ef6b9eSAlex Bennée         gchar **fields = g_strsplit(lines[i], " ", 6);
293ce3dd8cSRichard Henderson         guint nfields = g_strv_length(fields);
3001ef6b9eSAlex Bennée 
313ce3dd8cSRichard Henderson         if (nfields > 4) {
323ce3dd8cSRichard Henderson             uint64_t start, end, offset, inode;
33*79be812bSRichard Henderson             unsigned dev_maj, dev_min;
343ce3dd8cSRichard Henderson             int errors = 0;
353ce3dd8cSRichard Henderson             const char *p;
363ce3dd8cSRichard Henderson 
373ce3dd8cSRichard Henderson             errors |= qemu_strtou64(fields[0], &p, 16, &start);
383ce3dd8cSRichard Henderson             errors |= qemu_strtou64(p + 1, NULL, 16, &end);
393ce3dd8cSRichard Henderson             errors |= qemu_strtou64(fields[2], NULL, 16, &offset);
40*79be812bSRichard Henderson             errors |= qemu_strtoui(fields[3], &p, 16, &dev_maj);
41*79be812bSRichard Henderson             errors |= qemu_strtoui(p + 1, NULL, 16, &dev_min);
423ce3dd8cSRichard Henderson             errors |= qemu_strtou64(fields[4], NULL, 10, &inode);
433ce3dd8cSRichard Henderson 
443ce3dd8cSRichard Henderson             if (!errors) {
45*79be812bSRichard Henderson                 size_t path_len;
463ce3dd8cSRichard Henderson                 MapInfo *e;
473ce3dd8cSRichard Henderson 
483ce3dd8cSRichard Henderson                 if (nfields == 6) {
493ce3dd8cSRichard Henderson                     p = fields[5];
503ce3dd8cSRichard Henderson                     p += strspn(p, " ");
513ce3dd8cSRichard Henderson                     path_len = strlen(p) + 1;
523ce3dd8cSRichard Henderson                 } else {
533ce3dd8cSRichard Henderson                     p = NULL;
543ce3dd8cSRichard Henderson                     path_len = 0;
553ce3dd8cSRichard Henderson                 }
563ce3dd8cSRichard Henderson 
57*79be812bSRichard Henderson                 e = g_malloc0(sizeof(*e) + path_len);
583ce3dd8cSRichard Henderson 
593ce3dd8cSRichard Henderson                 e->itree.start = start;
603ce3dd8cSRichard Henderson                 e->itree.last = end - 1;
613ce3dd8cSRichard Henderson                 e->offset = offset;
62*79be812bSRichard Henderson                 e->dev = makedev(dev_maj, dev_min);
633ce3dd8cSRichard Henderson                 e->inode = inode;
6401ef6b9eSAlex Bennée 
6501ef6b9eSAlex Bennée                 e->is_read  = fields[1][0] == 'r';
6601ef6b9eSAlex Bennée                 e->is_write = fields[1][1] == 'w';
6701ef6b9eSAlex Bennée                 e->is_exec  = fields[1][2] == 'x';
6801ef6b9eSAlex Bennée                 e->is_priv  = fields[1][3] == 'p';
6901ef6b9eSAlex Bennée 
703ce3dd8cSRichard Henderson                 if (path_len) {
71*79be812bSRichard Henderson                     e->path = memcpy(e + 1, p, path_len);
7201ef6b9eSAlex Bennée                 }
7301ef6b9eSAlex Bennée 
743ce3dd8cSRichard Henderson                 interval_tree_insert(&e->itree, root);
753ce3dd8cSRichard Henderson             }
763ce3dd8cSRichard Henderson         }
7701ef6b9eSAlex Bennée         g_strfreev(fields);
7801ef6b9eSAlex Bennée     }
7901ef6b9eSAlex Bennée     g_strfreev(lines);
8001ef6b9eSAlex Bennée     g_free(maps);
8101ef6b9eSAlex Bennée 
823ce3dd8cSRichard Henderson     return root;
8301ef6b9eSAlex Bennée }
8401ef6b9eSAlex Bennée 
8501ef6b9eSAlex Bennée /**
8601ef6b9eSAlex Bennée  * free_self_maps:
873ce3dd8cSRichard Henderson  * @root: an interval tree
8801ef6b9eSAlex Bennée  *
893ce3dd8cSRichard Henderson  * Free a tree of MapInfo structures.
903ce3dd8cSRichard Henderson  * Since we allocated each MapInfo in one chunk, we need not consider the
913ce3dd8cSRichard Henderson  * contents and can simply free each RBNode.
9201ef6b9eSAlex Bennée  */
933ce3dd8cSRichard Henderson 
free_rbnode(RBNode * n)943ce3dd8cSRichard Henderson static void free_rbnode(RBNode *n)
9501ef6b9eSAlex Bennée {
963ce3dd8cSRichard Henderson     if (n) {
973ce3dd8cSRichard Henderson         free_rbnode(n->rb_left);
983ce3dd8cSRichard Henderson         free_rbnode(n->rb_right);
993ce3dd8cSRichard Henderson         g_free(n);
1003ce3dd8cSRichard Henderson     }
10101ef6b9eSAlex Bennée }
10201ef6b9eSAlex Bennée 
free_self_maps(IntervalTreeRoot * root)1033ce3dd8cSRichard Henderson void free_self_maps(IntervalTreeRoot *root)
10401ef6b9eSAlex Bennée {
1053ce3dd8cSRichard Henderson     if (root) {
1063ce3dd8cSRichard Henderson         free_rbnode(root->rb_root.rb_node);
1073ce3dd8cSRichard Henderson         g_free(root);
1083ce3dd8cSRichard Henderson     }
10901ef6b9eSAlex Bennée }
110