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