Skip to content

Commit

Permalink
Add VMCOREINFO to special Linux Kernel objects
Browse files Browse the repository at this point in the history
For Python-based object, type, and symbol finders, the vmcoreinfo is a
critical source of information. It can contain addresses necessary for
loading certain information (such as kallsyms). Expose this information
as a special object.

Signed-off-by: Stephen Brennan <[email protected]>
  • Loading branch information
brenns10 committed Aug 17, 2023
1 parent 7ac5007 commit e18acb2
Show file tree
Hide file tree
Showing 7 changed files with 58 additions and 0 deletions.
19 changes: 19 additions & 0 deletions docs/advanced_usage.rst
Original file line number Diff line number Diff line change
Expand Up @@ -191,3 +191,22 @@ core dumps. These special objects include:
resorting to architecture-specific logic.

This is *not* available without debugging information.

``VMCOREINFO``
Object type: ``const char []``

This is the data contained in the vmcoreinfo note, which is present either
as an ELF note in ``/proc/kcore`` or ELF vmcores, or as a special data
section in kdump-formatted vmcores. The vmcoreinfo note contains critical
data necessary for interpreting the kernel image, such as KASLR offsets and
data structure locations.

In the Linux kernel, this data is normally stored in a variable called
``vmcoreinfo_data``. However, drgn reads this information from ELF note or
from the diskdump header. It is possible (in rare cases, usually with
vmcores created by hypervisors) for a vmcore to contain vmcoreinfo which
differs from the data in ``vmcoreinfo_data``, so it is important to
distinguish the contents. For that reason, we use the name ``VMCOREINFO`` to
distinguish it from the kernel variable ``vmcoreinfo_data``.

This is available without debugging information.
6 changes: 6 additions & 0 deletions libdrgn/drgn_program_parse_vmcoreinfo.inc.strswitch
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,12 @@ struct drgn_error *drgn_program_parse_vmcoreinfo(struct drgn_program *prog,
size_t descsz)
{
struct drgn_error *err;

prog->vmcoreinfo.data_size = descsz;
prog->vmcoreinfo.data = memdup(desc, descsz);
if (!prog->vmcoreinfo.data) {
return &drgn_enomem;
}
for (const char *line = desc, *end = &desc[descsz], *newline;
(newline = memchr(line, '\n', end - line));
line = newline + 1) {
Expand Down
3 changes: 3 additions & 0 deletions libdrgn/kdump.c
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,9 @@ struct drgn_error *drgn_program_set_kdump(struct drgn_program *prog)
err_platform:
prog->has_platform = had_platform;
err:
// Reset anything we parsed from vmcoreinfo
free(prog->vmcoreinfo.data);
memset(&prog->vmcoreinfo, 0, sizeof(prog->vmcoreinfo));
kdump_free(ctx);
return err;
}
Expand Down
20 changes: 20 additions & 0 deletions libdrgn/linux_kernel.c
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,26 @@ static struct drgn_error *linux_kernel_get_jiffies(struct drgn_program *prog,
return err;
}

static struct drgn_error *
linux_kernel_get_vmcoreinfo(struct drgn_program *prog, struct drgn_object *ret)
{
struct drgn_error *err;
struct drgn_qualified_type qualified_type;
err = drgn_program_find_primitive_type(prog,
DRGN_C_TYPE_CHAR,
&qualified_type.type);
if (err)
return err;
qualified_type.qualifiers = DRGN_QUALIFIER_CONST;
err = drgn_array_type_create(prog, qualified_type, prog->vmcoreinfo.data_size,
&drgn_language_c, &qualified_type.type);
if (err)
return err;
qualified_type.qualifiers = 0;
return drgn_object_set_from_buffer(ret, qualified_type, prog->vmcoreinfo.data,
prog->vmcoreinfo.data_size, 0, 0);
}

// The vmemmap address can vary depending on architecture, kernel version,
// configuration options, and KASLR. However, we can get it generically from the
// section_mem_map of any valid mem_section.
Expand Down
4 changes: 4 additions & 0 deletions libdrgn/linux_kernel_object_find.inc.strswitch
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@ struct drgn_error *linux_kernel_object_find(const char *name, size_t name_len,
if (flags & DRGN_FIND_OBJECT_CONSTANT)
return linux_kernel_get_vmemmap(prog, ret);
break;
@case "VMCOREINFO"@
if (flags & DRGN_FIND_OBJECT_CONSTANT)
return linux_kernel_get_vmcoreinfo(prog, ret);
break;
@endswitch@
}
return &drgn_not_found;
Expand Down
2 changes: 2 additions & 0 deletions libdrgn/program.c
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@ void drgn_program_deinit(struct drgn_program *prog)
drgn_memory_reader_deinit(&prog->reader);

free(prog->file_segments);
free(prog->vmcoreinfo.data);

#ifdef WITH_LIBKDUMPFILE
if (prog->kdump_ctx)
Expand Down Expand Up @@ -581,6 +582,7 @@ drgn_program_set_core_dump(struct drgn_program *prog, const char *path)
out_notes:
// Reset anything we parsed from ELF notes.
prog->aarch64_insn_pac_mask = 0;
free(prog->vmcoreinfo.data);
memset(&prog->vmcoreinfo, 0, sizeof(prog->vmcoreinfo));
out_platform:
prog->has_platform = had_platform;
Expand Down
4 changes: 4 additions & 0 deletions libdrgn/program.h
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,10 @@ struct drgn_program {
bool pgtable_l5_enabled;
/** PAGE_SHIFT of the kernel (derived from PAGE_SIZE). */
int page_shift;

/** The original vmcoreinfo data, to expose as an object */
char *data;
size_t data_size;
} vmcoreinfo;
/*
* Difference between a virtual address in the direct mapping and the
Expand Down

0 comments on commit e18acb2

Please sign in to comment.