mirror of
https://github.com/JakeHillion/drgn.git
synced 2024-12-22 01:03:07 +00:00
helpers.common.memory: add print_annotated_memory() helper
This is similar to print_annotated_stack() except that it works on an arbitrary memory range. It's useful for trying to find some context in mystery memory. Signed-off-by: Omar Sandoval <osandov@osandov.com>
This commit is contained in:
parent
1232a404c6
commit
c7717280ad
@ -9,15 +9,19 @@ The ``drgn.helpers.common.memory`` module provides helpers for working with memo
|
||||
"""
|
||||
|
||||
import operator
|
||||
import typing
|
||||
from typing import Optional
|
||||
|
||||
import drgn
|
||||
from drgn import IntegerLike, Program, SymbolKind
|
||||
from drgn import IntegerLike, PlatformFlags, Program, SymbolKind
|
||||
from drgn.helpers.common.format import escape_ascii_string
|
||||
from drgn.helpers.common.prog import takes_program_or_default
|
||||
from drgn.helpers.linux.slab import slab_object_info
|
||||
|
||||
__all__ = ("identify_address",)
|
||||
__all__ = (
|
||||
"identify_address",
|
||||
"print_annotated_memory",
|
||||
)
|
||||
|
||||
|
||||
_SYMBOL_KIND_STR = {
|
||||
@ -84,3 +88,63 @@ def identify_address(prog: Program, addr: IntegerLike) -> Optional[str]:
|
||||
symbol_kind = _SYMBOL_KIND_STR.get(symbol.kind, "symbol")
|
||||
|
||||
return f"{symbol_kind}: {symbol.name}+{offset}"
|
||||
|
||||
|
||||
@takes_program_or_default
|
||||
def print_annotated_memory(
|
||||
prog: Program, address: IntegerLike, size: IntegerLike, physical: bool = False
|
||||
) -> None:
|
||||
"""
|
||||
Print the contents of a range of memory, annotating values that can be
|
||||
identified.
|
||||
|
||||
Currently, this will identify any addresses in the memory range with
|
||||
:func:`~drgn.helpers.common.memory.identify_address()`.
|
||||
|
||||
See :func:`~drgn.helpers.common.stack.print_annotated_stack()` for a
|
||||
similar function that annotates stack traces.
|
||||
|
||||
>>> print_annotated_memory(0xffffffff963eb200, 56)
|
||||
ADDRESS VALUE
|
||||
ffffffff963eb200: 00000000000000b8
|
||||
ffffffff963eb208: 000000000000a828
|
||||
ffffffff963eb210: 0000000000000000
|
||||
ffffffff963eb218: ffff8881042948e0 [slab object: mnt_cache+0x20]
|
||||
ffffffff963eb220: ffff88810074a540 [slab object: dentry+0x0]
|
||||
ffffffff963eb228: ffff8881042948e0 [slab object: mnt_cache+0x20]
|
||||
ffffffff963eb230: ffff88810074a540 [slab object: dentry+0x0]
|
||||
|
||||
:param address: Starting address.
|
||||
:param size: Number of bytes to read.
|
||||
:param physical: Whether *address* is a physical memory address. If
|
||||
``False``, then it is a virtual memory address.
|
||||
"""
|
||||
address = operator.index(address)
|
||||
mem = prog.read(address, size, physical)
|
||||
|
||||
# The platform must be known if we were able to read memory.
|
||||
assert prog.platform is not None
|
||||
|
||||
byteorder: 'typing.Literal["little", "big"]'
|
||||
if prog.platform.flags & PlatformFlags.IS_LITTLE_ENDIAN:
|
||||
byteorder = "little"
|
||||
else:
|
||||
byteorder = "big"
|
||||
|
||||
if prog.platform.flags & PlatformFlags.IS_64_BIT:
|
||||
word_size = 8
|
||||
line_format = "{:016x}: {:016x}{}"
|
||||
print("ADDRESS VALUE")
|
||||
else:
|
||||
word_size = 4
|
||||
line_format = "{:08x}: {:08x}{}"
|
||||
print("ADDRESS VALUE")
|
||||
|
||||
for offset in range(0, len(mem), word_size):
|
||||
value = int.from_bytes(mem[offset : offset + word_size], byteorder)
|
||||
identified = identify_address(prog, value)
|
||||
if identified is None:
|
||||
identified = ""
|
||||
else:
|
||||
identified = f" [{identified}]"
|
||||
print(line_format.format(address + offset, value, identified))
|
||||
|
@ -23,6 +23,9 @@ def print_annotated_stack(trace: StackTrace) -> None:
|
||||
Currently, this will identify any addresses on the stack with
|
||||
:func:`~drgn.helpers.common.memory.identify_address()`.
|
||||
|
||||
See :func:`~drgn.helpers.common.memory.print_annotated_memory()` for a
|
||||
similar function that annotates arbitrary memory ranges.
|
||||
|
||||
>>> print_annotated_stack(stack_trace(1))
|
||||
STACK POINTER VALUE
|
||||
[stack frame #0 at 0xffffffff8dc93c41 (__schedule+0x429/0x488) in context_switch at ./kernel/sched/core.c:5209:2 (inlined)]
|
||||
|
@ -4,7 +4,8 @@
|
||||
from contextlib import redirect_stdout
|
||||
import io
|
||||
|
||||
from drgn.helpers.common.memory import identify_address
|
||||
from drgn import sizeof
|
||||
from drgn.helpers.common.memory import identify_address, print_annotated_memory
|
||||
from drgn.helpers.common.stack import print_annotated_stack
|
||||
from drgn.helpers.linux.mm import pfn_to_virt
|
||||
from tests.linux_kernel import (
|
||||
@ -63,6 +64,19 @@ class TestIdentifyAddress(LinuxKernelTestCase):
|
||||
self.assertIsNone(identify_address(self.prog, self.prog["drgn_test_va"]))
|
||||
|
||||
|
||||
class TestPrintAnnotatedMemory(LinuxKernelTestCase):
|
||||
@skip_unless_have_test_kmod
|
||||
def test_print_annotated_memory(self):
|
||||
f = io.StringIO()
|
||||
with redirect_stdout(f):
|
||||
print_annotated_memory(
|
||||
self.prog,
|
||||
self.prog["drgn_test_small_slab_objects"].address_,
|
||||
sizeof(self.prog["drgn_test_small_slab_objects"]),
|
||||
)
|
||||
self.assertIn("slab object: drgn_test_small+0x0", f.getvalue())
|
||||
|
||||
|
||||
class TestPrintAnnotatedStack(LinuxKernelTestCase):
|
||||
@skip_unless_have_stack_tracing
|
||||
@skip_unless_have_test_kmod
|
||||
|
Loading…
Reference in New Issue
Block a user