diff --git a/sys/debug/README.md b/sys/debug/README.md index a710f7dac3..9964d0b43e 100644 --- a/sys/debug/README.md +++ b/sys/debug/README.md @@ -16,8 +16,10 @@ you can use following custom commands: * `free_pages` - list of free pages per segment with virtual and physical addresses, -* `segments` - list all memory segments, incl. start, end addresses and - number of pages (currently just one), +* `vm_map` - list memory map of process of given pid (when number is given as argument) + or of current process (when no argument is given) +* `vm_address` - dump all information about given address in process virtual address space + (e.g. `kdump vm_address 3 0x412000` tells about address 0x412000 in vmspace of process 3) * `klog` - all log messages currently saved in the kernel (can be saved to file as well), * `threads` - all existing threads, diff --git a/sys/debug/__init__.py b/sys/debug/__init__.py index 545f1b6960..79fdf3e8d6 100644 --- a/sys/debug/__init__.py +++ b/sys/debug/__init__.py @@ -5,7 +5,7 @@ from .kgmon import Kgmon from .klog import Klog from .ktrace import Ktrace -from .proc import Kprocess, Process, CurrentProcess +from .proc import Kprocess, Process, ShowProcess from .struct import BinTime from .sync import CondVar, Mutex from .thread import Kthread, Thread, CurrentThread @@ -35,7 +35,7 @@ def addPrettyPrinters(): # Functions CurrentThread() -CurrentProcess() +ShowProcess() # Events gdb.events.stop.connect(stop_handler) diff --git a/sys/debug/kdump.py b/sys/debug/kdump.py index a0f5e70288..f3b5a0be8e 100644 --- a/sys/debug/kdump.py +++ b/sys/debug/kdump.py @@ -1,5 +1,5 @@ -from .virtmem import VmPhysSeg, VmFreePages, VmMapSeg, PhysMap -from .memory import Vmem, MallocStats, PoolStats +from .virtmem import VmAddress, VmPhysSeg, VmFreePages, VmMapSeg, PhysMap +from .memory import Vmem, Malloc, MallocStats, PoolStats from .cmd import CommandDispatcher @@ -10,3 +10,6 @@ def __init__(self): super().__init__('kdump', [VmPhysSeg(), VmFreePages(), VmMapSeg(), PhysMap(), Vmem(), MallocStats(), PoolStats()]) + super().__init__('kdump', [VmAddress(), VmPhysSeg(), VmFreePages(), + VmMapSeg(), PhysMap(), Vmem(), Malloc(), + MallocStats(), PoolStats()]) diff --git a/sys/debug/proc.py b/sys/debug/proc.py index c91d5ce5d5..3ddbcebb8a 100644 --- a/sys/debug/proc.py +++ b/sys/debug/proc.py @@ -26,6 +26,15 @@ def from_current(cls): def from_pointer(cls, ptr): return cls(gdb.parse_and_eval('(struct proc *)' + ptr).dereference()) + @classmethod + def from_pid(cls, pid): + alive = list(TailQueue(global_var('proc_list'), 'p_all')) + dead = list(TailQueue(global_var('zombie_list'), 'p_all')) + for p in alive + dead: + if p['p_pid'] == pid: + return cls(p) + return None + @classmethod def list_all(cls): alive = TailQueue(global_var('proc_list'), 'p_all') @@ -35,6 +44,12 @@ def list_all(cls): def __repr__(self): return 'proc{pid=%d}' % self.p_pid + def address(self): + return self._obj.address + + def vm_map(self): + return self._obj['p_uspace'] + class Kprocess(SimpleCommand): """List all processes.""" @@ -56,11 +71,17 @@ def __call__(self, args): print(table) -class CurrentProcess(gdb.Function): - """Return address of currently running process.""" +class ShowProcess(gdb.Function): + """Return address of process of given pid (default current process).""" def __init__(self): - super().__init__('process') - - def invoke(self): - return Process.current() + super().__init__('proc') + + def invoke(self, pid=-1): + if pid == -1: + return Process.current() + p = Process.from_pid(pid) + if p: + return p.address() + print(f"No process of pid={pid}") + return 0 diff --git a/sys/debug/virtmem.py b/sys/debug/virtmem.py index f3407f1cf2..9cced2a9bd 100644 --- a/sys/debug/virtmem.py +++ b/sys/debug/virtmem.py @@ -4,6 +4,7 @@ from .cmd import UserCommand from .cpu import TLBLo from .utils import TextTable, global_var, cast +from .proc import Process PM_NQUEUES = 16 @@ -80,16 +81,80 @@ 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 + args = args.strip() + if len(args) == 0: + vm_map = gdb.parse_and_eval('vm_map_user()') + if vm_map == 0: + print('No active user vm_map!') + return + else: + pid = int(args) + proc = Process.from_pid(pid) + if proc is None: + print(f'No process of pid {pid}!') + return + vm_map = proc.vm_map() + entries = vm_map['entries'] - table = TextTable(types='itttttt', align='rrrrrrr') - table.header(['segment', 'start', 'end', 'prot', 'flags', 'object', - 'offset']) + table = TextTable(types='ittttt', align='rrrrrr') + table.header(['segment', 'start', 'end', 'prot', 'flags', 'object']) segments = TailQueue(entries, 'link') for idx, seg in enumerate(segments): table.add_row([idx, seg['start'], seg['end'], seg['prot'], - seg['flags'], seg['object'], seg['offset']]) + seg['flags'], seg['object']]) print(table) + + +def print_entry(ent): + table = TextTable(types='tttttt', align='rrrrrr') + table.header(['start', 'end', 'prot', 'flags', 'object', 'offset']) + table.add_row([ent['start'], ent['end'], ent['prot'], ent['flags'], + ent['object'], ent['offset']]) + print(table) + + +def print_addr_in_object(ent, address): + offset = ent['offset'] + address - ent['start'] + obj_addr = ent['object'] + page = gdb.parse_and_eval(f'vm_object_find_page({obj_addr}, {offset})') + if page == 0x0: + print(f'There is no page for address {hex(address)} in vm_object') + return + obj = obj_addr.dereference() + print(f'Page found in object ({obj_addr}):\n{obj}') + + +class VmAddress(UserCommand): + """List all information about addres in given vm_map""" + + def __init__(self): + super().__init__('vm_address') + + def __call__(self, args): + args = args.split() + + if len(args) < 2: + print("Please give pid and address") + return + + pid = int(args[0]) + address = int(args[1], 16) + + proc = Process.from_pid(pid) + if proc is None: + print(f'No process of pid {pid}!') + return + + PAGESHIFT = 12 + entries = TailQueue(proc.vm_map()['entries'], 'link') + for ent in entries: + if address >= ent['start'] and address < ent['end']: + print(f'Address in entry {ent.address}') + print_entry(ent) + # align address + address = (address >> PAGESHIFT) << PAGESHIFT + obj = ent['object'] + if obj != 0: + print_addr_in_object(ent, address) + return + print(f'Adress not found in process {pid} address space.')