From 7920d32696751dc7d5e485f60cfb86dffd726dd5 Mon Sep 17 00:00:00 2001
From: Toshikazu Nakayama <nakayama.ts@ncos.nec.co.jp>
Date: Mon, 17 Jan 2011 15:31:52 +0900
Subject: [PATCH 1/2] new ikconfig API.

IKCFG_SETUP/IKCFG_FREE args are added into read_in_kernel_config().

get_kernel_config() is new API which can get active kernel config
after read_in_kernel_config(IKCFG_SETUP).
Must be CONFIG_IKCONFIG=y for target kernel.

Maybe this API is also useful for extension users who write kernel config
depended code.

crash> extend dll
-> read_in_kernel_config(IKCFG_SETUP) from constructor.

       get_kernel_config() can work if CONFIG_IKCONFIG=y.

crash> extend -u dll
-> read_in_kernel_config(IKCFG_FREE) from destructor.

Signed-off-by: Toshikazu Nakayama <nakayama.ts@ncos.nec.co.jp>
---
 crash-5.1.1/defs.h   |   13 ++++
 crash-5.1.1/kernel.c |  162 +++++++++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 174 insertions(+), 1 deletions(-)

diff --git a/crash-5.1.1/defs.h b/crash-5.1.1/defs.h
index 22f876b..1b50fad 100755
--- a/crash-5.1.1/defs.h
+++ b/crash-5.1.1/defs.h
@@ -535,6 +535,9 @@ struct kernel_table {                   /* kernel data */
 	uint kernel_version[3];
 	uint gcc_version[3];
 	int runq_siblings;
+	int ikconfig_setup;
+	int ikconfig_ents;
+	int ikconfig_refs;
 	int kernel_NR_CPUS;
 	long __per_cpu_offset[NR_CPUS];
 	long *__rq_idx;
@@ -4052,6 +4055,16 @@ void read_in_kernel_config(int);
 
 #define IKCFG_INIT   (0)
 #define IKCFG_READ   (1)
+#define IKCFG_SETUP  (2)
+#define IKCFG_FREE   (3)
+
+int get_kernel_config(char *, char **);
+enum {
+	IKCONFIG_N,
+	IKCONFIG_Y,
+	IKCONFIG_M,
+	IKCONFIG_STR,
+};
 
 #define MAGIC_START  "IKCFG_ST"
 #define MAGIC_END    "IKCFG_ED"
diff --git a/crash-5.1.1/kernel.c b/crash-5.1.1/kernel.c
index 21236d0..739e75b 100755
--- a/crash-5.1.1/kernel.c
+++ b/crash-5.1.1/kernel.c
@@ -6818,7 +6818,123 @@ search_mapping_page(ulong mfn, ulong *index, ulong *startptr, ulong *endptr)
 	return found;
 }
 
+/*
+ * IKCONFIG management.
+ */
+#define IKCONFIG_MAX		5000
+#define IKCONFIG_SORT_INTERVAL	10
+static struct ikconfig_list {
+	int ref_cnt;
+	char *name;
+	char *val;
+} *ikconfig_all;
+
+/* Sort with access counts. */
+static int sort_ikconfig(const void *a, const void *b)
+{
+	struct ikconfig_list *aa, *bb;
+
+	aa = (struct ikconfig_list *)a;
+	bb = (struct ikconfig_list *)b;
+
+	return bb->ref_cnt - aa->ref_cnt;
+}
+
+static void add_ikconfig_entry(char *line, struct ikconfig_list *ent)
+{
+	char *tokptr, *name, *val;
+
+	name = strtok_r(line, "=", &tokptr);
+	sscanf(name, "CONFIG_%s", name);
+	val = strtok_r(NULL, "", &tokptr);
+
+	ent->ref_cnt = 0;
+	ent->name = strdup(name);
+	ent->val = strdup(val);
+}
+
+static int setup_ikconfig(char *config)
+{
+	char *ent, *tokptr;
+
+	ikconfig_all = calloc(1, sizeof(struct ikconfig_list) * IKCONFIG_MAX);
+	if (!ikconfig_all) {
+		error(WARNING, "cannot calloc for ikconfig entries.\n");
+		return 0;
+	}
+
+	ent =  strtok_r(config, "\n", &tokptr);
+	while (ent) {
+		while (whitespace(*ent))
+			ent++;
+
+		if (ent[0] != '#') {
+			add_ikconfig_entry(ent,
+					 &ikconfig_all[kt->ikconfig_ents++]);
+			if (kt->ikconfig_ents == IKCONFIG_MAX) {
+				error(WARNING, "ikconfig overflow.\n");
+				return 1;
+			}
+		}
+		ent = strtok_r(NULL, "\n", &tokptr);
+	}
+	if (kt->ikconfig_ents == 0) {
+		free(ikconfig_all);
+		return 0;
+	}
+	ikconfig_all = realloc(ikconfig_all,
+			   sizeof(struct ikconfig_list) * kt->ikconfig_ents);
+	kt->ikconfig_refs = 0;
+
+	return 1;
+}
+
+static void free_ikconfig(void)
+{
+	int i;
+
+	for (i = 0; i < kt->ikconfig_ents; i++) {
+		free(ikconfig_all[i].name);
+		free(ikconfig_all[i].val);
+	}
+	free(ikconfig_all);
+}
 
+int get_kernel_config(char *name, char **str)
+{
+	int i;
+	int ret = IKCONFIG_N;
+
+	if (!kt->ikconfig_setup) {
+		error(WARNING,
+		      "read_in_kernel_config(IKCFG_SETUP) has not done or\n"
+		      "CONFIG_IKCONFIG is not set\n");
+		return ret;
+	}
+
+	for (i = 0; i < kt->ikconfig_ents; i++) {
+		if (STREQ(name, ikconfig_all[i].name)) {
+			ikconfig_all[i].ref_cnt++;
+			if (str)
+				*str = ikconfig_all[i].val;
+			if (STREQ(ikconfig_all[i].val, "y"))
+				ret = IKCONFIG_Y;
+			else if (STREQ(ikconfig_all[i].val, "m"))
+				ret = IKCONFIG_M;
+			else
+				ret = IKCONFIG_STR;
+
+			kt->ikconfig_refs++;
+			if (!(kt->ikconfig_refs % IKCONFIG_SORT_INTERVAL))
+				qsort(ikconfig_all,
+				      (size_t)kt->ikconfig_ents,
+				      sizeof(struct ikconfig_list),
+				      sort_ikconfig);
+			break;
+		}
+	}
+	return ret;
+}
 
 /*
  *  Read the relevant IKCONFIG (In Kernel Config) data if available.
@@ -6846,7 +6962,7 @@ read_in_kernel_config(int command)
 		return;
 
 	if ((sp = symbol_search("kernel_config_data")) == NULL) {
-		if (command == IKCFG_READ)
+		if (command == IKCFG_READ || command == IKCFG_SETUP)
 			error(FATAL, 
 			    "kernel_config_data does not exist in this kernel\n");
 		return;
@@ -6948,6 +7064,50 @@ again:
 
 	pos = uncomp;
 
+	if (command == IKCFG_SETUP) {
+		if (!kt->ikconfig_setup) {
+			kt->ikconfig_setup = setup_ikconfig(pos);
+			if (kt->ikconfig_setup && CRASHDEBUG(1))
+				fprintf(fp,
+					"ikconfig: Setup %d valid configs.\n",
+					kt->ikconfig_ents);
+		} else /* Case of call from multiple extension modules. */
+			kt->ikconfig_setup++;
+		goto out1;
+	} else if (command == IKCFG_FREE) {
+		if (!(--kt->ikconfig_setup)) {
+			free_ikconfig();
+			kt->ikconfig_ents = 0;
+			kt->ikconfig_refs = 0;
+		}
+		goto out1;
+	}
+
+	if (command == IKCFG_INIT && kt->ikconfig_setup) {
+		/* fastpath */
+		if (get_kernel_config("DEBUG_BUGVERBOSE", NULL) == IKCONFIG_N)
+			kt->flags |= BUGVERBOSE_OFF;
+
+		if (get_kernel_config("NR_CPUS", &val) == IKCONFIG_STR) {
+			kt->kernel_NR_CPUS = atoi(val);
+			if (CRASHDEBUG(1))
+				error(INFO, "CONFIG_NR_CPUS: %d\n",
+				      kt->kernel_NR_CPUS);
+		}
+		if (get_kernel_config("PGTABLE_4", NULL) == IKCONFIG_Y) {
+			machdep->flags |= VM_4_LEVEL;
+			if (CRASHDEBUG(1))
+				error(INFO, "CONFIG_PGTABLE_4\n");
+		}
+		if (get_kernel_config("HZ", &val) == IKCONFIG_STR) {
+			machdep->hz = atoi(val);
+			if (CRASHDEBUG(1))
+				error(INFO, "CONFIG_HZ: %d\n", machdep->hz);
+		}
+
+		goto out1;
+	}
+
 	do {
 		ret = sscanf(pos, "%511[^\n]\n%n", line, &ii);
 		if (ret > 0) {
-- 
1.7.4.rc2

