mirror of
https://github.com/JakeHillion/drgn.git
synced 2024-12-22 17:23:06 +00:00
b3a6d6a35f
Rather than computing it every time we need it, compute it once when we parse PAGE_SIZE from VMCOREINFO (and validate that PAGE_SIZE is a power of two). This will be more important for AArch64 page table walking. Signed-off-by: Omar Sandoval <osandov@osandov.com>
93 lines
2.6 KiB
Plaintext
93 lines
2.6 KiB
Plaintext
static struct drgn_error *parse_vmcoreinfo_u64(const char *value,
|
|
const char *newline, int base,
|
|
uint64_t *ret)
|
|
{
|
|
errno = 0;
|
|
char *end;
|
|
*ret = strtoull(value, &end, base);
|
|
if (errno == ERANGE) {
|
|
return drgn_error_create(DRGN_ERROR_OVERFLOW,
|
|
"number in VMCOREINFO is too large");
|
|
} else if (errno || end == value || end != newline) {
|
|
return drgn_error_create(DRGN_ERROR_OTHER,
|
|
"number in VMCOREINFO is invalid");
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
struct drgn_error *drgn_program_parse_vmcoreinfo(struct drgn_program *prog,
|
|
const char *desc,
|
|
size_t descsz)
|
|
{
|
|
struct drgn_error *err;
|
|
for (const char *line = desc, *end = &desc[descsz], *newline;
|
|
(newline = memchr(line, '\n', end - line));
|
|
line = newline + 1) {
|
|
const char *equals = memchr(line, '=', newline - line);
|
|
if (!equals)
|
|
continue;
|
|
|
|
const char *value = equals + 1;
|
|
@memswitch (line, equals - line)@
|
|
@case "OSRELEASE"@
|
|
if ((size_t)(newline - value) >=
|
|
sizeof(prog->vmcoreinfo.osrelease)) {
|
|
return drgn_error_create(DRGN_ERROR_OTHER,
|
|
"OSRELEASE in VMCOREINFO is too long");
|
|
}
|
|
memcpy(prog->vmcoreinfo.osrelease, value,
|
|
newline - value);
|
|
prog->vmcoreinfo.osrelease[newline - value] = '\0';
|
|
break;
|
|
@case "PAGESIZE"@
|
|
err = parse_vmcoreinfo_u64(value, newline, 0,
|
|
&prog->vmcoreinfo.page_size);
|
|
if (err)
|
|
return err;
|
|
break;
|
|
@case "KERNELOFFSET"@
|
|
err = parse_vmcoreinfo_u64(value, newline, 16,
|
|
&prog->vmcoreinfo.kaslr_offset);
|
|
if (err)
|
|
return err;
|
|
break;
|
|
@case "SYMBOL(swapper_pg_dir)"@
|
|
err = parse_vmcoreinfo_u64(value, newline, 16,
|
|
&prog->vmcoreinfo.swapper_pg_dir);
|
|
if (err)
|
|
return err;
|
|
break;
|
|
@case "NUMBER(pgtable_l5_enabled)"@
|
|
{
|
|
uint64_t tmp;
|
|
err = parse_vmcoreinfo_u64(value, newline, 0, &tmp);
|
|
if (err)
|
|
return err;
|
|
prog->vmcoreinfo.pgtable_l5_enabled = tmp;
|
|
break;
|
|
}
|
|
@case "NUMBER(KERNELPACMASK)"@
|
|
err = parse_vmcoreinfo_u64(value, newline, 16,
|
|
&prog->aarch64_insn_pac_mask);
|
|
if (err)
|
|
return err;
|
|
break;
|
|
@endswitch@
|
|
}
|
|
if (!prog->vmcoreinfo.osrelease[0]) {
|
|
return drgn_error_create(DRGN_ERROR_OTHER,
|
|
"VMCOREINFO does not contain valid OSRELEASE");
|
|
}
|
|
if (!is_power_of_two(prog->vmcoreinfo.page_size)) {
|
|
return drgn_error_create(DRGN_ERROR_OTHER,
|
|
"VMCOREINFO does not contain valid PAGESIZE");
|
|
}
|
|
prog->vmcoreinfo.page_shift = ctz(prog->vmcoreinfo.page_size);
|
|
if (!prog->vmcoreinfo.swapper_pg_dir) {
|
|
return drgn_error_create(DRGN_ERROR_OTHER,
|
|
"VMCOREINFO does not contain valid swapper_pg_dir");
|
|
}
|
|
/* KERNELOFFSET, pgtable_l5_enabled, and KERNELPACMASK are optional. */
|
|
return NULL;
|
|
}
|