Slightly improving `buddydump` + deprecating `pcplist` (#3015)

* fixed buddydump behaviours and made test more comprehensive

* handling new name

* changing to tuple instead

* added comment to test
pull/3029/head
jxuanli 7 months ago committed by GitHub
parent 09c8ac6bc6
commit ed8c187691
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -122,7 +122,7 @@ def check_find(counter: int, physmap_addr: int, pba: ParsedBuddyArgs, cbp: Curre
if pba.find is None: if pba.find is None:
return False return False
start = physmap_addr start = physmap_addr
end = physmap_addr + (1 << cbp.order) end = physmap_addr + 0x1000 * (1 << cbp.order)
return pba.find >= start and pba.find < end return pba.find >= start and pba.find < end
@ -343,5 +343,5 @@ def buddydump(
print_pcp_set(pba, cbp) print_pcp_set(pba, cbp)
if not pcp_only: if not pcp_only:
print_free_area(pba, cbp) print_free_area(pba, cbp)
if not cbp.found: if not cbp.found:
log.warning("No free pages with specified filters found.") log.warning("No free pages with specified filters found.")

@ -1431,6 +1431,11 @@ class GDB(pwndbg.dbg_mod.Debugger):
f"alias -a {deprecated_cmd} = echo Use `{fixed_cmd}` instead (Pwndbg changed `_` to `-` in command names)\\n" f"alias -a {deprecated_cmd} = echo Use `{fixed_cmd}` instead (Pwndbg changed `_` to `-` in command names)\\n"
) )
for deprecated_cmd, new_cmd in (("pcplist", "buddydump"),):
gdb.execute(
f"alias -a {deprecated_cmd} = echo deprecation warning for old name, use `{new_cmd}` instead\\n"
)
# This may throw an exception, see pwndbg/pwndbg#27 # This may throw an exception, see pwndbg/pwndbg#27
try: try:
gdb.execute("set disassembly-flavor intel") gdb.execute("set disassembly-flavor intel")

@ -1,5 +1,8 @@
from __future__ import annotations from __future__ import annotations
import random
import re
import gdb import gdb
import pytest import pytest
@ -90,8 +93,6 @@ def test_x64_extra_registers_under_kernel_mode():
def get_slab_object_address(): def get_slab_object_address():
"""helper function to get the address of some kmalloc slab object """helper function to get the address of some kmalloc slab object
and the associated slab cache name""" and the associated slab cache name"""
import re
caches = pwndbg.aglib.kernel.slab.caches() caches = pwndbg.aglib.kernel.slab.caches()
for cache in caches: for cache in caches:
cache_name = cache.name cache_name = cache.name
@ -135,6 +136,42 @@ def test_command_msr_write():
) )
def test_command_buddydump(): def test_command_buddydump():
res = gdb.execute("buddydump", to_string=True) res = gdb.execute("buddydump", to_string=True)
assert ( NOFREEPAGE = "No free pages with specified filters found.\n"
"Order" in res and "Zone" in res and ("per_cpu_pageset" in res or "free_area" in res) if res == "WARNING: Symbol 'node_data' not found\n" or NOFREEPAGE == res:
) or res == "WARNING: Symbol 'node_data' not found\n" return
# this indicates the buddy allocator contains at least one entry
assert "Order" in res and "Zone" in res and ("per_cpu_pageset" in res or "free_area" in res)
ansi_escape = re.compile(r"\x1b\[[0-9;]*m")
res = ansi_escape.sub("", res)
# find the starting addresses of all entries within the freelists
matches = re.findall(r"\[0x[0-9a-fA-F\-]{2}\] (0x[0-9a-fA-F]{16})", res)
for i in range(0, len(matches), 20):
# check every 20 elements so tests do not take too long
match = int(matches[i], 16)
res = gdb.execute(f"bud -f {hex(match + random.randint(0, 0x1000 - 1))}", to_string=True)
res = ansi_escape.sub("", res)
_matches = re.findall(r"\[0x[0-9a-fA-F\-]{2}\] (0x[0-9a-fA-F]{16})", res)
# asserting `bud -f` behaviour -- should be able to find the corresponding entry to an address
# even if the address is not aligned
assert len(_matches) == 1 and int(_matches[0], 16) == match
# nonexistent node index should not contain any entries
no_output = gdb.execute("buddydump -n 10", to_string=True)
assert NOFREEPAGE == no_output
# below checks are for filters
# for example, if a zone name is specified, other zones should not be present
filter_res = gdb.execute("bud -z DMA", to_string=True)
for name in ["DMA32", "Normal", "HighMem", "Movable", "Device"]:
assert f"Zone {name}" not in filter_res
filter_res = gdb.execute("bud -m Unmovable", to_string=True)
for name in ["Movable", "Reclaimable", "HighAtomic", "CMA", "Isolate"]:
assert f"- {name}" not in filter_res
filter_res = gdb.execute("bud -o 1", to_string=True)
for i in range(11):
if i == 1:
continue
assert f"Order {i}" not in filter_res
filter_res = gdb.execute("bud -p", to_string=True)
assert "free_area" not in filter_res

Loading…
Cancel
Save