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

@ -217,11 +217,11 @@ def test_command_buddydump():
if res == "WARNING: Symbol 'node_data' not found\n" or NOFREEPAGE == res: if res == "WARNING: Symbol 'node_data' not found\n" or NOFREEPAGE == res:
return return
# this indicates the buddy allocator contains at least one entry # 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 # find the starting addresses of all entries within the freelists
matches = get_buddy_freelist_elements(res) 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] vaddr, page = matches[i]
res = gdb.execute(f"bud -f {hex(vaddr + random.randint(0, 0x1000 - 1))}", to_string=True) res = gdb.execute(f"bud -f {hex(vaddr + random.randint(0, 0x1000 - 1))}", to_string=True)
_matches = get_buddy_freelist_elements(res) _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 # for example, if a zone name is specified, other zones should not be present
filter_res = gdb.execute("bud -z DMA", to_string=True) filter_res = gdb.execute("bud -z DMA", to_string=True)
for name in ["DMA32", "Normal", "HighMem", "Movable", "Device"]: 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) filter_res = gdb.execute("bud -m Unmovable", to_string=True)
for name in ["Movable", "Reclaimable", "HighAtomic", "CMA", "Isolate"]: 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) filter_res = gdb.execute("bud -o 1", to_string=True)
for i in range(11): for i in range(11):
if i == 1: if i == 1:
continue 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) filter_res = gdb.execute("bud -p", to_string=True)
assert "free_area" not in filter_res assert "free_area" not in filter_res

Loading…
Cancel
Save