From da41ee64088f09a998a4281fe1bc0183f2fb3e9c Mon Sep 17 00:00:00 2001 From: patryk4815 Date: Sun, 24 Aug 2025 16:14:03 +0200 Subject: [PATCH] Dump apple commpage (#3263) * init * fixy * commpage * fix * fix gen docs * add docs * add comments * fix pretty_bytes * `get_commpage_mappings` add checking if address is readable --- .../darwin_libsystem_mach-o/commpage.md | 18 ++ docs/commands/index.md | 4 + pwndbg/aglib/commpage.py | 247 ++++++++++++++++++ pwndbg/commands/__init__.py | 2 + pwndbg/commands/commpage.py | 55 ++++ pwndbg/dbg/lldb/__init__.py | 5 + scripts/_docs/command_docs_common.py | 2 +- 7 files changed, 332 insertions(+), 1 deletion(-) create mode 100644 docs/commands/darwin_libsystem_mach-o/commpage.md create mode 100644 pwndbg/aglib/commpage.py create mode 100644 pwndbg/commands/commpage.py diff --git a/docs/commands/darwin_libsystem_mach-o/commpage.md b/docs/commands/darwin_libsystem_mach-o/commpage.md new file mode 100644 index 000000000..f83eb103c --- /dev/null +++ b/docs/commands/darwin_libsystem_mach-o/commpage.md @@ -0,0 +1,18 @@ + +# commpage + +```text +usage: commpage [-h] [-v] + +``` + +Dumps all values from the macOS commpage. +### Optional arguments + +|Short|Long|Help| +| :--- | :--- | :--- | +|-h|--help|show this help message and exit| +|-v|--verbose|Print detailed information.| + + + diff --git a/docs/commands/index.md b/docs/commands/index.md index e16843b76..7242858a0 100644 --- a/docs/commands/index.md +++ b/docs/commands/index.md @@ -23,6 +23,10 @@ - [contextwatch](context/contextwatch.md) - Adds an expression to be shown on context. - [regs](context/regs.md) - Print out all registers and enhance the information. +## Darwin/libsystem/Mach-O + +- [commpage](darwin_libsystem_mach-o/commpage.md) - Dumps all values from the macOS commpage. + ## Developer - [dev-dump-instruction](developer/dev-dump-instruction.md) - Dump internal PwndbgInstruction attributes. diff --git a/pwndbg/aglib/commpage.py b/pwndbg/aglib/commpage.py new file mode 100644 index 000000000..41403016c --- /dev/null +++ b/pwndbg/aglib/commpage.py @@ -0,0 +1,247 @@ +from __future__ import annotations + +import os +import struct +from typing import Any +from typing import NamedTuple +from typing import Tuple + +import pwndbg +import pwndbg.aglib.memory +import pwndbg.commands +import pwndbg.lib.cache +import pwndbg.lib.memory +from pwndbg.lib.arch import Platform + +rw_flags = os.R_OK | os.W_OK +ro_flags = os.R_OK + +# docs: https://github.com/pwndbg/pwndbg/issues/3261 +_comm_start_page_rw = { + "i386": 0xFFFF0000, + "x86-64": 0x00007FFFFFE00000, + "arm": 0xFFFF4000, + "aarch64": 0x0000000FFFFFC000, +} + +_comm_start_page_ro = { + "arm": 0xFFFFC000, + "aarch64": 0x0000000FFFFF4000, +} + +_comm_max_size = 0xFFF + + +class CommPageField(NamedTuple): + flags: int + ctype: str + name: str + offset: int + desc: str + fmt: str + + def is_undocumented(self): + return "UNDOCUMENTED" in self.name + + def is_unused(self): + return "UNUSED" in self.name + + def is_readonly(self): + return self.flags == ro_flags + + def real_addr(self) -> int: + if self.is_readonly(): + page_start = _comm_start_page_ro[pwndbg.aglib.arch.name] + else: + page_start = _comm_start_page_rw[pwndbg.aglib.arch.name] + return page_start + self.offset + + def real_size(self) -> int: + return struct.calcsize(self.fmt) + + def unpack(self) -> Any: + addr = self.real_addr() + size = self.real_size() + try: + data = pwndbg.aglib.memory.read(addr, size) + val = struct.unpack(self.fmt, data)[0] + except pwndbg.dbg_mod.Error as e: + val = f" ({e})" + return val + + +# fmt: off +# docs: https://github.com/pwndbg/pwndbg/issues/3261 +# docs: https://github.com/apple-oss-distributions/xnu/blob/e3723e1f17661b24996789d8afc084c0c3303b26/osfmk/arm/cpu_capabilities.h#L279-L384 +_fields_arm = ( + CommPageField(rw_flags, "?", "COMM_PAGE_SIGNATURE", 0x000, "First few bytes contain a signature", "16s"), + CommPageField(rw_flags, "uint64", "COMM_PAGE_CPU_CAPABILITIES64", 0x010, "CPU capabilities (64-bit)", "Q"), + CommPageField(rw_flags, "?", "COMM_PAGE_UNUSED", 0x018, "Unused bytes", "6s"), + CommPageField(rw_flags, "uint16", "COMM_PAGE_VERSION", 0x01E, "16-bit version number", "H"), + CommPageField(rw_flags, "uint16", "COMM_PAGE_CPU_CAPABILITIES", 0x020, "CPU capabilities (32-bit)", "H"), + CommPageField(rw_flags, "uint8", "COMM_PAGE_NCPUS", 0x022, "Number of configured CPUs", "B"), + CommPageField(rw_flags, "uint8", "COMM_PAGE_USER_PAGE_SHIFT_32_LEGACY", 0x024, "VM page shift for 32-bit processes (legacy)", "B"), + CommPageField(ro_flags, "uint8", "COMM_PAGE_USER_PAGE_SHIFT_32", 0x024, "VM page shift for 32-bit processes", "B"), + CommPageField(rw_flags, "uint8", "COMM_PAGE_USER_PAGE_SHIFT_64_LEGACY", 0x025, "VM page shift for 64-bit processes (legacy)", "B"), + CommPageField(ro_flags, "uint8", "COMM_PAGE_USER_PAGE_SHIFT_64", 0x025, "VM page shift for 64-bit processes", "B"), + CommPageField(rw_flags, "uint16", "COMM_PAGE_CACHE_LINESIZE", 0x026, "Cache line size", "H"), + CommPageField(rw_flags, "uint32", "COMM_PAGE_UNUSED4", 0x028, "Unused (was scheduler generation number)", "I"), + CommPageField(rw_flags, "uint32", "COMM_PAGE_UNUSED3", 0x02C, "Unused (was max spin count for mutexes)", "I"), + CommPageField(rw_flags, "uint8", "COMM_PAGE_CPU_CLUSTERS", 0x02F, "Number of CPU clusters", "B"), + CommPageField(rw_flags, "uint32", "COMM_PAGE_MEMORY_PRESSURE", 0x030, "Copy of VM memory pressure", "I"), + CommPageField(rw_flags, "uint8", "COMM_PAGE_ACTIVE_CPUS", 0x034, "Number of active CPUs", "B"), + CommPageField(rw_flags, "uint8", "COMM_PAGE_PHYSICAL_CPUS", 0x035, "Number of physical CPUs", "B"), + CommPageField(rw_flags, "uint8", "COMM_PAGE_LOGICAL_CPUS", 0x036, "Number of logical CPUs", "B"), + CommPageField(rw_flags, "uint8", "COMM_PAGE_KERNEL_PAGE_SHIFT_LEGACY", 0x037, "Kernel VM page shift (legacy)", "B"), + CommPageField(ro_flags, "uint8", "COMM_PAGE_KERNEL_PAGE_SHIFT", 0x037, "Kernel VM page shift", "B"), + CommPageField(rw_flags, "uint64", "COMM_PAGE_MEMORY_SIZE", 0x038, "Maximum memory size", "Q"), + CommPageField(rw_flags, "struct commpage_timeofday_data_t", "COMM_PAGE_TIMEOFDAY_DATA", 0x040, "Time-of-day data, gettimeofday() (legacy, 40 bytes)", "40s"), + CommPageField(rw_flags, "uint32", "COMM_PAGE_CPUFAMILY", 0x080, "CPU family used by memcpy() resolver", "I"), + CommPageField(rw_flags, "uint32", "COMM_PAGE_DEV_FIRM_LEGACY", 0x084, "handle on PE_i_can_has_debugger (legacy)", "I"), + CommPageField(ro_flags, "uint32", "COMM_PAGE_DEV_FIRM", 0x084, "handle on PE_i_can_has_debugger", "I"), + CommPageField(rw_flags, "uint64", "COMM_PAGE_TIMEBASE_OFFSET", 0x088, "Timebase offset for mach_absolute_time()", "Q"), + CommPageField(rw_flags, "uint8", "COMM_PAGE_USER_TIMEBASE", 0x090, "Is userspace mach_absolute_time supported", "B"), + CommPageField(rw_flags, "uint8", "COMM_PAGE_CONT_HWCLOCK", 0x091, "Always-on hardware clock presence for mach_continuous_time()", "B"), + CommPageField(rw_flags, "uint8", "COMM_PAGE_DTRACE_DOF_ENABLED", 0x092, "DTrace DOF enable flag", "B"), + CommPageField(rw_flags, "?", "COMM_PAGE_UNUSED0", 0x093, "Unused bytes", "5s"), + CommPageField(rw_flags, "uint64", "COMM_PAGE_CONT_TIMEBASE", 0x098, "Base for mach_continuous_time() relative to mach_absolute_time()", "Q"), + CommPageField(rw_flags, "uint64", "COMM_PAGE_BOOTTIME_USEC", 0x0A0, "boottime in microseconds", "Q"), + CommPageField(rw_flags, "uint64", "COMM_PAGE_CONT_HW_TIMEBASE", 0x0A8, "Base for mach_continuous_time() relative to hardware counter", "Q"), + CommPageField(rw_flags, "uint64", "COMM_PAGE_APPROX_TIME", 0x0C0, "Last known mach_absolute_time()", "Q"), + CommPageField(rw_flags, "uint8", "COMM_PAGE_APPROX_TIME_SUPPORTED", 0x0C8, "Is mach_approximate_time supported", "B"), + CommPageField(rw_flags, "?", "COMM_PAGE_UNUSED1", 0x0D9, "Unused (padding to align cacheline)", "39s"), + CommPageField(rw_flags, "uint32", "COMM_PAGE_KDEBUG_ENABLE", 0x100, "Kdebug status bits exported to userspace", "I"), + CommPageField(rw_flags, "uint32", "COMM_PAGE_ATM_DIAGNOSTIC_CONFIG", 0x104, "atm_diagnostic_config exported to userspace", "I"), + CommPageField(rw_flags, "uint32", "COMM_PAGE_MULTIUSER_CONFIG", 0x108, "multiuser_config exported to userspace", "I"), + CommPageField(rw_flags, "uint8", "COMM_PAGE_JIT_WRITE_PROTECT", 0x10c, "Is jit_write_protect_supported_np", "B"), + CommPageField(rw_flags, "struct new_commpage_timeofday_data_t", "COMM_PAGE_NEWTIMEOFDAY_DATA", 0x120, "gettimeofday(), struct new_commpage_timeofday_data_t (40 bytes)", "40s"), + CommPageField(rw_flags, "struct bt_params", "COMM_PAGE_REMOTETIME_PARAMS", 0x148, "mach_bridge_remote_time(), struct bt_params (24 bytes)", "24s"), + CommPageField(rw_flags, "uint64", "COMM_PAGE_DYLD_FLAGS", 0x160, "Dyld system flags kern.dyld_system_flags exported to userspace", "Q"), + CommPageField(rw_flags, "uint64", "COMM_PAGE_CPU_QUIESCENT_COUNTER", 0x180, "CPU quiescent counter", "Q"), + CommPageField(rw_flags, "?", "COMM_PAGE_CUSTOM2", 0x188, "Unused CPU quiescent counter (120 bytes reserved)", "120s"), + CommPageField(rw_flags, "?", "COMM_PAGE_CPU_TO_CLUSTER", 0x200, "CPU ID to cluster ID mappings (256 bytes reserved)", "256s"), + CommPageField(rw_flags, "uint64", "COMM_PAGE_ASB_TARGET_VALUE", 0x320, "Random target value for security bounty", "Q"), + CommPageField(rw_flags, "uint64", "COMM_PAGE_ASB_TARGET_ADDRESS", 0x328, "Random target address for security bounty", "Q"), + CommPageField(rw_flags, "uint64", "COMM_PAGE_ASB_TARGET_KERN_VALUE", 0x330, "Random kernel value for security bounty", "Q"), + CommPageField(rw_flags, "uint64", "COMM_PAGE_ASB_TARGET_KERN_ADDRESS", 0x338, "Random kernel target address for security bounty", "Q"), + CommPageField(rw_flags, "uint8", "COMM_PAGE_APT_MSG_POLICY", 0x340, "APT message policy APT_MSG", "B"), + CommPageField(rw_flags, "uint8", "COMM_PAGE_APT_ACTIVE", 0x341, "APT active status (infrequently mutated)", "B"), +) + +# docs: https://github.com/pwndbg/pwndbg/issues/3261 +# docs: https://github.com/apple-oss-distributions/xnu/blob/e3723e1f17661b24996789d8afc084c0c3303b26/osfmk/i386/cpu_capabilities.h#L185-L248 +_fields_x86 = ( + CommPageField(rw_flags, "?", "COMM_PAGE_SIGNATURE", 0x000, "First 16 bytes contain a signature", "16s"), + CommPageField(rw_flags, "uint64", "COMM_PAGE_CPU_CAPABILITIES64", 0x010, "CPU capabilities (64-bit)", "Q"), + CommPageField(rw_flags, "?", "COMM_PAGE_UNUSED", 0x018, "Unused bytes", "6s"), + CommPageField(rw_flags, "uint16", "COMM_PAGE_VERSION", 0x01E, "16-bit version number", "H"), + CommPageField(rw_flags, "uint16", "COMM_PAGE_CPU_CAPABILITIES", 0x020, "CPU capabilities (32-bit, retained for compatibility)", "H"), + CommPageField(rw_flags, "uint8", "COMM_PAGE_NCPUS", 0x022, "Number of configured CPUs (hw.logicalcpu at boot time)", "B"), + CommPageField(rw_flags, "uint64", "COMM_PAGE_UNUSED0", 0x024, "Unused bytes (previously reserved for cpu_capabilities expansion)", "2s"), + CommPageField(rw_flags, "uint16", "COMM_PAGE_CACHE_LINESIZE", 0x026, "Cache line size", "H"), + CommPageField(rw_flags, "uint32", "COMM_PAGE_UNUSED4", 0x028, "Unused (was scheduler generation number)", "I"), + CommPageField(rw_flags, "uint32", "COMM_PAGE_MEMORY_PRESSURE", 0x02C, "Copy of VM memory pressure", "I"), + CommPageField(rw_flags, "uint32", "COMM_PAGE_UNUSED3", 0x030, "Unused (was max spin count for mutexes)", "I"), + CommPageField(rw_flags, "uint8", "COMM_PAGE_ACTIVE_CPUS", 0x034, "Number of active CPUs", "B"), + CommPageField(rw_flags, "uint8", "COMM_PAGE_PHYSICAL_CPUS", 0x035, "Number of physical CPUs", "B"), + CommPageField(rw_flags, "uint8", "COMM_PAGE_LOGICAL_CPUS", 0x036, "Number of logical CPUs", "B"), + CommPageField(rw_flags, "uint8", "COMM_PAGE_CPU_CLUSTERS", 0x037, "Number of CPU clusters", "B"), + CommPageField(rw_flags, "uint64", "COMM_PAGE_MEMORY_SIZE", 0x038, "Maximum memory size", "Q"), + CommPageField(rw_flags, "uint32", "COMM_PAGE_CPUFAMILY", 0x040, "CPU family (hw.cpufamily, x86)", "I"), + CommPageField(rw_flags, "uint32", "COMM_PAGE_KDEBUG_ENABLE", 0x044, "Kdebug enable exported to userspace", "I"), + CommPageField(rw_flags, "uint32", "COMM_PAGE_ATM_DIAGNOSTIC_CONFIG", 0x048, "ATM diagnostic configuration exported to userspace", "I"), + CommPageField(rw_flags, "uint8", "COMM_PAGE_DTRACE_DOF_ENABLED", 0x04C, "DTrace DOF enable flag", "B"), + CommPageField(rw_flags, "uint8", "COMM_PAGE_KERNEL_PAGE_SHIFT", 0x04D, "Kernel VM page shift (version >=14)", "B"), + CommPageField(rw_flags, "uint8", "COMM_PAGE_USER_PAGE_SHIFT_64", 0x04E, "User VM page shift (version >=14)", "B"), + CommPageField(rw_flags, "uint8", "COMM_PAGE_UNUSED2", 0x04F, "Unused", "B"), + CommPageField(rw_flags, "uint64", "COMM_PAGE_TIME_DATA_START", 0x050, "Base for time-related offsets", "Q"), + CommPageField(rw_flags, "uint64", "COMM_PAGE_NT_TSC_BASE", 0x050, "Nanotime TSC base", "Q"), + CommPageField(rw_flags, "uint32", "COMM_PAGE_NT_SCALE", 0x058, "Nanotime scale", "I"), + CommPageField(rw_flags, "uint32", "COMM_PAGE_NT_SHIFT", 0x05C, "Nanotime shift", "I"), + CommPageField(rw_flags, "uint64", "COMM_PAGE_NT_NS_BASE", 0x060, "Nanotime nanosecond base", "Q"), + CommPageField(rw_flags, "uint32", "COMM_PAGE_NT_GENERATION", 0x068, "Nanotime generation counter", "I"), + CommPageField(rw_flags, "uint32", "COMM_PAGE_GTOD_GENERATION", 0x06C, "Gettimeofday generation counter", "I"), + CommPageField(rw_flags, "uint64", "COMM_PAGE_GTOD_NS_BASE", 0x070, "Gettimeofday nanosecond base", "Q"), + CommPageField(rw_flags, "uint64", "COMM_PAGE_GTOD_SEC_BASE", 0x078, "Gettimeofday second base", "Q"), + CommPageField(rw_flags, "uint64", "COMM_PAGE_APPROX_TIME", 0x080, "Used by mach_approximate_time()", "Q"), + CommPageField(rw_flags, "uint8", "COMM_PAGE_APPROX_TIME_SUPPORTED", 0x088, "Flag if mach_approximate_time() is supported", "B"), + CommPageField(rw_flags, "uint64", "COMM_PAGE_CONT_TIMEBASE", 0x0C0, "Base for mach_continuous_time()", "Q"), + CommPageField(rw_flags, "uint64", "COMM_PAGE_BOOTTIME_USEC", 0x0C8, "Boot time in microseconds", "Q"), + CommPageField(rw_flags, "struct new_commpage_timeofday_data_t", "COMM_PAGE_NEWTIMEOFDAY_DATA", 0x0D0, "New time-of-day data (40 bytes)", "40s"), + CommPageField(rw_flags, "uint64", "COMM_PAGE_DYLD_FLAGS", 0x100, "Dyld system flags exported to userspace", "Q"), + CommPageField(rw_flags, "?", "COMM_PAGE_CPU_TO_CLUSTER", 0x108, "CPU ID to cluster ID mappings (256 bytes reserved)", "256s"), + CommPageField(rw_flags, "uint64", "COMM_PAGE_ASB_TARGET_VALUE", 0x320, "Random target value for security bounty", "Q"), + CommPageField(rw_flags, "uint64", "COMM_PAGE_ASB_TARGET_ADDRESS", 0x328, "Random target address for security bounty", "Q"), + CommPageField(rw_flags, "uint64", "COMM_PAGE_ASB_TARGET_KERN_VALUE", 0x330, "Random kernel value for security bounty", "Q"), + CommPageField(rw_flags, "uint64", "COMM_PAGE_ASB_TARGET_KERN_ADDRESS", 0x338, "Random kernel target address for security bounty", "Q"), +) +# fmt: on + + +def _comm_fix_gaps(fields: Tuple[CommPageField, ...]) -> Tuple[CommPageField, ...]: + fixed_fields = [] + prev_endaddr = 0 + for comm in fields: + if comm.is_readonly(): + fixed_fields.append(comm) + continue + + curr_addr = comm.offset + if (gap_size := (curr_addr - prev_endaddr)) > 0: + gap_addr = prev_endaddr + fixed_fields.append( + CommPageField( + rw_flags, + f"? uint{gap_size * 8}", + "GAP UNDOCUMENTED", + gap_addr, + "", + f"{gap_size}s", + ) + ) + + fixed_fields.append(comm) + prev_endaddr = curr_addr + comm.real_size() + + if (gap_size := (_comm_max_size - prev_endaddr)) > 0: + gap_addr = prev_endaddr + fixed_fields.append( + CommPageField( + rw_flags, f"? uint{gap_size * 8}", "GAP UNDOCUMENTED", gap_addr, "", f"{gap_size}s" + ) + ) + + return tuple(fixed_fields) + + +_comm_fields = { + "i386": _comm_fix_gaps(_fields_x86), + "x86-64": _comm_fix_gaps(_fields_x86), + "arm": _comm_fix_gaps(_fields_arm), + "aarch64": _comm_fix_gaps(_fields_arm), +} + + +def get_commpage_fields() -> Tuple[CommPageField, ...]: + if pwndbg.aglib.arch.platform != Platform.DARWIN: + return () + return _comm_fields.get(pwndbg.aglib.arch.name, ()) + + +@pwndbg.lib.cache.cache_until("start") +def get_commpage_mappings() -> Tuple[pwndbg.lib.memory.Page, ...]: + if pwndbg.aglib.arch.platform != Platform.DARWIN: + return () + + start_rw = _comm_start_page_rw.get(pwndbg.aglib.arch.name, None) + if start_rw is None or not pwndbg.aglib.memory.peek(start_rw): + return () + + start_ro = _comm_start_page_ro.get(pwndbg.aglib.arch.name, None) + if start_ro is None or not pwndbg.aglib.memory.peek(start_ro): + return (pwndbg.lib.memory.Page(start_rw, _comm_max_size, rw_flags, 0, "[commpage]"),) + + return ( + pwndbg.lib.memory.Page(start_ro, _comm_max_size, ro_flags, 0, "[commpage]"), + pwndbg.lib.memory.Page(start_rw, _comm_max_size, rw_flags, 0, "[commpage]"), + ) diff --git a/pwndbg/commands/__init__.py b/pwndbg/commands/__init__.py index 7b125ac79..2f764f044 100644 --- a/pwndbg/commands/__init__.py +++ b/pwndbg/commands/__init__.py @@ -59,6 +59,7 @@ class CommandCategory(str, Enum): REGISTER = "Register" PROCESS = "Process" LINUX = "Linux/libc/ELF" + DARWIN = "Darwin/libsystem/Mach-O" DISASS = "Disassemble" MISC = "Misc" KERNEL = "Kernel" @@ -899,6 +900,7 @@ def load_commands() -> None: import pwndbg.commands.canary import pwndbg.commands.checksec import pwndbg.commands.comments + import pwndbg.commands.commpage import pwndbg.commands.config import pwndbg.commands.context import pwndbg.commands.cpsr diff --git a/pwndbg/commands/commpage.py b/pwndbg/commands/commpage.py new file mode 100644 index 000000000..4f2508d91 --- /dev/null +++ b/pwndbg/commands/commpage.py @@ -0,0 +1,55 @@ +from __future__ import annotations + +import argparse + +from rich.console import Console +from rich.table import Table + +import pwndbg +import pwndbg.aglib.commpage +import pwndbg.commands +from pwndbg.commands import CommandCategory + + +def pretty_bytes(data: bytes) -> str: + if not data: + return "b''" + + if len(set(data)) == 1 and len(data) > 1: + return f"b'\\x{data[0]:02x}' " + + return repr(data) + + +parser = argparse.ArgumentParser(description="Dumps all values from the macOS commpage.") +parser.add_argument("-v", "--verbose", action="store_true", help="Print detailed information.") + + +@pwndbg.commands.Command(parser, category=CommandCategory.DARWIN) +def commpage(verbose: bool = False): + table = Table() + + table.add_column("Name", style="cyan", no_wrap=True) + table.add_column("Address", style="magenta", no_wrap=True) + table.add_column("Type", style="magenta", no_wrap=True) + table.add_column("Value", style="green", overflow="fold") + if verbose: + table.add_column("Description", style="yellow", overflow="fold") + + for comm in pwndbg.aglib.commpage.get_commpage_fields(): + val = comm.unpack() + style = None + if comm.is_undocumented(): + style = "red" + if comm.is_unused(): + style = "yellow" + + if isinstance(val, bytes): + val = pretty_bytes(val) + + rows = [comm.name, hex(comm.real_addr()), comm.ctype, str(val)] + if verbose: + rows.append(comm.desc) + table.add_row(*rows, style=style) + + Console().print(table) diff --git a/pwndbg/dbg/lldb/__init__.py b/pwndbg/dbg/lldb/__init__.py index d9a370467..95f420b1f 100644 --- a/pwndbg/dbg/lldb/__init__.py +++ b/pwndbg/dbg/lldb/__init__.py @@ -889,8 +889,13 @@ class LLDBProcess(pwndbg.dbg_mod.Process): @override def vmmap(self) -> pwndbg.dbg_mod.MemoryMap: + from pwndbg.aglib.commpage import get_commpage_mappings + pages = self.get_known_pages() if pages: + pages.extend(get_commpage_mappings()) + pages.sort() + return LLDBMemoryMap(pages) from pwndbg.aglib.kernel.vmmap import kernel_vmmap diff --git a/scripts/_docs/command_docs_common.py b/scripts/_docs/command_docs_common.py index 601e9a125..238e4ce5e 100644 --- a/scripts/_docs/command_docs_common.py +++ b/scripts/_docs/command_docs_common.py @@ -28,7 +28,7 @@ def category_to_folder_name(category) -> str: folder = re.sub(r"[ /]", "_", folder) # replace all spaces and / with _ # Don't allow wacky characters for folder names. If you hit this assert, feel free # to update the regex above to sanitize the category name. - assert all(c.isalnum() or c == "_" for c in folder) + assert all(c.isalnum() or c in ("_", "-") for c in folder), f"Error folder={folder}" return folder