drgn/libdrgn/drgn_program_parse_vmcoreinfo.inc.strswitch
Omar Sandoval db3babd42e libdrgn: aarch64: implement page table iterator
Now that we made the other memory management helpers generic, the last
thing to implement for AArch64 is page table walking. This looks a lot
like the x86-64 equivalent but has to support the various page and
virtual address sizes that can be configured for AArch64.

Signed-off-by: Omar Sandoval <osandov@osandov.com>
2022-07-14 12:23:08 -07:00

105 lines
2.9 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 "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(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;
}