Port plist (#2551)

* commands/plist.py: port to aglib

* commands/plist.py: fix lint

* commands/plist.py: Fix types

* commands/plist.py: make available from lldb

* ptype: implement compare for LDDBType and GDBType

* ptype: fix display value

* gdb/GDBValue: fix rethrowing exception

* aglib: create new function Value.value_to_human_readable
pull/2559/head
patryk4815 1 year ago committed by GitHub
parent d01ee809a2
commit be05019504
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -757,6 +757,7 @@ def load_commands() -> None:
import pwndbg.commands.p2p
import pwndbg.commands.patch
import pwndbg.commands.pie
import pwndbg.commands.plist
import pwndbg.commands.probeleak
import pwndbg.commands.retaddr
import pwndbg.commands.search

@ -3,11 +3,10 @@ from __future__ import annotations
import argparse
from typing import Optional
import gdb
import pwndbg.aglib.memory
import pwndbg.chain
import pwndbg.commands
import pwndbg.gdblib.memory
import pwndbg.dbg
from pwndbg.color import message
parser = argparse.ArgumentParser(
@ -189,17 +188,17 @@ parser.add_argument(
@pwndbg.commands.ArgparsedCommand(parser, command_name="plist")
def plist(
path: str,
next: int,
next: str,
sentinel: int,
inner_name: str,
field_name: str,
inner_name: Optional[str],
field_name: Optional[str],
offset: int,
count: Optional[int] = None,
) -> None:
# Have GDB parse the path for us and check if it's valid.
try:
first = gdb.parse_and_eval(path)
except gdb.error as e:
first = pwndbg.dbg.selected_frame().evaluate_expression(path)
except pwndbg.dbg_mod.Error as e:
print(message.error(f"{e}"))
return
@ -219,16 +218,16 @@ def plist(
# for the error mesages.
sep = "."
deref = ""
if first.type.code == gdb.TYPE_CODE_PTR:
if first.type.code == pwndbg.dbg_mod.TypeCode.POINTER:
sep = "->"
deref = "*"
try:
first = first.dereference()
except gdb.error as e:
except pwndbg.dbg_mod.Error as e:
print(message.error(f"Pointer at {path} could not be dereferenced: {e}"))
return
if first.type.code == gdb.TYPE_CODE_PTR:
if first.type.code == pwndbg.dbg_mod.TypeCode.POINTER:
print(message.error(f"{path} is not a value or a single pointer to one"))
return
@ -247,7 +246,7 @@ def plist(
try:
inner = first[inner_name]
inner_sep = "->"
except gdb.error as e:
except pwndbg.dbg_mod.Error as e:
print(message.error(f"Cannot find component {inner_name} in {path}: {e}"))
return
if inner.is_optimized_out:
@ -265,14 +264,14 @@ def plist(
next_ptr = inner[next]
next_ptr_loc = inner
next_ptr_name = f"{inner_name}.{next}"
except gdb.error as e:
except pwndbg.dbg_mod.Error as e:
print(message.error(f"Cannot find component {next_ptr_name} in {path}: {e}"))
return
if next_ptr.is_optimized_out:
print(message.error(f"{path}{sep}{next_ptr_name} has been optimized out"))
return
if next_ptr.type.code != gdb.TYPE_CODE_PTR:
if next_ptr.type.code != pwndbg.dbg_mod.TypeCode.POINTER:
print(message.error(f"{path}{sep}{next_ptr_name} is not a pointer"))
return
@ -282,7 +281,7 @@ def plist(
if field_name is not None:
try:
field = first[field_name]
except gdb.error as e:
except pwndbg.dbg_mod.Error as e:
print(message.error(f"Cannot find component {field_name} in {path}: {e}"))
return
field_type = field.type
@ -409,13 +408,13 @@ def plist(
target_type = field_type
target_address = address + field_offset
value = pwndbg.gdblib.memory.get_typed_pointer_value(target_type, target_address)
value = pwndbg.aglib.memory.get_typed_pointer_value(target_type, target_address)
symbol = pwndbg.gdblib.symbol.get(target_address)
symbol = pwndbg.dbg.selected_inferior().symbol_name_at_address(target_address)
symbol = f"<{symbol}>" if symbol else ""
print(f"{target_address:#x} {symbol}: {value}")
except gdb.error as e:
print(f"{target_address:#x} {symbol}: {value.value_to_human_readable()}")
except pwndbg.dbg_mod.Error as e:
print(message.error(f"Cannot dereference {address:#x} for list link #{i + 1}: {e}"))
print(message.error("Is the linked list corrupted or is the sentinel value wrong?"))
return

@ -664,6 +664,12 @@ class Type:
# if there is a better debugger-specific way to do this.
return [field.name for field in self.fields()]
def __eq__(self, rhs: object) -> bool:
"""
Returns True if types are the same
"""
raise NotImplementedError()
class Value:
"""
@ -719,6 +725,23 @@ class Value:
"""
raise NotImplementedError()
def value_to_human_readable(self) -> str:
"""
Converts a Value to a human-readable string representation.
The format is similar to what is produced by the `str()` function for gdb.Value,
displaying nested fields and pointers in a user-friendly way.
**Usage Notes:**
- This function is intended solely for displaying results to the user.
- The output format may differ between debugger implementations (e.g., GDB vs LLDB),
as each debugger may format values differently. For instance:
- GDB might produce: '{\n value = 0,\n inner = {\n next = 0x555555558098 <inner_a_node_b+8>\n }\n}'
- LLDB might produce: '(inner_a_node) *$PWNDBG_CREATED_VALUE_0 = {\n value = 0\n inner = {\n next = 0x0000555555558098\n }\n}'
- As such, this function should not be relied upon for parsing or programmatic use.
"""
raise NotImplementedError()
# This is a GDB implementation detail.
def fetch_lazy(self) -> None:
"""

@ -910,6 +910,13 @@ class GDBType(pwndbg.dbg_mod.Type):
def __init__(self, inner: gdb.Type):
self.inner = inner
@override
def __eq__(self, rhs: object) -> bool:
assert isinstance(rhs, GDBType), "tried to compare GDBType to other type"
other: GDBType = rhs
return self.inner == other.inner
@property
@override
def sizeof(self) -> int:
@ -997,7 +1004,17 @@ class GDBValue(pwndbg.dbg_mod.Value):
@override
def string(self) -> str:
return self.inner.string()
try:
return self.inner.string()
except gdb.error as e:
raise pwndbg.dbg_mod.Error(e)
@override
def value_to_human_readable(self) -> str:
try:
return str(self.inner)
except gdb.error as e:
raise pwndbg.dbg_mod.Error(e)
@override
def fetch_lazy(self) -> None:

@ -319,6 +319,13 @@ class LLDBType(pwndbg.dbg_mod.Type):
def __init__(self, inner: lldb.SBType):
self.inner = inner
@override
def __eq__(self, rhs: object) -> bool:
assert isinstance(rhs, LLDBType), "tried to compare LLDBType to other type"
other: LLDBType = rhs
return self.inner == other.inner
@property
@override
def sizeof(self) -> int:
@ -480,6 +487,10 @@ class LLDBValue(pwndbg.dbg_mod.Value):
return last_str
@override
def value_to_human_readable(self) -> str:
return str(self.inner)
@override
def fetch_lazy(self) -> None:
# Not needed under LLDB.

Loading…
Cancel
Save