/* DF-3398 fix-check: dump qwords past the cpu's cfg_alias end.
 * usage: kcheck <cpu> <ip_fw3_nat_ctx_runtime_addr> */
#include <sys/types.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdint.h>

#define ALIAS_RANGE 64511
#define ICMP_IN_OFF (24 + 2 * (ALIAS_RANGE * 8))   /* next(8)+prev(8)+ip(4)+pad(4)+tcp_in+udp_in */
#define CFG_ALIAS_SZ (24 + 3 * (ALIAS_RANGE * 8))   /* 1548288 = exactly 378 pages */

static int fd;
static int
rd(uint64_t a, void *b, size_t n)
{
	return pread(fd, b, n, (off_t)a) == (ssize_t)n ? 0 : -1;
}

int
main(int argc, char **argv)
{
	int cpu = atoi(argv[1]);
	uint64_t sym = strtoull(argv[2], NULL, 16);
	uint64_t ctx, nat, alias, a;
	uint64_t v;

	fd = open("/dev/kmem", O_RDONLY);
	if (rd(sym + cpu * 8, &ctx, 8)) { perror("ctx"); return 1; }
	if (rd(ctx, &nat, 8)) { perror("nat"); return 1; }
	if (rd(nat + 8, &alias, 8)) { perror("alias"); return 1; }
	printf("cpu%d ctx=0x%llx nat=0x%llx alias=0x%llx alias_sz=%d\n",
	    cpu, (unsigned long long)ctx, (unsigned long long)nat,
	    (unsigned long long)alias, CFG_ALIAS_SZ);
	printf("qwords past allocation end:\n");
	for (a = 0; a < 128; a += 8) {
		char tag[64] = "";
		if (rd(alias + CFG_ALIAS_SZ + a, &v, 8)) {
			printf("  +%4lld: READ FAIL\n", (long long)a);
			continue;
		}
		if (a == 8) strcpy(tag, "<- idx 64512 (x=0xfc store, baseline wrote here)");
		if (a == 16) strcpy(tag, "<- idx 64513 (x=0x1fc)");
		if (a == 24) strcpy(tag, "<- idx 64514 (x=0x2fc)");
		if (a == 32) strcpy(tag, "<- idx 64515 (x=0x3fc)");
		printf("  +%4lld: 0x%016llx %s\n", (long long)a,
		    (unsigned long long)v, tag);
	}
	/* also verify the in-bounds slots hold the states after the fix */
	printf("in-bounds icmp_in slots (252/508/764/1020 after fix):\n");
	{
		uint64_t base = alias + ICMP_IN_OFF;
		int slots[] = {252, 508, 764, 1020, 300};
		int i;
		for (i = 0; i < 5; i++) {
			if (rd(base + 8ULL * slots[i], &v, 8)) v = 0xDEAD;
			printf("  icmp_in[%d] = 0x%016llx\n", slots[i],
			    (unsigned long long)v);
		}
	}
	return 0;
}
