#line 1 "../../libdrgn/drgn_program_parse_vmcoreinfo.inc.strswitch"
// 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;
#line 41 "drgn_program_parse_vmcoreinfo.inc"
		/* Generated by libdrgn/build-aux/gen_strswitch.py. */
		switch (1) {
		default: {
			#define memswitch0_args(ptr, len) \
				const void *memswitch0_ptr = (ptr); \
				const char *memswitch0_str = memswitch0_ptr; \
				size_t memswitch0_len = (len);
			memswitch0_args(
#line 39 "../../libdrgn/drgn_program_parse_vmcoreinfo.inc.strswitch"
		            line, equals - line
#line 52 "drgn_program_parse_vmcoreinfo.inc"
			)
			#undef memswitch0_args
			if (memswitch0_len == 8) {
				if (memcmp(&memswitch0_str[0], "PAGESIZE", sizeof("PAGESIZE") - 1) == 0) {
					memswitch0_case2:
#line 54 "../../libdrgn/drgn_program_parse_vmcoreinfo.inc.strswitch"
			err = parse_vmcoreinfo_u64(value, newline, 0,
						   &prog->vmcoreinfo.page_size);
			if (err)
				return err;
			break;
#line 64 "drgn_program_parse_vmcoreinfo.inc"
					goto memswitch0_case3;
				}
			} else if (memswitch0_len == 9) {
				if (memswitch0_str[0] == 'C') {
					if (memcmp(&memswitch0_str[1], "RASHTIME", sizeof("RASHTIME") - 1) == 0) {
#line 41 "../../libdrgn/drgn_program_parse_vmcoreinfo.inc.strswitch"
			prog->vmcoreinfo.have_crashtime = true;
			break;
#line 73 "drgn_program_parse_vmcoreinfo.inc"
						goto memswitch0_case1;
					}
				} else if (memswitch0_str[0] == 'O') {
					if (memcmp(&memswitch0_str[1], "SRELEASE", sizeof("SRELEASE") - 1) == 0) {
						memswitch0_case1:
#line 44 "../../libdrgn/drgn_program_parse_vmcoreinfo.inc.strswitch"
			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;
#line 89 "drgn_program_parse_vmcoreinfo.inc"
						goto memswitch0_case2;
					}
				}
			} else if (memswitch0_len == 12) {
				if (memcmp(&memswitch0_str[0], "KERNELOFFSET", sizeof("KERNELOFFSET") - 1) == 0) {
					memswitch0_case3:
#line 60 "../../libdrgn/drgn_program_parse_vmcoreinfo.inc.strswitch"
			err = parse_vmcoreinfo_u64(value, newline, 16,
						   &prog->vmcoreinfo.kaslr_offset);
			if (err)
				return err;
			break;
#line 102 "drgn_program_parse_vmcoreinfo.inc"
					goto memswitch0_case4;
				}
			} else if (memswitch0_len == 15) {
				if (memswitch0_str[0] == 'C') {
					if (memcmp(&memswitch0_str[1], "ONFIG_ARM_LPAE", sizeof("ONFIG_ARM_LPAE") - 1) == 0) {
						memswitch0_case11:
#line 114 "../../libdrgn/drgn_program_parse_vmcoreinfo.inc.strswitch"
			prog->vmcoreinfo.arm_lpae = value[0] == 'y';
			break;
#line 112 "drgn_program_parse_vmcoreinfo.inc"
					}
				} else if (memswitch0_str[0] == 'N') {
					if (memcmp(&memswitch0_str[1], "UMBER(VA_BITS)", sizeof("UMBER(VA_BITS)") - 1) == 0) {
						memswitch0_case9:
#line 102 "../../libdrgn/drgn_program_parse_vmcoreinfo.inc.strswitch"
			err = parse_vmcoreinfo_u64(value, newline, 0,
						   &prog->vmcoreinfo.va_bits);
			if (err)
				return err;
			break;
#line 123 "drgn_program_parse_vmcoreinfo.inc"
						goto memswitch0_case10;
					}
				}
			} else if (memswitch0_len == 17) {
				if (memcmp(&memswitch0_str[0], "NUMBER(phys_base)", sizeof("NUMBER(phys_base)") - 1) == 0) {
					memswitch0_case7:
#line 87 "../../libdrgn/drgn_program_parse_vmcoreinfo.inc.strswitch"
		{
			err = parse_vmcoreinfo_u64(value, newline, 0,
						   &prog->vmcoreinfo.phys_base);
			if (err)
				return err;
			prog->vmcoreinfo.have_phys_base = true;
			break;
		}
#line 139 "drgn_program_parse_vmcoreinfo.inc"
					goto memswitch0_case8;
				}
			} else if (memswitch0_len == 19) {
				if (memcmp(&memswitch0_str[0], "LENGTH(mem_section)", sizeof("LENGTH(mem_section)") - 1) == 0) {
					memswitch0_case5:
#line 72 "../../libdrgn/drgn_program_parse_vmcoreinfo.inc.strswitch"
			err = parse_vmcoreinfo_u64(value, newline, 0,
						   &prog->vmcoreinfo.mem_section_length);
			if (err)
				return err;
			break;
#line 151 "drgn_program_parse_vmcoreinfo.inc"
					goto memswitch0_case6;
				}
			} else if (memswitch0_len == 20) {
				if (memcmp(&memswitch0_str[0], "NUMBER(TCR_EL1_T1SZ)", sizeof("NUMBER(TCR_EL1_T1SZ)") - 1) == 0) {
					memswitch0_case10:
#line 108 "../../libdrgn/drgn_program_parse_vmcoreinfo.inc.strswitch"
			err = parse_vmcoreinfo_u64(value, newline, 0,
						   &prog->vmcoreinfo.tcr_el1_t1sz);
			if (err)
				return err;
			break;
#line 163 "drgn_program_parse_vmcoreinfo.inc"
					goto memswitch0_case11;
				}
			} else if (memswitch0_len == 21) {
				if (memcmp(&memswitch0_str[0], "NUMBER(KERNELPACMASK)", sizeof("NUMBER(KERNELPACMASK)") - 1) == 0) {
					memswitch0_case8:
#line 96 "../../libdrgn/drgn_program_parse_vmcoreinfo.inc.strswitch"
			err = parse_vmcoreinfo_u64(value, newline, 16,
						   &prog->aarch64_insn_pac_mask);
			if (err)
				return err;
			break;
#line 175 "drgn_program_parse_vmcoreinfo.inc"
					goto memswitch0_case9;
				}
			} else if (memswitch0_len == 22) {
				if (memcmp(&memswitch0_str[0], "SYMBOL(swapper_pg_dir)", sizeof("SYMBOL(swapper_pg_dir)") - 1) == 0) {
					memswitch0_case4:
#line 66 "../../libdrgn/drgn_program_parse_vmcoreinfo.inc.strswitch"
			err = parse_vmcoreinfo_u64(value, newline, 16,
						   &prog->vmcoreinfo.swapper_pg_dir);
			if (err)
				return err;
			break;
#line 187 "drgn_program_parse_vmcoreinfo.inc"
					goto memswitch0_case5;
				}
			} else if (memswitch0_len == 26) {
				if (memcmp(&memswitch0_str[0], "NUMBER(pgtable_l5_enabled)", sizeof("NUMBER(pgtable_l5_enabled)") - 1) == 0) {
					memswitch0_case6:
#line 78 "../../libdrgn/drgn_program_parse_vmcoreinfo.inc.strswitch"
		{
			uint64_t tmp;
			err = parse_vmcoreinfo_u64(value, newline, 0, &tmp);
			if (err)
				return err;
			prog->vmcoreinfo.pgtable_l5_enabled = tmp;
			break;
		}
#line 202 "drgn_program_parse_vmcoreinfo.inc"
					goto memswitch0_case7;
				}
			}
		}
		}
#line 117 "../../libdrgn/drgn_program_parse_vmcoreinfo.inc.strswitch"
	}
	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;
}
