avoid default values for the options of `buddydump` (#3313)

* avoiding using default values for the options of `buddydump`

* updated doc

* updated test
pull/3314/head
jxuanli 2 months ago committed by GitHub
parent ee10c5aea8
commit 2ea5e383bf
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -18,7 +18,7 @@ Displays metadata and freelists of the buddy allocator.
|-m|--mtype|Displays/searches lists only with the specified mtype.|
|-p|--pcp-only|Displays/searches only PCP lists.|
|-c|--cpu|CPU nr for searching PCP.|
|-n|--node| (default: 0)|
|-n|--node||
|-f|--find|The address to find in page free lists.|
<!-- END OF AUTOGENERATED PART. Do not modify this line or the line below, they mark the end of the auto-generated part of the file. If you want to extend the documentation in a way which cannot easily be done by adding to the command help description, write below the following line. -->

@ -44,6 +44,7 @@ class CurrentBuddyParams:
# this is so that values can be cleanly passed around
sections: List[Tuple[str, str]]
indent: IndentContextManager
node: int | None
zone: pwndbg.dbg_mod.Value | None
order: int
mtype: str | None
@ -101,7 +102,7 @@ parser.add_argument(
parser.add_argument(
"-c", "--cpu", type=cpu_limitcheck, dest="cpu", default=None, help="CPU nr for searching PCP."
)
parser.add_argument("-n", "--node", type=int, dest="node", default=0, help="")
parser.add_argument("-n", "--node", type=int, dest="node", default=None, help="")
parser.add_argument(
"-f",
"--find",
@ -212,7 +213,7 @@ def print_mtypes(pba: ParsedBuddyArgs, cbp: CurrentBuddyParams):
if nr_types is None:
nr_types = len(mtypes)
for i in range(nr_types):
cbp.mtype = mtypes[i]
cbp.mtype = mtypes[i].lower()
if pba.mtype is not None and cbp.mtype != pba.mtype:
continue
cbp.freelist = freelists[i]
@ -228,7 +229,7 @@ def print_pcp_set(pba: ParsedBuddyArgs, cbp: CurrentBuddyParams):
elif cbp.zone.type.has_field("pageset"):
pcp = per_cpu(cbp.zone["pageset"], pba.cpu)
pcp_lists = pcp["pcp"]["lists"]
cbp.sections[1] = ("per_cpu_pageset", None)
cbp.sections[1] = (f"[cpu #{pba.cpu}] per_cpu_pageset", None)
if pcp is None or pcp_lists is None:
log.warning("cannot find pcplist")
return
@ -245,7 +246,7 @@ def print_pcp_set(pba: ParsedBuddyArgs, cbp: CurrentBuddyParams):
order = 21 - 12 # HPAGE_SHIFT - PAGE_SHIFT
cbp.nr_types = nr_pcp_lists % MIGRATE_PCPTYPES
cbp.sections[2] = (
f"Order {order}",
f"order {order}",
f"size: {cbp.indent.aux_hex(0x1000 * (1 << order))}",
)
cbp.order = order
@ -261,7 +262,7 @@ def print_free_area(pba: ParsedBuddyArgs, cbp: CurrentBuddyParams):
cbp.freelists = free_area[order]["free_list"]
nr_free = int(free_area[order]["nr_free"])
cbp.sections[2] = (
f"Order {order}",
f"order {order}",
f"nr_free: {cbp.indent.aux_hex(nr_free)}, size: {cbp.indent.aux_hex(0x1000 * (1 << order))}",
)
cbp.order = order
@ -269,13 +270,18 @@ def print_free_area(pba: ParsedBuddyArgs, cbp: CurrentBuddyParams):
def print_zones(pba: ParsedBuddyArgs, cbp: CurrentBuddyParams, zones, pcp_only):
target_cpu = pba.cpu
for i in range(pwndbg.aglib.kernel.symbol.nzones()):
cbp.zone = zones[i]
name = zones[i]["name"].string()
if pba.zone is not None and pba.zone != name:
continue
cbp.sections[0] = (f"Zone {name}", None)
print_pcp_set(pba, cbp)
cbp.sections[0] = (f"[node #{cbp.node}] zone {name}", None)
for cpu in range(pwndbg.aglib.kernel.nproc()):
if target_cpu is not None and target_cpu != cpu:
continue
pba.cpu = cpu
print_pcp_set(pba, cbp)
if not pcp_only:
print_free_area(pba, cbp)
@ -338,9 +344,9 @@ def buddydump(
if not pwndbg.aglib.kernel.has_debug_info():
pwndbg.aglib.kernel.buddydump.load_buddydump_typeinfo()
node_data = pwndbg.aglib.memory.get_typed_pointer("node_data_t", node_data)
pba = ParsedBuddyArgs(zone, order, mtype, cpu, find)
pba = ParsedBuddyArgs(zone, order, mtype.lower() if mtype is not None else None, cpu, find)
cbp = CurrentBuddyParams(
[NONE_TUPLE] * 3, IndentContextManager(), None, None, None, None, None, None, False
[NONE_TUPLE] * 3, IndentContextManager(), None, None, None, None, None, None, None, False
)
for node_idx in range(kernel.num_numa_nodes()):
if node is not None and node_idx != node:
@ -351,6 +357,7 @@ def buddydump(
zones = node_data.dereference()[node_idx]["node_zones"]
else:
zones = node_data["node_zones"]
cbp.node = node_idx
print_zones(pba, cbp, zones, pcp_only)
if not cbp.found:
log.warning("No free pages with specified filters found.")

@ -217,11 +217,11 @@ def test_command_buddydump():
if res == "WARNING: Symbol 'node_data' not found\n" or NOFREEPAGE == res:
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)
assert "order" in res and "zone" in res and ("per_cpu_pageset" in res or "free_area" in res)
# find the starting addresses of all entries within the freelists
matches = get_buddy_freelist_elements(res)
for i in range(0, len(matches), 10):
for i in range(0, len(matches)):
vaddr, page = matches[i]
res = gdb.execute(f"bud -f {hex(vaddr + random.randint(0, 0x1000 - 1))}", to_string=True)
_matches = get_buddy_freelist_elements(res)
@ -238,15 +238,21 @@ def test_command_buddydump():
# 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
assert f"zone {name.lower()}" 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
assert f"- {name.lower()}" 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
assert f"order {i}" not in filter_res
filter_res = gdb.execute("bud -c 0", to_string=True)
for i in range(1, pwndbg.aglib.kernel.nproc()):
assert f"cpu #{i}" not in filter_res
filter_res = gdb.execute("bud -n 0", to_string=True)
for i in range(1, pwndbg.aglib.kernel.num_numa_nodes()):
assert f"node #{i}" not in filter_res
filter_res = gdb.execute("bud -p", to_string=True)
assert "free_area" not in filter_res

Loading…
Cancel
Save