133 lines
3.6 KiB
Diff
133 lines
3.6 KiB
Diff
|
Subject: [PATCH] add syslog printing to xmon debugger.
|
||
|
From: Linas Vepstas <linas@austin.ibm.com>
|
||
|
Patch-mainline: Not yet
|
||
|
|
||
|
|
||
|
This patch 'dmesg'/printk log buffer printing to xmon. I find this
|
||
|
useful because crashes are almost always preceeded by interesting
|
||
|
printk's. This patch is simple & straightforward, except for one
|
||
|
possibly controversial aspect: it embeds a small snippet in
|
||
|
kernel/printk.c to return the location of the syslog. This is
|
||
|
needed because kallsyms and even CONFIG_KALLSYMS_ALL is not enough
|
||
|
to reveal the location of log_buf. This code is about 90%
|
||
|
cut-n-paste of earlier code from Keith Owens.
|
||
|
|
||
|
Signed-off-by: Olaf Hering <olh@suse.de>
|
||
|
---
|
||
|
|
||
|
arch/powerpc/xmon/xmon.c | 57 +++++++++++++++++++++++++++++++++++++++++++++++
|
||
|
kernel/printk.c | 15 ++++++++++++
|
||
|
2 files changed, 72 insertions(+)
|
||
|
|
||
|
--- a/arch/powerpc/xmon/xmon.c
|
||
|
+++ b/arch/powerpc/xmon/xmon.c
|
||
|
@@ -138,6 +138,7 @@ static struct bpt *in_breakpoint_table(u
|
||
|
static int do_step(struct pt_regs *);
|
||
|
static void bpt_cmds(void);
|
||
|
static void cacheflush(void);
|
||
|
+static void xmon_show_dmesg(void);
|
||
|
static int cpu_cmd(void);
|
||
|
static void csum(void);
|
||
|
static void bootcmds(void);
|
||
|
@@ -194,6 +195,7 @@ Commands:\n\
|
||
|
#endif
|
||
|
"\
|
||
|
C checksum\n\
|
||
|
+ D show dmesg (printk) buffer\n\
|
||
|
d dump bytes\n\
|
||
|
di dump instructions\n\
|
||
|
df dump float values\n\
|
||
|
@@ -828,6 +830,9 @@ cmds(struct pt_regs *excp)
|
||
|
case 'd':
|
||
|
dump();
|
||
|
break;
|
||
|
+ case 'D':
|
||
|
+ xmon_show_dmesg();
|
||
|
+ break;
|
||
|
case 'l':
|
||
|
symbol_lookup();
|
||
|
break;
|
||
|
@@ -2599,6 +2604,58 @@ static void xmon_print_symbol(unsigned l
|
||
|
printf("%s", after);
|
||
|
}
|
||
|
|
||
|
+extern void debugger_syslog_data(char *syslog_data[4]);
|
||
|
+#define SYSLOG_WRAP(p) if (p < syslog_data[0]) p = syslog_data[1]-1; \
|
||
|
+ else if (p >= syslog_data[1]) p = syslog_data[0];
|
||
|
+
|
||
|
+static void xmon_show_dmesg(void)
|
||
|
+{
|
||
|
+ char *syslog_data[4], *start, *end, c;
|
||
|
+ int logsize;
|
||
|
+
|
||
|
+ /* syslog_data[0,1] physical start, end+1.
|
||
|
+ * syslog_data[2,3] logical start, end+1.
|
||
|
+ */
|
||
|
+ debugger_syslog_data(syslog_data);
|
||
|
+ if (syslog_data[2] == syslog_data[3])
|
||
|
+ return;
|
||
|
+ logsize = syslog_data[1] - syslog_data[0];
|
||
|
+ start = syslog_data[0] + (syslog_data[2] - syslog_data[0]) % logsize;
|
||
|
+ end = syslog_data[0] + (syslog_data[3] - syslog_data[0]) % logsize;
|
||
|
+
|
||
|
+ /* Do a line at a time (max 200 chars) to reduce overhead */
|
||
|
+ c = '\0';
|
||
|
+ while(1) {
|
||
|
+ char *p;
|
||
|
+ int chars = 0;
|
||
|
+ if (!*start) {
|
||
|
+ while (!*start) {
|
||
|
+ ++start;
|
||
|
+ SYSLOG_WRAP(start);
|
||
|
+ if (start == end)
|
||
|
+ break;
|
||
|
+ }
|
||
|
+ if (start == end)
|
||
|
+ break;
|
||
|
+ }
|
||
|
+ p = start;
|
||
|
+ while (*start && chars < 200) {
|
||
|
+ c = *start;
|
||
|
+ ++chars;
|
||
|
+ ++start;
|
||
|
+ SYSLOG_WRAP(start);
|
||
|
+ if (start == end || c == '\n')
|
||
|
+ break;
|
||
|
+ }
|
||
|
+ if (chars)
|
||
|
+ printf("%.*s", chars, p);
|
||
|
+ if (start == end)
|
||
|
+ break;
|
||
|
+ }
|
||
|
+ if (c != '\n')
|
||
|
+ printf("\n");
|
||
|
+}
|
||
|
+
|
||
|
#ifdef CONFIG_PPC_BOOK3S_64
|
||
|
static void dump_slb(void)
|
||
|
{
|
||
|
--- a/kernel/printk.c
|
||
|
+++ b/kernel/printk.c
|
||
|
@@ -413,6 +413,21 @@ SYSCALL_DEFINE3(syslog, int, type, char
|
||
|
return do_syslog(type, buf, len, SYSLOG_FROM_CALL);
|
||
|
}
|
||
|
|
||
|
+#ifdef CONFIG_DEBUG_KERNEL
|
||
|
+/* Its very handy to be able to view the syslog buffer during debug.
|
||
|
+ * But do_syslog() uses locks so it cannot be used during debugging.
|
||
|
+ * Instead, provide the start and end of the physical and logical logs.
|
||
|
+ * This is equivalent to do_syslog(3).
|
||
|
+ */
|
||
|
+void debugger_syslog_data(char *syslog_data[4])
|
||
|
+{
|
||
|
+ syslog_data[0] = log_buf;
|
||
|
+ syslog_data[1] = log_buf + log_buf_len;
|
||
|
+ syslog_data[2] = log_buf + log_end - (logged_chars < log_buf_len ? logged_chars : log_buf_len);
|
||
|
+ syslog_data[3] = log_buf + log_end;
|
||
|
+}
|
||
|
+#endif /* CONFIG_DEBUG_KERNEL */
|
||
|
+
|
||
|
/*
|
||
|
* Call the console drivers on a range of log_buf
|
||
|
*/
|