/*
 * DF-2230 verification rig -- KERNEL side.
 *
 * Drives the REAL in-kernel proplib parser path end to end:
 *
 *	prop_array_internalize()			[exported kernel symbol]
 *	  -> _prop_array_internalize()
 *	  -> _prop_number_internalize()		[the function under audit]
 *	  -> _prop_number_internalize_signed()	[strtoq, ERANGE check compiled out]
 *
 * with a case matrix of <integer> payloads, then reports the stored value
 * and the pnv_is_unsigned flag through the real accessors
 * (prop_number_unsigned / prop_number_integer_value /
 * prop_number_unsigned_integer_value).
 *
 * No code is copied from prop_number.c: this exercises the exact object
 * code in the running kernel.  Source identity between the running
 * kernel build tree and the audited tree is enforced by build.sh via
 * sha256 of /usr/src/sys/libprop/prop_number.c.
 *
 * Output contract (one line per case, grep-able):
 *	DF2230|K|in=<input>|array=<0/1>|cnt=<n>|elem=<yes/NO>|is_unsigned=<0/1/-1>|signed=<dec> (0x<hex>)|unsigned=<dec> (0x<hex>)
 */
#include <sys/param.h>
#include <sys/module.h>
#include <sys/kernel.h>
#include <sys/systm.h>
#include <sys/types.h>
#include <libprop/proplib.h>

static const char *df2230_vals[] = {
	"0",				/* small */
	"42",				/* small */
	"-1",				/* negative control */
	"-9223372036854775808",		/* INT64_MIN, exact boundary */
	"-9223372036854775809",		/* INT64_MIN-1: negative saturation */
	"9223372036854775807",		/* INT64_MAX, exact boundary */
	"9223372036854775808",		/* INT64_MAX+1: claimed bug domain */
	"10000000000000000000",		/* 1e19 mid-range, bug domain */
	"18446744073709551615",		/* UINT64_MAX decimal, bug domain */
	"99999999999999999999",		/* > UINT64_MAX decimal (residual class) */
	"0x7fffffffffffffff",		/* hex INT64_MAX (must stay correct) */
	"0x8000000000000000",		/* hex 2^63 (must stay correct) */
	"0xffffffffffffffff",		/* hex UINT64_MAX (must stay correct) */
	"0Xffffffffffffffff",		/* capital 0X: routes via signed path */
};
#define	DF2230_NVALS	((int)(sizeof(df2230_vals) / sizeof(df2230_vals[0])))

static void
df2230_run(void)
{
	int i;

	kprintf("DF2230|K|BEGIN matrix (kernel prop_array_internalize)\n");
	for (i = 0; i < DF2230_NVALS; i++) {
		char xml[640];
		prop_array_t pa;
		prop_object_t o;
		int ok, cnt = -1, isu = -1;
		int64_t sv = 0;
		uint64_t uv = 0;

		ksnprintf(xml, sizeof(xml),
		    "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
		    "<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n"
		    "<plist version=\"1.0\">\n"
		    "<array>\n"
		    "<integer>%s</integer>\n"
		    "</array>\n"
		    "</plist>\n", df2230_vals[i]);

		pa = prop_array_internalize(xml);
		ok = (pa != NULL);
		o = NULL;
		if (ok) {
			cnt = prop_array_count(pa);
			o = prop_array_get(pa, 0);
			if (o != NULL &&
			    prop_object_type(o) == PROP_TYPE_NUMBER) {
				isu = prop_number_unsigned(o);
				sv = prop_number_integer_value(o);
				uv = prop_number_unsigned_integer_value(o);
			} else {
				o = NULL;
			}
		}
		kprintf("DF2230|K|in=%s|array=%d|cnt=%d|elem=%s|is_unsigned=%d|"
		    "signed=%lld (0x%llx)|unsigned=%llu (0x%llx)\n",
		    df2230_vals[i], ok, cnt, o ? "yes" : "NO", isu,
		    (long long)sv, (unsigned long long)sv,
		    (unsigned long long)uv, (unsigned long long)uv);
		if (ok)
			prop_object_release(pa);
	}
	kprintf("DF2230|K|END\n");
}

static int
df2230_modevent(module_t mod __unused, int type, void *data __unused)
{
	switch (type) {
	case MOD_LOAD:
		df2230_run();
		return (0);
	case MOD_UNLOAD:
		kprintf("DF2230|K|module unloaded\n");
		return (0);
	default:
		return (EOPNOTSUPP);
	}
}

static moduledata_t df2230_mod = {
	"df2230",
	df2230_modevent,
	NULL
};

DECLARE_MODULE(df2230, df2230_mod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE);
MODULE_VERSION(df2230, 1);
