Skip to content

Commit

Permalink
libdrgn: x86_64: avoid recursive address translation for swapper_pg_dir
Browse files Browse the repository at this point in the history
Most core dumps contain some virtual address mappings: usually at a
minimum, the kernel's direct map is represented in ELF vmcores via a
segment. So normally, drgn can rely on the vmcore to read the virtual
address of swapper_pg_dir. However, some vmcores only contain physical
address information, so when drgn reads memory at swapper_pg_dir, it
needs to first translate that address, thus causing a recursive
translation error like below:

>>> prog["slab_caches"]
Traceback (most recent call last):
  File "<console>", line 1, in <module>
  File "/home/stepbren/repos/drgn/drgn/cli.py", line 141, in _displayhook
    text = value.format_(columns=shutil.get_terminal_size((0, 0)).columns)
_drgn.FaultError: recursive address translation; page table may be missing from core dump: 0xffffffff9662aff8

Debuggers like crash, as well as libkdumpfile, contain fallback code
which can translate swapper_pg_dir in order to bootstrap this address
translation. In fact, the above error does not occur in drgn when using
libkdumpfile. So, let's add this fallback case to drgn as well. Other
architectures will need to have equivalent support added.

Co-authored-by: Illia Ostapyshyn <[email protected]>
Signed-off-by: Stephen Brennan <[email protected]>
  • Loading branch information
brenns10 and iostapyshyn committed May 30, 2024
1 parent 4a4058f commit 573d1c2
Show file tree
Hide file tree
Showing 3 changed files with 26 additions and 1 deletion.
17 changes: 16 additions & 1 deletion libdrgn/arch_x86_64.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@

#include "arch_x86_64_defs.inc"

// This is __START_KERNEL_map from the Linux kernel. It has never been modified
// since the x86_64 architecture was introduced.
#define START_KERNEL_MAP UINT64_C(0xffffffff80000000)

static const struct drgn_cfi_row default_dwarf_cfi_row_x86_64 = DRGN_CFI_ROW(
// The System V psABI defines the CFA as the value of rsp in the calling
// frame.
Expand Down Expand Up @@ -616,7 +620,18 @@ linux_kernel_pgtable_iterator_next_x86_64(struct drgn_program *prog,
for (;; level--) {
uint64_t table;
bool table_physical;
if (level == levels) {
if (level == levels && prog->vmcoreinfo.phys_base &&
it->it.pgtable == prog->vmcoreinfo.swapper_pg_dir) {
// Avoid recursive address translation on swapper_pg_dir by
// directly resolving to a physical address. Don't do
// this if phys_base is 0, since that likely means it
// was not present in the vmcoreinfo. It has been
// present since Linux kernel commit 401721ecd1dc
// ("kexec: export the value of phys_base instead of
// symbol address") (in v4.10).
table = it->it.pgtable + prog->vmcoreinfo.phys_base - START_KERNEL_MAP;
table_physical = true;
} else if (level == levels) {
table = it->it.pgtable;
table_physical = false;
} else {
Expand Down
8 changes: 8 additions & 0 deletions libdrgn/drgn_program_parse_vmcoreinfo.inc.strswitch
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,14 @@ struct drgn_error *drgn_program_parse_vmcoreinfo(struct drgn_program *prog,
prog->vmcoreinfo.pgtable_l5_enabled = tmp;
break;
}
@case "NUMBER(phys_base)"@
{
err = parse_vmcoreinfo_u64(value, newline, 0,
&prog->vmcoreinfo.phys_base);;
if (err)
return err;
break;
}
@case "NUMBER(KERNELPACMASK)"@
err = parse_vmcoreinfo_u64(value, newline, 16,
&prog->aarch64_insn_pac_mask);
Expand Down
2 changes: 2 additions & 0 deletions libdrgn/program.h
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,8 @@ struct drgn_program {
uint64_t mem_section_length;
/** VA_BITS on AArch64. */
uint64_t va_bits;
/** phys_base on x86_64 */
uint64_t phys_base;
/** Whether 5-level paging was enabled on x86-64. */
bool pgtable_l5_enabled;
/** PAGE_SHIFT of the kernel (derived from PAGE_SIZE). */
Expand Down

0 comments on commit 573d1c2

Please sign in to comment.