Skip to content

Commit

Permalink
Use maint info sec for coredumps (#1155)
Browse files Browse the repository at this point in the history
## Description

When analyzing a coredump, always prefer `maintenance info sections`
over `info proc sections`

Fixes #1154
  • Loading branch information
hugsy authored Nov 11, 2024
1 parent 3bdba58 commit 9f2737a
Showing 1 changed file with 58 additions and 7 deletions.
65 changes: 58 additions & 7 deletions gef.py
Original file line number Diff line number Diff line change
Expand Up @@ -3536,6 +3536,16 @@ def is_qemu_system() -> bool:
return "received: \"\"" in response


def is_target_coredump() -> bool:
global gef
if gef.session.coredump_mode is not None:
return gef.session.coredump_mode
lines = (gdb.execute("maintenance info section", to_string=True) or "").splitlines()
is_coredump_mode = any(map(lambda line: line.startswith("Core file: "), lines))
gef.session.coredump_mode = is_coredump_mode
return is_coredump_mode


def get_filepath() -> str | None:
"""Return the local absolute path of the file currently debugged."""
if gef.session.remote:
Expand Down Expand Up @@ -10704,6 +10714,7 @@ def __gef_prompt__(current_prompt: Callable[[Callable], str]) -> str:
if gef.config["gef.readline_compat"] is True: return GEF_PROMPT
if gef.config["gef.disable_color"] is True: return GEF_PROMPT
prompt = gef.session.remote.mode.prompt_string() if gef.session.remote else ""
prompt += "(core) " if is_target_coredump() else ""
prompt += GEF_PROMPT_ON if is_alive() else GEF_PROMPT_OFF
return prompt

Expand Down Expand Up @@ -10818,6 +10829,12 @@ def __parse_maps(self) -> list[Section] | None:
if gef.arch.maps is not None:
return list(gef.arch.maps())

# Coredumps are the only case where `maintenance info sections` collected more
# info than `info proc sections`.so use this unconditionally. See #1154

if is_target_coredump():
return list(self.parse_gdb_maintenance_info_sections())

try:
return list(self.parse_gdb_info_proc_maps())
except Exception:
Expand All @@ -10835,8 +10852,8 @@ def __parse_maps(self) -> list[Section] | None:

raise RuntimeError("Failed to get memory layout")

@classmethod
def parse_procfs_maps(cls) -> Generator[Section, None, None]:
@staticmethod
def parse_procfs_maps() -> Generator[Section, None, None]:
"""Get the memory mapping from procfs."""
procfs_mapfile = gef.session.maps
if not procfs_mapfile:
Expand Down Expand Up @@ -10867,9 +10884,9 @@ def parse_procfs_maps(cls) -> Generator[Section, None, None]:
path=pathname)
return

@classmethod
def parse_gdb_info_proc_maps(cls) -> Generator[Section, None, None]:
"""Get the memory mapping from GDB's command `maintenance info sections` (limited info)."""
@staticmethod
def parse_gdb_info_proc_maps() -> Generator[Section, None, None]:
"""Get the memory mapping from GDB's command `info proc mappings`."""
if GDB_VERSION < (11, 0):
raise AttributeError("Disregarding old format")

Expand Down Expand Up @@ -10926,8 +10943,8 @@ def parse_gdb_info_proc_maps(cls) -> Generator[Section, None, None]:
)
return

@classmethod
def parse_monitor_info_mem(cls) -> Generator[Section, None, None]:
@staticmethod
def parse_monitor_info_mem() -> Generator[Section, None, None]:
"""Get the memory mapping from GDB's command `monitor info mem`
This can raise an exception, which the memory manager takes to mean
that this method does not work to get a map.
Expand All @@ -10948,6 +10965,39 @@ def parse_monitor_info_mem(cls) -> Generator[Section, None, None]:
offset=off,
permission=perm)

@staticmethod
def parse_gdb_maintenance_info_sections() -> Generator[Section, None, None]:
"""Get the memory mapping from GDB's command `maintenance info sections` (limited info). In some cases (i.e. coredumps),
the memory info collected by `info proc sections` is insufficent."""
stream = StringIO(gdb.execute("maintenance info sections", to_string=True))

for line in stream:
if not line:
break

try:
parts = line.split()
addr_start, addr_end = [int(x, 16) for x in parts[1].split("->")]
off = int(parts[3][:-1], 16)
path = parts[4]
perm = Permission.NONE
if "DATA" in parts[5:]:
perm |= Permission.READ | Permission.WRITE
if "CODE" in parts[5:]:
perm |= Permission.READ | Permission.EXECUTE
yield Section(
page_start=addr_start,
page_end=addr_end,
offset=off,
permission=perm,
path=path,
)

except IndexError:
continue
except ValueError:
continue

@staticmethod
def parse_info_mem():
"""Get the memory mapping from GDB's command `info mem`. This can be
Expand Down Expand Up @@ -11270,6 +11320,7 @@ def __init__(self) -> None:
self.remote: "GefRemoteSessionManager | None" = None
self.remote_initializing: bool = False
self.qemu_mode: bool = False
self.coredump_mode: bool | None = None
self.convenience_vars_index: int = 0
self.heap_allocated_chunks: list[tuple[int, int]] = []
self.heap_freed_chunks: list[tuple[int, int]] = []
Expand Down

0 comments on commit 9f2737a

Please sign in to comment.