per_cpu variable printing for KDB?

Keith Owens kaos at sgi.com
Sun Jun 6 01:02:05 PDT 2004


On Thu, 3 Jun 2004 11:51:45 -0500, 
linas at austin.ibm.com wrote:
>Is anybody working on per_cpu variable printing for KDB?
>I'm finding that looking up per-cpu values is tedious and
>error prone, esp. on systems with more than a few cpu's.

In my tree, to be released as part of kdb v4.4-2.6.6-common-2 this
weekend.  It goes over kdb v4.4-2.6.6-common-1.


Index: linux/Documentation/kdb/kdb.mm
===================================================================
--- linux.orig/Documentation/kdb/kdb.mm	Fri Jun  4 14:02:29 2004
+++ linux/Documentation/kdb/kdb.mm	Fri Jun  4 16:31:36 2004
@@ -1,4 +1,4 @@
-.TH KDB 8 "May 17, 2004"
+.TH KDB 8 "June 4, 2004"
 .hy 0
 .SH NAME
 Built-in Kernel Debugger for Linux - v4.4
@@ -148,6 +148,7 @@ mdr	Display raw memory contents
 mds	Display memory contents symbolically
 mm	Modify memory contents, words
 mmW	Modify memory contents, bytes
+per_cpu	Display per_cpu variables
 pid	Change the default process context
 ps	Display process status
 reboot	Reboot the machine
@@ -267,6 +268,18 @@ lsmod
 Internal command to list modules.
 This does not use any kernel nor user space services so can be used at any time.
 .TP 8
+per_cpu <variable_name> [<length>] [<cpu>]
+Display the values of a per_cpu variable, the variable_name is
+specified without the \fIper_cpu__\fR prefix.
+Length is the length of the variable, 1-8, if omitted or 0 it defaults
+to the size of the machine's register.
+To display the variable on a specific cpu, the third parameter is the
+cpu number.
+When the third parameter is omitted, the variable's value is printed
+from all cpus, except that zero values are suppressed.
+For each cpu, per_cpu prints the cpu number, the address of the
+variable and its value.
+.TP 8
 pid <number>
 Change the current process context, with no parameters it displays the
 current process.
Index: linux/kdb/ChangeLog
===================================================================
--- linux.orig/kdb/ChangeLog	Fri Jun  4 14:04:39 2004
+++ linux/kdb/ChangeLog	Fri Jun  4 14:07:52 2004
@@ -2,6 +2,7 @@
 
 	* Avoid recursion problems in kdb_init().
 	* Add standard archkdb commands.
+	* Add per_cpu command.
 
 2004-05-23 Keith Owens  <kaos at sgi.com>
 
Index: linux/kdb/kdbmain.c
===================================================================
--- linux.orig/kdb/kdbmain.c	Fri Jun  4 14:02:31 2004
+++ linux/kdb/kdbmain.c	Fri Jun  4 16:59:31 2004
@@ -3408,6 +3408,109 @@ kdb_summary(int argc, const char **argv,
 	return 0;
 }
 
+/*
+ * kdb_per_cpu
+ *
+ *	This function implements the 'per_cpu' command.
+ *
+ * Inputs:
+ *	argc	argument count
+ *	argv	argument vector
+ *	envp	environment vector
+ *	regs	registers at time kdb was entered.
+ * Outputs:
+ *	None.
+ * Returns:
+ *	zero for success, a kdb diagnostic if error
+ * Locking:
+ *	none.
+ * Remarks:
+ */
+
+static int
+kdb_per_cpu(int argc, const char **argv, const char **envp, struct pt_regs *regs)
+{
+	char buf[256], fmtstr[64];
+	kdb_symtab_t symtab;
+	cpumask_t suppress = CPU_MASK_NONE;
+	int cpu, diag;
+	unsigned long addr, val, bytesperword = 0, whichcpu = ~0UL;
+
+	if (argc < 1 || argc > 3)
+		return KDB_ARGCOUNT;
+
+	snprintf(buf, sizeof(buf), "per_cpu__%s", argv[1]);
+	if (!kdbgetsymval(buf, &symtab)) {
+		kdb_printf("%s is not a per_cpu variable\n", argv[1]);
+		return KDB_BADADDR;
+	}
+	if (argc >=2 && (diag = kdbgetularg(argv[2], &bytesperword)))
+		return diag;
+	if (!bytesperword)
+		bytesperword = sizeof(kdb_machreg_t);
+	else if (bytesperword > sizeof(kdb_machreg_t))
+		return KDB_BADWIDTH;
+	sprintf(fmtstr, "%%0%dlx ", (int)(2*bytesperword));
+	if (argc >= 3) {
+		if ((diag = kdbgetularg(argv[3], &whichcpu)))
+			return diag;
+		if (!cpu_online(whichcpu)) {
+			kdb_printf("cpu %ld is not online\n", whichcpu);
+			return KDB_BADCPUNUM;
+		}
+	}
+
+	/* Most architectures use __per_cpu_offset[cpu], some use
+	 * __per_cpu_offset(cpu), smp has no __per_cpu_offset.
+	 */
+#ifdef	__per_cpu_offset
+#define KDB_PCU(cpu) __per_cpu_offset(cpu)
+#else
+#ifdef	CONFIG_SMP
+#define KDB_PCU(cpu) __per_cpu_offset[cpu]
+#else
+#define KDB_PCU(cpu) 0
+#endif
+#endif
+
+	for_each_online_cpu(cpu) {
+		if (whichcpu != ~0UL && whichcpu != cpu)
+			continue;
+		addr = symtab.sym_start + KDB_PCU(cpu);
+		if ((diag = kdb_getword(&val, addr, bytesperword))) {
+			kdb_printf("%5d " kdb_bfd_vma_fmt0 " - unable to read, diag=%d\n",
+				cpu, addr, diag);
+			continue;
+		}
+#ifdef	CONFIG_SMP
+		if (!val) {
+			cpu_set(cpu, suppress);
+			continue;
+		}
+#endif	/* CONFIG_SMP */
+		kdb_printf("%5d ", cpu);
+		kdb_md_line(fmtstr, addr,
+			bytesperword == sizeof(kdb_machreg_t),
+			1, bytesperword, 1, 1);
+	}
+	if (cpus_weight(suppress) == 0)
+		return 0;
+	kdb_printf("Zero suppressed cpu(s):");
+	for (cpu = first_cpu(suppress); cpu < NR_CPUS; cpu = next_cpu(cpu, suppress)) {
+		kdb_printf(" %d", cpu);
+		if (cpu == NR_CPUS-1 || next_cpu(cpu, suppress) != cpu + 1)
+			continue;
+		while (cpu < NR_CPUS && next_cpu(cpu, suppress) == cpu + 1)
+			++cpu;
+		kdb_printf("-%d", cpu);
+	}
+	kdb_printf("\n");
+
+#undef KDB_PCU
+
+	return 0;
+}
+
 
 /*
  * kdb_register_repeat
@@ -3625,6 +3728,7 @@ kdb_inittab(void)
 	kdb_register_repeat("defcmd", kdb_defcmd, "name \"usage\" \"help\"", "Define a set of commands, down to endefcmd", 0, KDB_REPEAT_NONE);
 	kdb_register_repeat("kill", kdb_kill, "<-signal> <pid>", "Send a signal to a process", 0, KDB_REPEAT_NONE);
 	kdb_register_repeat("summary", kdb_summary, "", "Summarize the system", 4, KDB_REPEAT_NONE);
+	kdb_register_repeat("per_cpu", kdb_per_cpu, "", "Display per_cpu variables", 3, KDB_REPEAT_NONE);
 
 	/* Any kdb commands that are not in the base code but are required
 	 * earlier than normal initcall processing.
Index: linux/scripts/kallsyms.c
===================================================================
--- linux.orig/scripts/kallsyms.c	Fri Jun  4 14:02:29 2004
+++ linux/scripts/kallsyms.c	Fri Jun  4 15:45:59 2004
@@ -22,7 +22,7 @@ struct sym_entry {
 
 static struct sym_entry *table;
 static int size, cnt;
-static unsigned long long _stext, _etext, _sinittext, _einittext, _end;
+static unsigned long long _stext, _etext, _sinittext, _einittext, __per_cpu_end;
 #ifdef CONFIG_KDB
 #define kdb 1
 #else
@@ -57,7 +57,7 @@ read_symbol(FILE *in, struct sym_entry *
 static int
 symbol_valid(struct sym_entry *s)
 {
-	if ((s->addr < _stext || (kdb && s->addr > _end) || (!kdb && s->addr > _etext))
+	if ((s->addr < _stext || (kdb && s->addr > __per_cpu_end) || (!kdb && s->addr > _etext))
 	    && (s->addr < _sinittext || s->addr > _einittext))
 		return 0;
 
@@ -99,8 +99,8 @@ read_map(FILE *in)
 			_sinittext = table[i].addr;
 		if (strcmp(table[i].sym, "_einittext") == 0)
 			_einittext = table[i].addr;
-		if (kdb && strcmp(table[i].sym, "_end") == 0)
-			_end = table[i].addr;
+		if (kdb && strcmp(table[i].sym, "__per_cpu_end") == 0)
+			__per_cpu_end = table[i].addr;
 	}
 }
 


---------------------------
Use http://oss.sgi.com/ecartis to modify your settings or to unsubscribe.


More information about the kdb mailing list