Add VMCOREINFO to special Linux Kernel objects

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 <stephen.s.brennan@oracle.com>
This commit is contained in:
Stephen Brennan 2023-06-29 16:28:12 -07:00 committed by Omar Sandoval
parent a657c841d0
commit eb83d51175
7 changed files with 57 additions and 0 deletions

View File

@ -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.

View File

@ -23,6 +23,11 @@ struct drgn_error *drgn_program_parse_vmcoreinfo(struct drgn_program *prog,
size_t descsz)
{
struct drgn_error *err;
prog->vmcoreinfo.raw_size = descsz;
prog->vmcoreinfo.raw = memdup(desc, descsz);
if (!prog->vmcoreinfo.raw)
return &drgn_enomem;
for (const char *line = desc, *end = &desc[descsz], *newline;
(newline = memchr(line, '\n', end - line));
line = newline + 1) {

View File

@ -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.raw);
memset(&prog->vmcoreinfo, 0, sizeof(prog->vmcoreinfo));
kdump_free(ctx);
return err;
}

View File

@ -248,6 +248,26 @@ out:
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.raw_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.raw,
prog->vmcoreinfo.raw_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.

View File

@ -25,6 +25,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_uts_release(prog, ret);
break;
@case "VMCOREINFO"@
if (flags & DRGN_FIND_OBJECT_CONSTANT)
return linux_kernel_get_vmcoreinfo(prog, ret);
break;
@case "jiffies"@
if (flags & DRGN_FIND_OBJECT_VARIABLE)
return linux_kernel_get_jiffies(prog, ret);

View File

@ -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.raw);
#ifdef WITH_LIBKDUMPFILE
if (prog->kdump_ctx)
@ -581,6 +582,7 @@ out_segments:
out_notes:
// Reset anything we parsed from ELF notes.
prog->aarch64_insn_pac_mask = 0;
free(prog->vmcoreinfo.raw);
memset(&prog->vmcoreinfo, 0, sizeof(prog->vmcoreinfo));
out_platform:
prog->has_platform = had_platform;

View File

@ -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 *raw;
size_t raw_size;
} vmcoreinfo;
/*
* Difference between a virtual address in the direct mapping and the