vmmap: fix riscv64 kernel (#3252)

* vmmap: fix crash with pi.markers

* fix refactor

* vmmap: fix riscv64 `info mem`
pull/3258/head
patryk4815 4 months ago committed by GitHub
parent 89095d1214
commit 260a7204a7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -427,49 +427,33 @@ class Aarch64Ops(ArchOps):
return int(pwndbg.aglib.regs.SCTLR) & BIT(0) != 0
_arch_paginginfo: ArchPagingInfo = None
@pwndbg.lib.cache.cache_until("start")
def arch_paginginfo() -> ArchPagingInfo:
global _arch_paginginfo
if _arch_paginginfo is None:
def arch_paginginfo() -> ArchPagingInfo | None:
if pwndbg.aglib.arch.name == "aarch64":
_arch_paginginfo = pwndbg.aglib.kernel.paging.Aarch64PagingInfo()
return pwndbg.aglib.kernel.paging.Aarch64PagingInfo()
elif pwndbg.aglib.arch.name == "x86-64":
_arch_paginginfo = pwndbg.aglib.kernel.paging.x86_64PagingInfo()
return _arch_paginginfo
_arch_ops: ArchOps = None
return pwndbg.aglib.kernel.paging.x86_64PagingInfo()
return None
@pwndbg.lib.cache.cache_until("start")
def arch_ops() -> ArchOps:
global _arch_ops
if _arch_ops is None:
def arch_ops() -> ArchOps | None:
if pwndbg.aglib.arch.name == "aarch64":
_arch_ops = Aarch64Ops()
return Aarch64Ops()
elif pwndbg.aglib.arch.name == "x86-64":
_arch_ops = x86_64Ops()
return x86_64Ops()
elif pwndbg.aglib.arch.name == "i386":
_arch_ops = i386Ops()
return _arch_ops
_arch_symbols: pwndbg.aglib.kernel.symbol.ArchSymbols = None
return i386Ops()
return None
def arch_symbols() -> pwndbg.aglib.kernel.symbol.ArchSymbols:
global _arch_symbols
if _arch_symbols is None:
@pwndbg.lib.cache.cache_until("start")
def arch_symbols() -> pwndbg.aglib.kernel.symbol.ArchSymbols | None:
if pwndbg.aglib.arch.name == "aarch64":
_arch_symbols = pwndbg.aglib.kernel.symbol.Aarch64Symbols()
return pwndbg.aglib.kernel.symbol.Aarch64Symbols()
elif pwndbg.aglib.arch.name == "x86-64":
_arch_symbols = pwndbg.aglib.kernel.symbol.x86_64Symbols()
return _arch_symbols
return pwndbg.aglib.kernel.symbol.x86_64Symbols()
return None
def ptr_size() -> int:

@ -32,8 +32,7 @@ class KernelVmmap:
self.pages = pages
self.sections = None
self.pi = pwndbg.aglib.kernel.arch_paginginfo()
if self.pi and not pwndbg.aglib.kernel.has_debug_symbols():
return
if self.pi and pwndbg.aglib.kernel.has_debug_symbols():
self.sections = self.pi.markers()
def get_name(self, addr: int) -> str:
@ -44,12 +43,12 @@ class KernelVmmap:
_, next = self.sections[i + 1]
if cur is None or next is None:
continue
if addr >= cur and addr < next:
if cur <= addr < next:
return name
return None
def adjust(self):
if self.pages is None or len(self.pages) == 0:
if self.pi is None or self.pages is None or len(self.pages) == 0:
return
for i, page in enumerate(self.pages):
name = self.get_name(page.start)
@ -248,6 +247,84 @@ def kernel_vmmap_via_page_tables() -> Tuple[pwndbg.lib.memory.Page, ...]:
monitor_info_mem_not_warned = True
def _parser_mem_info_line_x86(line: str) -> pwndbg.lib.memory.Page | None:
"""
Example response from `info mem`:
```
ffff903580000000-ffff903580099000 0000000000099000 -rw
ffff903580099000-ffff90358009b000 0000000000002000 -r-
ffff90358009b000-ffff903582200000 0000000002165000 -rw
ffff903582200000-ffff903582803000 0000000000603000 -r-
```
"""
dash_idx = line.index("-")
space_idx = line.index(" ")
rspace_idx = line.rindex(" ")
start = int(line[:dash_idx], 16)
end = int(line[dash_idx + 1 : space_idx], 16)
size = int(line[space_idx + 1 : rspace_idx], 16)
perm = line[rspace_idx + 1 :]
flags = 0
if "r" in perm:
flags |= 4
if "w" in perm:
flags |= 2
if "x" in perm:
flags |= 1
global monitor_info_mem_not_warned
if end - start != size and monitor_info_mem_not_warned:
print(
M.warn(
(
"The vmmap output may be incorrect as `monitor info mem` output assertion/assumption\n"
"that end-start==size failed. The values are:\n"
"end=%#x; start=%#x; size=%#x; end-start=%#x\n"
"Note that this warning will not show up again in this Pwndbg/GDB session."
)
% (end, start, size, end - start)
)
)
monitor_info_mem_not_warned = False
return pwndbg.lib.memory.Page(start, size, flags, 0, "<qemu>")
def _parser_mem_info_line_riscv64(line: str) -> pwndbg.lib.memory.Page | None:
"""
Example response from `info mem`:
```
vaddr paddr size attr
---------------- ---------------- ---------------- -------
0000000000010000 00000000feece000 0000000000001000 r-xu-a-
0000000000011000 00000000fefeb000 0000000000002000 r-xu-a-
0000000000013000 00000000a0a7a000 0000000000002000 r-xu-a-
0000000000015000 00000000bfe02000 0000000000002000 r-xu-a-
```
"""
arr = line.split(" ", 3)
if len(arr) != 4:
raise ValueError("invalid line format")
start, _, size, perm = arr
start = int(start, 16)
size = int(size, 16)
flags = 0
if "r" in perm:
flags |= 4
if "w" in perm:
flags |= 2
if "x" in perm:
flags |= 1
return pwndbg.lib.memory.Page(start, size, flags, 0, "<qemu>")
@pwndbg.lib.cache.cache_until("stop")
def kernel_vmmap_via_monitor_info_mem() -> Tuple[pwndbg.lib.memory.Page, ...]:
"""
@ -260,13 +337,6 @@ def kernel_vmmap_via_monitor_info_mem() -> Tuple[pwndbg.lib.memory.Page, ...]:
See also: https://github.com/pwndbg/pwndbg/pull/685
(TODO: revisit with future QEMU versions)
# Example output from the command:
# pwndbg> monitor info mem
# ffff903580000000-ffff903580099000 0000000000099000 -rw
# ffff903580099000-ffff90358009b000 0000000000002000 -r-
# ffff90358009b000-ffff903582200000 0000000002165000 -rw
# ffff903582200000-ffff903582803000 0000000000603000 -r-
"""
if not pwndbg.aglib.qemu.is_qemu_kernel():
return ()
@ -275,16 +345,18 @@ def kernel_vmmap_via_monitor_info_mem() -> Tuple[pwndbg.lib.memory.Page, ...]:
monitor_info_mem = pwndbg.dbg.selected_inferior().send_monitor("info mem")
except pwndbg.dbg_mod.Error:
# Exception should not happen in new qemu, can we clean up it?
monitor_info_mem = None
is_error = monitor_info_mem is None or "unknown command" in monitor_info_mem
if is_error:
# Older versions of QEMU/GDB may throw `gdb.error: "monitor" command
# not supported by this target`. Newer versions will not throw, but will
# return a string starting with 'unknown command:'. We handle both of
# these cases in a `finally` block instead of an `except` block.
# TODO: Find out which other architectures don't support this command
if pwndbg.aglib.arch.name == "aarch64":
# return a string starting with 'unknown command:'.
monitor_info_mem = "unknown command"
parser_func = None
if pwndbg.aglib.arch.name in ("i386", "x86-64"):
parser_func = _parser_mem_info_line_x86
elif pwndbg.aglib.arch.name == "rv64":
parser_func = _parser_mem_info_line_riscv64
if parser_func is None or "unknown command" in monitor_info_mem:
print(
M.error(
f"The {pwndbg.aglib.arch.name} architecture does"
@ -294,50 +366,14 @@ def kernel_vmmap_via_monitor_info_mem() -> Tuple[pwndbg.lib.memory.Page, ...]:
)
return ()
lines = monitor_info_mem.splitlines()
# Handle disabled PG
# This will prevent a crash on abstract architectures
if len(lines) == 1 and lines[0] == "PG disabled":
return ()
global monitor_info_mem_not_warned
pages: List[pwndbg.lib.memory.Page] = []
for line in lines:
for line in monitor_info_mem.splitlines():
try:
dash_idx = line.index("-")
space_idx = line.index(" ")
rspace_idx = line.rindex(" ")
start = int(line[:dash_idx], 16)
end = int(line[dash_idx + 1 : space_idx], 16)
size = int(line[space_idx + 1 : rspace_idx], 16)
page = parser_func(line)
except Exception:
# invalid format
continue
if end - start != size and monitor_info_mem_not_warned:
print(
M.warn(
(
"The vmmap output may be incorrect as `monitor info mem` output assertion/assumption\n"
"that end-start==size failed. The values are:\n"
"end=%#x; start=%#x; size=%#x; end-start=%#x\n"
"Note that this warning will not show up again in this Pwndbg/GDB session."
)
% (end, start, size, end - start)
)
)
monitor_info_mem_not_warned = False
perm = line[rspace_idx + 1 :]
flags = 0
if "r" in perm:
flags |= 4
if "w" in perm:
flags |= 2
if "x" in perm:
flags |= 1
pages.append(pwndbg.lib.memory.Page(start, size, flags, 0, "<qemu>"))
pages.append(page)
return tuple(pages)

Loading…
Cancel
Save