From 2110cbc90707b6b24b279459fbd4b2b8c5158441 Mon Sep 17 00:00:00 2001 From: franciscozdo Date: Sat, 1 Jul 2023 17:07:13 +0200 Subject: [PATCH 1/6] GDB: Improve debugging options for VM subsystem --- sys/debug/__init__.py | 2 + sys/debug/kdump.py | 8 +- sys/debug/proc.py | 10 ++- sys/debug/utils.py | 27 ++++++ sys/debug/virtmem.py | 205 ++++++++++++++++++++++++++++++++---------- sys/debug/vm_map.py | 55 ++++++++++++ 6 files changed, 257 insertions(+), 50 deletions(-) create mode 100644 sys/debug/vm_map.py diff --git a/sys/debug/__init__.py b/sys/debug/__init__.py index 545f1b6960..7d4a0f002c 100644 --- a/sys/debug/__init__.py +++ b/sys/debug/__init__.py @@ -10,6 +10,7 @@ from .sync import CondVar, Mutex from .thread import Kthread, Thread, CurrentThread from .events import stop_handler +from .virtmem import VmInfo def addPrettyPrinters(): @@ -32,6 +33,7 @@ def addPrettyPrinters(): Kthread() Ktrace() Kgmon() +VmInfo() # Functions CurrentThread() diff --git a/sys/debug/kdump.py b/sys/debug/kdump.py index a0f5e70288..47bb7a3fd9 100644 --- a/sys/debug/kdump.py +++ b/sys/debug/kdump.py @@ -1,4 +1,3 @@ -from .virtmem import VmPhysSeg, VmFreePages, VmMapSeg, PhysMap from .memory import Vmem, MallocStats, PoolStats from .cmd import CommandDispatcher @@ -7,6 +6,7 @@ class Kdump(CommandDispatcher): """Examine kernel data structures.""" def __init__(self): - super().__init__('kdump', [VmPhysSeg(), VmFreePages(), VmMapSeg(), - PhysMap(), Vmem(), MallocStats(), - PoolStats()]) + super().__init__('kdump', [Vmem(), + MallocStats(), + PoolStats(), + ]) diff --git a/sys/debug/proc.py b/sys/debug/proc.py index c91d5ce5d5..8229247806 100644 --- a/sys/debug/proc.py +++ b/sys/debug/proc.py @@ -1,9 +1,10 @@ import gdb -from .cmd import SimpleCommand, AutoCompleteMixin +from .cmd import SimpleCommand from .utils import TextTable, global_var from .struct import GdbStructMeta, TailQueue, enum from .thread import Thread +from .vm_map import VmMap from .sync import Mutex @@ -12,6 +13,7 @@ class Process(metaclass=GdbStructMeta): __cast__ = {'p_pid': int, 'p_lock': Mutex, 'p_thread': Thread, + 'p_uspace': VmMap, 'p_state': enum} @staticmethod @@ -32,6 +34,12 @@ def list_all(cls): dead = TailQueue(global_var('zombie_list'), 'p_all') return map(cls, list(alive) + list(dead)) + @classmethod + def find_by_pid(cls, pid): + for p in cls.list_all(): + if p.p_pid == pid: + return p + def __repr__(self): return 'proc{pid=%d}' % self.p_pid diff --git a/sys/debug/utils.py b/sys/debug/utils.py index 622ab1763b..389716ff45 100644 --- a/sys/debug/utils.py +++ b/sys/debug/utils.py @@ -9,6 +9,10 @@ def cast(value, typename): return value.cast(gdb.lookup_type(typename)) +def cast_ptr(value, typename): + return value.cast(gdb.lookup_type(typename).pointer()) + + def local_var(name): return gdb.newest_frame().read_var(name) @@ -21,6 +25,29 @@ def relpath(path): return path.rsplit('sys/')[-1] +def get_arch(): + try: + _ = gdb.parse_and_eval('aarch64_init') + return 'aarch64' + except gdb.error: + pass + + try: + _ = gdb.parse_and_eval('riscv_init') + return 'riscv' + except gdb.error: + pass + + try: + _ = gdb.parse_and_eval('mips_init') + return 'mips' + except gdb.error: + pass + + print('Current architecture is not supported') + raise KeyError + + # calculates address of ret instruction within function body (MIPS specific) def func_ret_addr(name): s = gdb.execute('disass thread_create', to_string=True) diff --git a/sys/debug/virtmem.py b/sys/debug/virtmem.py index 69fb77cef6..1447ee16d9 100644 --- a/sys/debug/virtmem.py +++ b/sys/debug/virtmem.py @@ -1,43 +1,179 @@ -import gdb - from .struct import TailQueue -from .cmd import UserCommand +from .cmd import UserCommand, CommandDispatcher from .cpu import TLBLo -from .utils import TextTable, global_var, cast +from .utils import TextTable, global_var, cast_ptr, get_arch +from .proc import Process PM_NQUEUES = 16 -class PhysMap(UserCommand): - """List active page entries in kernel pmap""" +class VmInfo(CommandDispatcher): + """Examine virtual memory data structures.""" + def __init__(self): - super().__init__('pmap') + super().__init__('vm', [DumpPmap('kernel'), + DumpPmap('user'), + VmMapDump(), + SegmentInfo(''), + SegmentInfo('proc'), + VmPhysSeg(), + VmFreePages(), + ]) + + +def _print_mips_pmap(pmap): + pdp = cast_ptr(pmap['pde'], 'pde_t') + table = TextTable(types='ttttt', align='rrrrr') + table.header(['vpn', 'pte0', 'pte1', 'pte2', 'pte3']) + for i in range(1024): + pde = TLBLo(pdp[i]) + if not pde.valid: + continue + ptp = cast_ptr(pde.ppn, 'pte_t') + pte = [TLBLo(ptp[j]) for j in range(1024)] + for j in range(0, 1024, 4): + if not any(pte.valid for pte in pte[j:j+4]): + continue + pte4 = [str(pte) if pte.valid else '-' for pte in pte[j:j+4]] + table.add_row(['{:8x}'.format((i << 22) + (j << 12)), + pte4[0], pte4[1], pte4[2], pte4[3]]) + print(table) + + +class DumpPmap(UserCommand): + """List active page entries in user pmap""" + + def __init__(self, typ): + command = 'pmap_' + typ + if command not in ('pmap_user', 'pmap_kernel'): + print(f'{command} command not supported') + return + self.command = command + super().__init__(command) def __call__(self, args): - pdp = global_var('kernel_pmap')['pde'] - table = TextTable(types='ttttt', align='rrrrr') - table.header(['vpn', 'pte0', 'pte1', 'pte2', 'pte3']) - for i in range(1024): - pde = TLBLo(pdp[i]) - if not pde.valid: - continue - ptp = pde.ppn.cast(gdb.lookup_type('pte_t').pointer()) - pte = [TLBLo(ptp[j]) for j in range(1024)] - for j in range(0, 1024, 4): - if not any(pte.valid for pte in pte[j:j+4]): - continue - pte4 = [str(pte) if pte.valid else '-' for pte in pte[j:j+4]] - table.add_row(['{:8x}'.format((i << 22) + (j << 12)), - pte4[0], pte4[1], pte4[2], pte4[3]]) + if self.command == 'pmap_kernel': + pmap = global_var('kernel_pmap') + else: + args = args.split() + if len(args) == 0: + proc = Process.from_current() + else: + pid = int(args[0]) + proc = Process.find_by_pid(pid) + if proc is None: + print(f'Process {pid} not found') + return + pmap = proc.p_uspace.pmap + + arch = get_arch() + if arch == 'mips': + _print_mips_pmap(pmap) + else: + print(f"Can't print {arch} pmap") + + +class VmMapDump(UserCommand): + """List segments describing virtual address space""" + + def __init__(self): + super().__init__('map') + + def __call__(self, args): + args = args.split() + if len(args) == 0: + proc = Process.from_current() + else: + pid = int(args[0]) + proc = Process.find_by_pid(pid) + if proc is None: + print(f'Process {pid} not found') + return + + entries = proc.p_uspace.get_entries() + + table = TextTable(types='ittttt', align='rrrrrr') + table.header(['segment', 'start', 'end', 'prot', 'flags', 'amap']) + for idx, seg in enumerate(entries): + table.add_row([idx, hex(seg.start), hex(seg.end), seg.prot, + seg.flags, seg.aref]) print(table) +class SegmentInfo(UserCommand): + """Show info about i-th segment in proc vm_map""" + + def __init__(self, typ): + command = f"segment{'_' if typ != '' else ''}{typ}" + if command not in ['segment', 'segment_proc']: + print(f'{command} command not supported') + return + self.command = command + super().__init__(command) + + def _print_segment(self, seg, pid, id): + print('Segment {} in proc {}'.format(id, pid)) + print('Range: {:#08x}-{:#08x} ({:d} pages)'.format(seg.start, + seg.end, + seg.pages)) + print('Prot: {}'.format(seg.prot)) + print('Flags: {}'.format(seg.flags)) + amap = seg.amap + if amap: + print('Amap: {}'.format(seg.amap_ptr)) + print('Amap offset: {}'.format(seg.amap_offset)) + print('Amap slots: {}'.format(amap.slots)) + print('Amap refs: {}'.format(amap.ref_cnt)) + + # TODO: show used pages/anons + else: + print('Amap: NULL') + + def __call__(self, args): + args = args.split() + if self.command == 'segment': + if len(args) < 1: + print('require argument (segment)') + return + proc = Process.from_current() + else: + if len(args) < 2: + print('require 2 arguments (pid and segment)') + return + + pid = int(args[0]) + proc = Process.find_by_pid(pid) + if proc is None: + print(f'Process {pid} not found') + return + args = args[1:] + + entries = proc.p_uspace.get_entries() + + segment = int(args[0], 0) + + if segment < 4096: + # Lookup by id + if segment > len(entries): + print(f'Segment {segment} does not exist!') + return + self._print_segment(entries[segment], proc.p_pid, segment) + else: + # Lookup by address + addr = segment + for idx, e in enumerate(entries): + if e.start <= addr and addr < e.end: + self._print_segment(e, proc.p_pid, idx) + return + print(f'Segment with address {addr} not found') + + class VmPhysSeg(UserCommand): """List physical memory segments managed by vm subsystem""" def __init__(self): - super().__init__('vm_physseg') + super().__init__('physseg') def __call__(self, args): table = TextTable(types='ittit', align='rrrrr') @@ -53,7 +189,7 @@ class VmFreePages(UserCommand): """List free pages known to vm subsystem""" def __init__(self): - super().__init__('vm_freepages') + super().__init__('freepages') def __call__(self, args): table = TextTable(align='rrl', types='iit') @@ -71,24 +207,3 @@ def __call__(self, args): segments = TailQueue(global_var('seglist'), 'seglink') pages = int(sum(seg['npages'] for seg in segments if not seg['used'])) print('Used pages count: {}'.format(pages - free_pages)) - - -class VmMapSeg(UserCommand): - """List segments describing virtual address space""" - - def __init__(self): - super().__init__('vm_map') - - def __call__(self, args): - vm_map = gdb.parse_and_eval('vm_map_user()') - if vm_map == 0: - print('No active user vm_map!') - return - entries = vm_map['entries'] - table = TextTable(types='ittttt', align='rrrrrr') - table.header(['segment', 'start', 'end', 'prot', 'flags', 'amap']) - segments = TailQueue(entries, 'link') - for idx, seg in enumerate(segments): - table.add_row([idx, seg['start'], seg['end'], seg['prot'], - seg['flags'], seg['aref']]) - print(table) diff --git a/sys/debug/vm_map.py b/sys/debug/vm_map.py new file mode 100644 index 0000000000..15f5207957 --- /dev/null +++ b/sys/debug/vm_map.py @@ -0,0 +1,55 @@ +from .struct import GdbStructMeta +from .struct import TailQueue + + +class VmMap(metaclass=GdbStructMeta): + __ctype__ = 'struct vm_map' + + def __repr__(self): + return 'vm_map[entries=[{} {}], pmap={}]'.format( + self.entries, self.nentries, self.pmap) + + def get_entries(self): + entries = TailQueue(self.entries, 'link') + return [VmMapEntry(e) for e in entries] + + +class VmMapEntry(metaclass=GdbStructMeta): + __ctype__ = 'struct vm_map_entry' + __cast__ = {'start': int, + 'end': int} + + def __repr__(self): + return 'vm_map_entry[{:#08x}-{:#08x}]'.format(self.start, self.end) + + @property + def amap_ptr(self): + return self.aref['amap'] + + @property + def pages(self): + size = self.end - self.start + return int(size / 4096) + + @property + def amap(self): + if int(self.aref['amap']) == 0: + return None + else: + return Amap(self.aref['amap']) + + @property + def amap_offset(self): + return self.aref['offset'] + + def amap_bitmap_str(self): + return self.amap.str_bitmap(self.amap_offset, self.pages) + + +class Amap(metaclass=GdbStructMeta): + __ctype__ = 'struct vm_amap' + __cast__ = {'slots': int, + 'ref_cnt': int} + + def __repr__(self): + return 'vm_amap[slots={}, refs={}]'.format(self.slots, self.ref_cnt) From b41d7ba5b35c44261c040cf60713169289e231cd Mon Sep 17 00:00:00 2001 From: franciscozdo Date: Sat, 1 Jul 2023 18:20:42 +0200 Subject: [PATCH 2/6] GDB: make sparate class for each command --- sys/debug/virtmem.py | 196 ++++++++++++++++++++++++------------------- 1 file changed, 112 insertions(+), 84 deletions(-) diff --git a/sys/debug/virtmem.py b/sys/debug/virtmem.py index 1447ee16d9..1053b42518 100644 --- a/sys/debug/virtmem.py +++ b/sys/debug/virtmem.py @@ -12,11 +12,11 @@ class VmInfo(CommandDispatcher): """Examine virtual memory data structures.""" def __init__(self): - super().__init__('vm', [DumpPmap('kernel'), - DumpPmap('user'), + super().__init__('vm', [KernelPmap(), + UserPmap(), VmMapDump(), - SegmentInfo(''), - SegmentInfo('proc'), + CurrentSegmentInfo(), + ProcSegmentInfo(), VmPhysSeg(), VmFreePages(), ]) @@ -41,32 +41,46 @@ def _print_mips_pmap(pmap): print(table) -class DumpPmap(UserCommand): - """List active page entries in user pmap""" +class KernelPmap(UserCommand): + """List active page entries in kernel pmap""" - def __init__(self, typ): - command = 'pmap_' + typ - if command not in ('pmap_user', 'pmap_kernel'): - print(f'{command} command not supported') - return - self.command = command - super().__init__(command) + def __init__(self): + super().__init__('pmap_kernel') def __call__(self, args): - if self.command == 'pmap_kernel': - pmap = global_var('kernel_pmap') + pmap = global_var('kernel_pmap') + arch = get_arch() + if arch == 'mips': + _print_mips_pmap(pmap) else: - args = args.split() - if len(args) == 0: - proc = Process.from_current() - else: - pid = int(args[0]) - proc = Process.find_by_pid(pid) - if proc is None: - print(f'Process {pid} not found') - return - pmap = proc.p_uspace.pmap + print(f"Can't print {arch} pmap") + +class UserPmap(UserCommand): + """List active page entries in user pmap + + vm pmap_user [pid] + + Arguments: + pid pid of process to show pmap for + + If argument is not specifed the pmap of current process is dumped. + """ + + def __init__(self): + super().__init__('pmap_user') + + def __call__(self, args): + args = args.split() + if len(args) == 0: + proc = Process.from_current() + else: + pid = int(args[0]) + proc = Process.find_by_pid(pid) + if proc is None: + print(f'Process {pid} not found') + return + pmap = proc.p_uspace.pmap arch = get_arch() if arch == 'mips': _print_mips_pmap(pmap) @@ -75,7 +89,15 @@ def __call__(self, args): class VmMapDump(UserCommand): - """List segments describing virtual address space""" + """List segments describing virtual address space + + vm map [pid] + + Arguments: + pid pid of process to list vm_map for + + If argument is not specifed the vm_map of current process is listed. + """ def __init__(self): super().__init__('map') @@ -101,72 +123,78 @@ def __call__(self, args): print(table) -class SegmentInfo(UserCommand): - """Show info about i-th segment in proc vm_map""" - - def __init__(self, typ): - command = f"segment{'_' if typ != '' else ''}{typ}" - if command not in ['segment', 'segment_proc']: - print(f'{command} command not supported') +def _print_segment(seg, pid, id): + print('Segment {} in proc {}'.format(id, pid)) + print('Range: {:#08x}-{:#08x} ({:d} pages)'.format(seg.start, + seg.end, + seg.pages)) + print('Prot: {}'.format(seg.prot)) + print('Flags: {}'.format(seg.flags)) + amap = seg.amap + if amap: + print('Amap: {}'.format(seg.amap_ptr)) + print('Amap offset: {}'.format(seg.amap_offset)) + print('Amap slots: {}'.format(amap.slots)) + print('Amap refs: {}'.format(amap.ref_cnt)) + + # TODO: show used pages/anons + else: + print('Amap: NULL') + + +def _segment_info(proc, segment): + entries = proc.p_uspace.get_entries() + if segment < 4096: + # Lookup by id + if segment > len(entries): + print(f'Segment {segment} does not exist!') return - self.command = command - super().__init__(command) - - def _print_segment(self, seg, pid, id): - print('Segment {} in proc {}'.format(id, pid)) - print('Range: {:#08x}-{:#08x} ({:d} pages)'.format(seg.start, - seg.end, - seg.pages)) - print('Prot: {}'.format(seg.prot)) - print('Flags: {}'.format(seg.flags)) - amap = seg.amap - if amap: - print('Amap: {}'.format(seg.amap_ptr)) - print('Amap offset: {}'.format(seg.amap_offset)) - print('Amap slots: {}'.format(amap.slots)) - print('Amap refs: {}'.format(amap.ref_cnt)) - - # TODO: show used pages/anons - else: - print('Amap: NULL') + _print_segment(entries[segment], proc.p_pid, segment) + else: + # Lookup by address + addr = segment + for idx, e in enumerate(entries): + if e.start <= addr and addr < e.end: + _print_segment(e, proc.p_pid, idx) + return + print(f'Segment with address {addr} not found') + + +class CurrentSegmentInfo(UserCommand): + """Show info about i-th segment in curent proc vm_map""" + + def __init__(self): + super().__init__('segment') def __call__(self, args): args = args.split() - if self.command == 'segment': - if len(args) < 1: - print('require argument (segment)') - return - proc = Process.from_current() - else: - if len(args) < 2: - print('require 2 arguments (pid and segment)') - return + if len(args) < 1: + print('require argument (segment)') + return + proc = Process.from_current() + segment = int(args[0], 0) + _segment_info(proc, segment) - pid = int(args[0]) - proc = Process.find_by_pid(pid) - if proc is None: - print(f'Process {pid} not found') - return - args = args[1:] - entries = proc.p_uspace.get_entries() +class ProcSegmentInfo(UserCommand): + """Show info about i-th segment in proc vm_map""" - segment = int(args[0], 0) + def __init__(self): + super().__init__('segment_proc') - if segment < 4096: - # Lookup by id - if segment > len(entries): - print(f'Segment {segment} does not exist!') - return - self._print_segment(entries[segment], proc.p_pid, segment) - else: - # Lookup by address - addr = segment - for idx, e in enumerate(entries): - if e.start <= addr and addr < e.end: - self._print_segment(e, proc.p_pid, idx) - return - print(f'Segment with address {addr} not found') + def __call__(self, args): + args = args.split() + if len(args) < 2: + print('require 2 arguments (pid and segment)') + return + + pid = int(args[0]) + proc = Process.find_by_pid(pid) + if proc is None: + print(f'Process {pid} not found') + return + segment = int(args[1], 0) + _segment_info(proc, segment) class VmPhysSeg(UserCommand): From 82b131c120b22efda8736b5608001af2ec517c00 Mon Sep 17 00:00:00 2001 From: franciscozdo Date: Sat, 1 Jul 2023 18:58:47 +0200 Subject: [PATCH 3/6] GDB: print pages used in segment --- sys/debug/virtmem.py | 2 +- sys/debug/vm_map.py | 27 +++++++++++++++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/sys/debug/virtmem.py b/sys/debug/virtmem.py index 1053b42518..750a695908 100644 --- a/sys/debug/virtmem.py +++ b/sys/debug/virtmem.py @@ -137,7 +137,7 @@ def _print_segment(seg, pid, id): print('Amap slots: {}'.format(amap.slots)) print('Amap refs: {}'.format(amap.ref_cnt)) - # TODO: show used pages/anons + amap.print_pages(seg.amap_offset, seg.pages) else: print('Amap: NULL') diff --git a/sys/debug/vm_map.py b/sys/debug/vm_map.py index 15f5207957..7ac649c4b6 100644 --- a/sys/debug/vm_map.py +++ b/sys/debug/vm_map.py @@ -53,3 +53,30 @@ class Amap(metaclass=GdbStructMeta): def __repr__(self): return 'vm_amap[slots={}, refs={}]'.format(self.slots, self.ref_cnt) + + def _get_bitmap(self): + bitmap = [] + bitssize = ((self.slots) + 7) >> 3 + for i in range(bitssize): + val = self.pg_bitmap[i] + for _ in range(8): + bitmap.append(val & 1 == 1) + val >>= 1 + return bitmap + + def print_pages(self, offset, n): + bm = self._get_bitmap() + slots = 'Page num:' + values = 'Ref cnt: ' + used = 0 + for i in range(n): + slots += f'{i:^5}' + if bm[offset + i]: + values += f'{1:^5}' + used += 1 + else: + values += f'{"-": ^5}' + + print(f'Pages used by segment ({used} pages)') + print(slots) + print(values) From 89c8306bcde32bdaf0c1e55c788846b469ef8541 Mon Sep 17 00:00:00 2001 From: franciscozdo Date: Mon, 7 Aug 2023 20:26:48 +0200 Subject: [PATCH 4/6] Apply review changes --- sys/debug/utils.py | 23 ++++++----------------- sys/debug/virtmem.py | 31 +++++++++++++++---------------- sys/debug/vm_map.py | 17 ++++++++--------- 3 files changed, 29 insertions(+), 42 deletions(-) diff --git a/sys/debug/utils.py b/sys/debug/utils.py index 389716ff45..0410704f42 100644 --- a/sys/debug/utils.py +++ b/sys/debug/utils.py @@ -26,23 +26,12 @@ def relpath(path): def get_arch(): - try: - _ = gdb.parse_and_eval('aarch64_init') - return 'aarch64' - except gdb.error: - pass - - try: - _ = gdb.parse_and_eval('riscv_init') - return 'riscv' - except gdb.error: - pass - - try: - _ = gdb.parse_and_eval('mips_init') - return 'mips' - except gdb.error: - pass + for arch in ['mips', 'aarch64', 'riscv']: + try: + _ = gdb.parse_and_eval(f'{arch}_init') + return arch + except gdb.error: + continue print('Current architecture is not supported') raise KeyError diff --git a/sys/debug/virtmem.py b/sys/debug/virtmem.py index 750a695908..16335bbf9d 100644 --- a/sys/debug/virtmem.py +++ b/sys/debug/virtmem.py @@ -36,8 +36,8 @@ def _print_mips_pmap(pmap): if not any(pte.valid for pte in pte[j:j+4]): continue pte4 = [str(pte) if pte.valid else '-' for pte in pte[j:j+4]] - table.add_row(['{:8x}'.format((i << 22) + (j << 12)), - pte4[0], pte4[1], pte4[2], pte4[3]]) + table.add_row([f'{(i << 22) + (j << 12):8x}', pte4[0], pte4[1], + pte4[2], pte4[3]]) print(table) @@ -124,18 +124,16 @@ def __call__(self, args): def _print_segment(seg, pid, id): - print('Segment {} in proc {}'.format(id, pid)) - print('Range: {:#08x}-{:#08x} ({:d} pages)'.format(seg.start, - seg.end, - seg.pages)) - print('Prot: {}'.format(seg.prot)) - print('Flags: {}'.format(seg.flags)) + print(f'Segment {id} in proc {pid}') + print(f'Range: {seg.start:#08x}-{seg.end:#08x} ({seg.pages:d} pages)') + print(f'Prot: {seg.prot}') + print(f'Flags: {seg.flags}') amap = seg.amap if amap: - print('Amap: {}'.format(seg.amap_ptr)) - print('Amap offset: {}'.format(seg.amap_offset)) - print('Amap slots: {}'.format(amap.slots)) - print('Amap refs: {}'.format(amap.ref_cnt)) + print(f'Amap: {seg.amap_ptr}') + print(f'Amap offset: {seg.amap_offset}') + print(f'Amap slots: {amap.slots}') + print(f'Amap refs: {amap.refcnt}') amap.print_pages(seg.amap_offset, seg.pages) else: @@ -143,8 +141,9 @@ def _print_segment(seg, pid, id): def _segment_info(proc, segment): + MAX_SEGMENT_ID = 4096 entries = proc.p_uspace.get_entries() - if segment < 4096: + if segment < MAX_SEGMENT_ID: # Lookup by id if segment > len(entries): print(f'Segment {segment} does not exist!') @@ -226,12 +225,12 @@ def __call__(self, args): count = int(global_var('pagecount')[q]) pages = [] for page in TailQueue(global_var('freelist')[q], 'freeq'): - pages.append('{:8x}'.format(int(page['paddr']))) + pages.append(f'{int(page["paddr"]):8x}') free_pages += int(page['size']) table.add_row([count, 2**q, ' '.join(pages)]) table.header(['#pages', 'size', 'addresses']) print(table) - print('Free pages count: {}'.format(free_pages)) + print(f'Free pages count: {free_pages}') segments = TailQueue(global_var('seglist'), 'seglink') pages = int(sum(seg['npages'] for seg in segments if not seg['used'])) - print('Used pages count: {}'.format(pages - free_pages)) + print(f'Used pages count: {pages - free_pages}') diff --git a/sys/debug/vm_map.py b/sys/debug/vm_map.py index 7ac649c4b6..7b4647fc94 100644 --- a/sys/debug/vm_map.py +++ b/sys/debug/vm_map.py @@ -6,8 +6,8 @@ class VmMap(metaclass=GdbStructMeta): __ctype__ = 'struct vm_map' def __repr__(self): - return 'vm_map[entries=[{} {}], pmap={}]'.format( - self.entries, self.nentries, self.pmap) + return (f'vm_map[entries=[{self.entries} {self.nentries}],' + f'pmap={self.pmap}]') def get_entries(self): entries = TailQueue(self.entries, 'link') @@ -20,7 +20,7 @@ class VmMapEntry(metaclass=GdbStructMeta): 'end': int} def __repr__(self): - return 'vm_map_entry[{:#08x}-{:#08x}]'.format(self.start, self.end) + return f'vm_map_entry[{self.start:#08x}-{self.end:#08x}]' @property def amap_ptr(self): @@ -29,14 +29,13 @@ def amap_ptr(self): @property def pages(self): size = self.end - self.start - return int(size / 4096) + return size // 4096 @property def amap(self): - if int(self.aref['amap']) == 0: + if not self.aref['amap']: return None - else: - return Amap(self.aref['amap']) + return Amap(self.aref['amap']) @property def amap_offset(self): @@ -52,11 +51,11 @@ class Amap(metaclass=GdbStructMeta): 'ref_cnt': int} def __repr__(self): - return 'vm_amap[slots={}, refs={}]'.format(self.slots, self.ref_cnt) + return f'vm_amap[slots={self.slots}, refs={self.ref_cnt}]' def _get_bitmap(self): bitmap = [] - bitssize = ((self.slots) + 7) >> 3 + bitssize = (self.slots + 7) >> 3 for i in range(bitssize): val = self.pg_bitmap[i] for _ in range(8): From 4dd32e45b0c476cd6c92ecff58467197528d02e7 Mon Sep 17 00:00:00 2001 From: franciscozdo Date: Mon, 7 Aug 2023 21:38:33 +0200 Subject: [PATCH 5/6] Update printing pmap --- sys/debug/cpu.py | 53 +++++++++++++++++++++++++++++++++++++++++++- sys/debug/utils.py | 6 +---- sys/debug/virtmem.py | 39 +++++--------------------------- 3 files changed, 59 insertions(+), 39 deletions(-) diff --git a/sys/debug/cpu.py b/sys/debug/cpu.py index 05d09e6f94..6df002ff3c 100644 --- a/sys/debug/cpu.py +++ b/sys/debug/cpu.py @@ -1,7 +1,7 @@ import gdb from .struct import GdbStructMeta -from .utils import TextTable, cast +from .utils import TextTable, cast, cast_ptr, get_arch from .cmd import UserCommand, CommandDispatcher @@ -110,3 +110,54 @@ class Cpu(CommandDispatcher): def __init__(self): super().__init__('cpu', [TLB()]) + + +class PageTableMips(): + def __init__(self, pmap): + self._pmap = pmap + + def print(self): + pdp = cast_ptr(self._pmap['pde'], 'pde_t') + table = TextTable(types='ttttt', align='rrrrr') + table.header(['vpn', 'pte0', 'pte1', 'pte2', 'pte3']) + for i in range(1024): + pde = TLBLo(pdp[i]) + if not pde.valid: + continue + ptp = cast_ptr(pde.ppn, 'pte_t') + pte = [TLBLo(ptp[j]) for j in range(1024)] + for j in range(0, 1024, 4): + if not any(pte.valid for pte in pte[j:j+4]): + continue + pte4 = [str(pte) if pte.valid else '-' for pte in pte[j:j+4]] + table.add_row([f'{(i << 22) + (j << 12):8x}', pte4[0], pte4[1], + pte4[2], pte4[3]]) + print(table) + + +class PageTableAarch64(): + def __init__(self, pmap): + self._pmap = pmap + print("Page table not implemented for Aarch64") + + def print(self): + pass + + +class PageTableRiscv(): + def __init__(self, pmap): + self._pmap = pmap + print("Page table not implemented for RISC-V") + + def print(self): + pass + + +if get_arch() == 'mips': + PageTable = PageTableMips +elif get_arch() == 'aarch64': + PageTable = PageTableAarch64 +elif get_arch() == 'riscv': + PageTable = PageTableRiscv +else: + print(f'Arch {get_arch()} not supported') diff --git a/sys/debug/utils.py b/sys/debug/utils.py index 0410704f42..61977c14ae 100644 --- a/sys/debug/utils.py +++ b/sys/debug/utils.py @@ -27,12 +27,8 @@ def relpath(path): def get_arch(): for arch in ['mips', 'aarch64', 'riscv']: - try: - _ = gdb.parse_and_eval(f'{arch}_init') + if arch in gdb.architecture_names(): return arch - except gdb.error: - continue - print('Current architecture is not supported') raise KeyError diff --git a/sys/debug/virtmem.py b/sys/debug/virtmem.py index 16335bbf9d..a2f4c06753 100644 --- a/sys/debug/virtmem.py +++ b/sys/debug/virtmem.py @@ -1,7 +1,7 @@ from .struct import TailQueue from .cmd import UserCommand, CommandDispatcher -from .cpu import TLBLo -from .utils import TextTable, global_var, cast_ptr, get_arch +from .cpu import PageTable +from .utils import TextTable, global_var from .proc import Process @@ -22,25 +22,6 @@ def __init__(self): ]) -def _print_mips_pmap(pmap): - pdp = cast_ptr(pmap['pde'], 'pde_t') - table = TextTable(types='ttttt', align='rrrrr') - table.header(['vpn', 'pte0', 'pte1', 'pte2', 'pte3']) - for i in range(1024): - pde = TLBLo(pdp[i]) - if not pde.valid: - continue - ptp = cast_ptr(pde.ppn, 'pte_t') - pte = [TLBLo(ptp[j]) for j in range(1024)] - for j in range(0, 1024, 4): - if not any(pte.valid for pte in pte[j:j+4]): - continue - pte4 = [str(pte) if pte.valid else '-' for pte in pte[j:j+4]] - table.add_row([f'{(i << 22) + (j << 12):8x}', pte4[0], pte4[1], - pte4[2], pte4[3]]) - print(table) - - class KernelPmap(UserCommand): """List active page entries in kernel pmap""" @@ -48,12 +29,8 @@ def __init__(self): super().__init__('pmap_kernel') def __call__(self, args): - pmap = global_var('kernel_pmap') - arch = get_arch() - if arch == 'mips': - _print_mips_pmap(pmap) - else: - print(f"Can't print {arch} pmap") + pmap = PageTable(global_var('kernel_pmap')) + pmap.print() class UserPmap(UserCommand): @@ -80,12 +57,8 @@ def __call__(self, args): if proc is None: print(f'Process {pid} not found') return - pmap = proc.p_uspace.pmap - arch = get_arch() - if arch == 'mips': - _print_mips_pmap(pmap) - else: - print(f"Can't print {arch} pmap") + pmap = PageTable(proc.p_uspace.pmap) + pmap.print() class VmMapDump(UserCommand): From 0c4fe754e645baf51b8e280adb3c81f4db9a909a Mon Sep 17 00:00:00 2001 From: franciscozdo Date: Mon, 7 Aug 2023 21:41:02 +0200 Subject: [PATCH 6/6] Fix AArch64 name --- sys/debug/cpu.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sys/debug/cpu.py b/sys/debug/cpu.py index 6df002ff3c..ce8555d5eb 100644 --- a/sys/debug/cpu.py +++ b/sys/debug/cpu.py @@ -135,10 +135,10 @@ def print(self): print(table) -class PageTableAarch64(): +class PageTableAArch64(): def __init__(self, pmap): self._pmap = pmap - print("Page table not implemented for Aarch64") + print("Page table not implemented for AArch64") def print(self): pass @@ -156,7 +156,7 @@ def print(self): if get_arch() == 'mips': PageTable = PageTableMips elif get_arch() == 'aarch64': - PageTable = PageTableAarch64 + PageTable = PageTableAArch64 elif get_arch() == 'riscv': PageTable = PageTableRiscv else: