aboutsummaryrefslogblamecommitdiff
path: root/gdb.py
blob: 30d8ee3dc21e709925107669e63bfe9a32073298 (plain) (tree)















































                                                                                   
                                                                            

































































































                                                                                                                              
from __future__ import print_function
import gdb
from gdb import Command

MASK_64 = 0xffffffffffffffff

class PageTable(Command):
    def __init__(self):
        super(PageTable, self).__init__("pagetable", gdb.COMMAND_DATA)

    def invoke(self, arg, from_tty):
        try:
            self.sub_invoke(arg, from_tty)
        except KeyboardInterrupt:
            pass

    def sub_invoke(self, arg, from_tty):
        args = [x for x in arg.split(' ') if len(x) > 0]
        table_base = 0xfffffffffffff000

        if len(args) > 0:
            try:
                table_base = int(args[0], 0)
            except ValueError:
                print('argument must be an integer')
                return

        table_base = (table_base >> 3) & MASK_64
        table_base = (table_base << 3) & MASK_64

        if table_base & 0xfff != 0:
            table_base = table_base & ~0xfff
            print('WARN: table misaligned, masking to {:#018x}'.format(table_base))

        mask = 0xff80000000000000  # high 9 bits
        tbl_wrk = ((table_base & 0x000ffffffffff000) << 16) & MASK_64

        table_level = 4
        # noinspection PyUnresolvedReferences
        for i in xrange(4):
            if mask & ~tbl_wrk != 0:
                table_level = i
                break

            tbl_wrk = (tbl_wrk << 9) & MASK_64

        print('inferred table level: {}'.format(table_level))

        table = gdb.parse_and_eval('{:#x} as *const u64'.format(table_base))

        entries_written = False

        # noinspection PyUnresolvedReferences
        for i in xrange(512):
            entry = table[i]
            if entry != 0:
                entries_written = True

                print()

                entry_addr = table_base + i*8
                print('entry {} [{:#x}]'.format(i, entry_addr))

                print('\traw: {:#018x}'.format(int(entry)))

                flags = []
                if entry & 1 << 0 != 0:
                    flags.append('PRESENT')

                if entry & 1 << 1 != 0:
                    flags.append('WRITABLE')

                if entry & 1 << 2 != 0:
                    flags.append('USER_ACCESS')

                if entry & 1 << 3 != 0:
                    flags.append('WRITETHROUGH')

                if entry & 1 << 4 != 0:
                    flags.append('NOCACHE')

                if entry & 1 << 5 != 0:
                    flags.append('ACCESSED')

                if entry & 1 << 6 != 0:
                    flags.append('DIRTY')

                huge = entry & 1 << 7 != 0
                if huge:
                    flags.append('HUGE')

                if entry & 1 << 8 != 0:
                    flags.append('GLOBAL')

                if entry & 1 << 63 != 0:
                    flags.append('NX')

                # TODO: check remaining flags for validity (see intel vol. 4 ch. 4 table 4-9)

                print('\tflags: {}'.format(' '.join(flags)))

                frame = (entry & 0x000ffffffffff000) >> 12

                if table_level > 1 and not huge:
                    subtable_addr = (table_base << 9 | i << 12) & MASK_64
                    print('\tpointed table:')

                    subtable_vmem_base = (subtable_addr << (16 + 9 * (table_level - 1)) & MASK_64) >> 16
                    if subtable_vmem_base & (1 << 47) != 0:
                        subtable_vmem_base |= 0xffff000000000000

                    subtable_size = 1 << (12 + (table_level - 1) * 9)

                    print('\t\tvmem range: {:#x} - {:#x}'.format(subtable_vmem_base, subtable_vmem_base + subtable_size - 1))

                    print('\t\tframe: {:#x}'.format(int(frame)))
                    print('\t\taddr: {:#018x}'.format(subtable_addr))

                elif table_level == 4 or (table_level == 1 and huge):
                    print('\tERROR: unsupported HUGE flag (only applies to levels 2 and 3)')

                else:
                    entry_mag = (12 + (table_level - 1) * 9)
                    virt_base = (entry_addr << (16 + 9 * table_level) & MASK_64) >> 16

                    if virt_base & (1 << 47) != 0:
                        virt_base |= 0xffff000000000000

                    size = 1 << entry_mag

                    print('\taddressing characteristics:')
                    print('\t\tvmem: {:#x} - {:#x}'.format(virt_base, virt_base + size - 1))

                    frame_count = size >> 12

                    if frame_count > 1:
                        print('\t\tframes: {:#x} - {:#x}'.format(int(frame), int(frame) + (size >> 12) - 1))
                    else:
                        print('\t\tframe: {:#x}'.format(int(frame)))

                    print('\t\tsize: {:#x} bytes ({} {})'.format(size, size >> 12, 'frame' if frame_count == 1 else 'frames'))

        if not entries_written:
            print('\tno entries')


PageTable()