mirror of
https://github.com/JakeHillion/drgn.git
synced 2024-12-22 01:03:07 +00:00
bdb793508f
Fixes: 5b39bfb547
("libdrgn: x86_64: avoid recursive address translation for swapper_pg_dir")
Signed-off-by: Omar Sandoval <osandov@osandov.com>
124 lines
3.4 KiB
Plaintext
124 lines
3.4 KiB
Plaintext
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
// SPDX-License-Identifier: LGPL-2.1-or-later
|
|
|
|
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;
|
|
|
|
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) {
|
|
const char *equals = memchr(line, '=', newline - line);
|
|
if (!equals)
|
|
continue;
|
|
|
|
const char *value = equals + 1;
|
|
@memswitch (line, equals - line)@
|
|
@case "CRASHTIME"@
|
|
prog->vmcoreinfo.have_crashtime = true;
|
|
break;
|
|
@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 "LENGTH(mem_section)"@
|
|
err = parse_vmcoreinfo_u64(value, newline, 0,
|
|
&prog->vmcoreinfo.mem_section_length);
|
|
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(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);
|
|
if (err)
|
|
return err;
|
|
break;
|
|
@case "NUMBER(VA_BITS)"@
|
|
err = parse_vmcoreinfo_u64(value, newline, 0,
|
|
&prog->vmcoreinfo.va_bits);
|
|
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");
|
|
}
|
|
// Everything else is optional.
|
|
return NULL;
|
|
}
|