xref: /qemu/scripts/qemugdb/mtree.py (revision 12b35405)
1#
2# GDB debugging support
3#
4# Copyright 2012 Red Hat, Inc. and/or its affiliates
5#
6# Authors:
7#  Avi Kivity <avi@redhat.com>
8#
9# This work is licensed under the terms of the GNU GPL, version 2 or
10# later.  See the COPYING file in the top-level directory.
11
12# 'qemu mtree' -- display the memory hierarchy
13
14import gdb
15
16def isnull(ptr):
17    return ptr == gdb.Value(0).cast(ptr.type)
18
19def int128(p):
20    '''Read an Int128 type to a python integer.
21
22    QEMU can be built with native Int128 support so we need to detect
23    if the value is a structure or the native type.
24    '''
25    if p.type.code == gdb.TYPE_CODE_STRUCT:
26        return int(p['lo']) + (int(p['hi']) << 64)
27    else:
28        return int(("%s" % p), 16)
29
30class MtreeCommand(gdb.Command):
31    '''Display the memory tree hierarchy'''
32    def __init__(self):
33        gdb.Command.__init__(self, 'qemu mtree', gdb.COMMAND_DATA,
34                             gdb.COMPLETE_NONE)
35        self.queue = []
36    def invoke(self, arg, from_tty):
37        self.seen = set()
38        self.queue_root('address_space_memory')
39        self.queue_root('address_space_io')
40        self.process_queue()
41    def queue_root(self, varname):
42        ptr = gdb.parse_and_eval(varname)['root']
43        self.queue.append(ptr)
44    def process_queue(self):
45        while self.queue:
46            ptr = self.queue.pop(0)
47            if int(ptr) in self.seen:
48                continue
49            self.print_item(ptr)
50    def print_item(self, ptr, offset = gdb.Value(0), level = 0):
51        self.seen.add(int(ptr))
52        addr = ptr['addr']
53        addr += offset
54        size = int128(ptr['size'])
55        alias = ptr['alias']
56        klass = ''
57        if not isnull(alias):
58            klass = ' (alias)'
59        elif not isnull(ptr['ops']):
60            klass = ' (I/O)'
61        elif bool(ptr['ram']):
62            klass = ' (RAM)'
63        gdb.write('%s%016x-%016x %s%s (@ %s)\n'
64                  % ('  ' * level,
65                     int(addr),
66                     int(addr + (size - 1)),
67                     ptr['name'].string(),
68                     klass,
69                     ptr,
70                     ),
71                  gdb.STDOUT)
72        if not isnull(alias):
73            gdb.write('%s    alias: %s@%016x (@ %s)\n' %
74                      ('  ' * level,
75                       alias['name'].string(),
76                       int(ptr['alias_offset']),
77                       alias,
78                       ),
79                      gdb.STDOUT)
80            self.queue.append(alias)
81        subregion = ptr['subregions']['tqh_first']
82        level += 1
83        while not isnull(subregion):
84            self.print_item(subregion, addr, level)
85            subregion = subregion['subregions_link']['tqe_next']
86