mirror of
https://github.com/JakeHillion/drgn.git
synced 2024-12-22 09:13:06 +00:00
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:
parent
a657c841d0
commit
eb83d51175
@ -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.
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user