Subject: [PATCH] add syslog printing to xmon debugger. From: Linas Vepstas 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 --- arch/powerpc/xmon/xmon.c | 57 +++++++++++++++++++++++++++++++++++++++++++++++ kernel/printk.c | 2 - 2 files changed, 58 insertions(+), 1 deletion(-) --- 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); @@ -197,6 +198,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\ @@ -831,6 +833,9 @@ cmds(struct pt_regs *excp) case 'd': dump(); break; + case 'D': + xmon_show_dmesg(); + break; case 'l': symbol_lookup(); break; @@ -2607,6 +2612,58 @@ static void xmon_print_symbol(unsigned l printf("%s", after); } +extern void kdb_syslog_data(char *syslog_data[]); +#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. + */ + kdb_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 @@ -416,7 +416,7 @@ SYSCALL_DEFINE3(syslog, int, type, char return do_syslog(type, buf, len, SYSLOG_FROM_CALL); } -#ifdef CONFIG_KGDB_KDB +#if defined(CONFIG_KGDB_KDB) || defined(CONFIG_DEBUG_KERNEL) /* kdb dmesg command needs access to the syslog buffer. do_syslog() * uses locks so it cannot be used during debugging. Just tell kdb * where the start and end of the physical and logical logs are. This