]>
Commit | Line | Data |
---|---|---|
2cb7cef9 BS |
1 | Subject: [PATCH] add syslog printing to xmon debugger. |
2 | From: Linas Vepstas <linas@austin.ibm.com> | |
3 | ||
4 | ||
5 | This patch 'dmesg'/printk log buffer printing to xmon. I find this | |
6 | useful because crashes are almost always preceeded by interesting | |
7 | printk's. This patch is simple & straightforward, except for one | |
8 | possibly controversial aspect: it embeds a small snippet in | |
9 | kernel/printk.c to return the location of the syslog. This is | |
10 | needed because kallsyms and even CONFIG_KALLSYMS_ALL is not enough | |
11 | to reveal the location of log_buf. This code is about 90% | |
12 | cut-n-paste of earlier code from Keith Owens. | |
13 | ||
14 | Signed-off-by: Olaf Hering <olh@suse.de> | |
15 | ||
16 | arch/powerpc/xmon/xmon.c | 57 +++++++++++++++++++++++++++++++++++++++++++++++ | |
17 | kernel/printk.c | 15 ++++++++++++ | |
18 | 2 files changed, 72 insertions(+) | |
19 | ||
20 | --- a/arch/powerpc/xmon/xmon.c | |
21 | +++ b/arch/powerpc/xmon/xmon.c | |
22 | @@ -136,6 +136,7 @@ static struct bpt *in_breakpoint_table(u | |
23 | static int do_step(struct pt_regs *); | |
24 | static void bpt_cmds(void); | |
25 | static void cacheflush(void); | |
26 | +static void xmon_show_dmesg(void); | |
27 | static int cpu_cmd(void); | |
28 | static void csum(void); | |
29 | static void bootcmds(void); | |
30 | @@ -194,6 +195,7 @@ Commands:\n\ | |
31 | #endif | |
32 | "\ | |
33 | C checksum\n\ | |
34 | + D show dmesg (printk) buffer\n\ | |
35 | d dump bytes\n\ | |
36 | di dump instructions\n\ | |
37 | df dump float values\n\ | |
38 | @@ -808,6 +810,9 @@ cmds(struct pt_regs *excp) | |
39 | case 'd': | |
40 | dump(); | |
41 | break; | |
42 | + case 'D': | |
43 | + xmon_show_dmesg(); | |
44 | + break; | |
45 | case 'l': | |
46 | symbol_lookup(); | |
47 | break; | |
48 | @@ -2522,6 +2527,58 @@ static void xmon_print_symbol(unsigned l | |
49 | printf("%s", after); | |
50 | } | |
51 | ||
52 | +extern void debugger_syslog_data(char *syslog_data[4]); | |
53 | +#define SYSLOG_WRAP(p) if (p < syslog_data[0]) p = syslog_data[1]-1; \ | |
54 | + else if (p >= syslog_data[1]) p = syslog_data[0]; | |
55 | + | |
56 | +static void xmon_show_dmesg(void) | |
57 | +{ | |
58 | + char *syslog_data[4], *start, *end, c; | |
59 | + int logsize; | |
60 | + | |
61 | + /* syslog_data[0,1] physical start, end+1. | |
62 | + * syslog_data[2,3] logical start, end+1. | |
63 | + */ | |
64 | + debugger_syslog_data(syslog_data); | |
65 | + if (syslog_data[2] == syslog_data[3]) | |
66 | + return; | |
67 | + logsize = syslog_data[1] - syslog_data[0]; | |
68 | + start = syslog_data[0] + (syslog_data[2] - syslog_data[0]) % logsize; | |
69 | + end = syslog_data[0] + (syslog_data[3] - syslog_data[0]) % logsize; | |
70 | + | |
71 | + /* Do a line at a time (max 200 chars) to reduce overhead */ | |
72 | + c = '\0'; | |
73 | + while(1) { | |
74 | + char *p; | |
75 | + int chars = 0; | |
76 | + if (!*start) { | |
77 | + while (!*start) { | |
78 | + ++start; | |
79 | + SYSLOG_WRAP(start); | |
80 | + if (start == end) | |
81 | + break; | |
82 | + } | |
83 | + if (start == end) | |
84 | + break; | |
85 | + } | |
86 | + p = start; | |
87 | + while (*start && chars < 200) { | |
88 | + c = *start; | |
89 | + ++chars; | |
90 | + ++start; | |
91 | + SYSLOG_WRAP(start); | |
92 | + if (start == end || c == '\n') | |
93 | + break; | |
94 | + } | |
95 | + if (chars) | |
96 | + printf("%.*s", chars, p); | |
97 | + if (start == end) | |
98 | + break; | |
99 | + } | |
100 | + if (c != '\n') | |
101 | + printf("\n"); | |
102 | +} | |
103 | + | |
104 | #ifdef CONFIG_PPC64 | |
105 | static void dump_slb(void) | |
106 | { | |
107 | --- a/kernel/printk.c | |
108 | +++ b/kernel/printk.c | |
109 | @@ -426,6 +426,21 @@ asmlinkage long sys_syslog(int type, cha | |
110 | return do_syslog(type, buf, len); | |
111 | } | |
112 | ||
113 | +#ifdef CONFIG_DEBUG_KERNEL | |
114 | +/* Its very handy to be able to view the syslog buffer during debug. | |
115 | + * But do_syslog() uses locks so it cannot be used during debugging. | |
116 | + * Instead, provide the start and end of the physical and logical logs. | |
117 | + * This is equivalent to do_syslog(3). | |
118 | + */ | |
119 | +void debugger_syslog_data(char *syslog_data[4]) | |
120 | +{ | |
121 | + syslog_data[0] = log_buf; | |
122 | + syslog_data[1] = log_buf + log_buf_len; | |
123 | + syslog_data[2] = log_buf + log_end - (logged_chars < log_buf_len ? logged_chars : log_buf_len); | |
124 | + syslog_data[3] = log_buf + log_end; | |
125 | +} | |
126 | +#endif /* CONFIG_DEBUG_KERNEL */ | |
127 | + | |
128 | /* | |
129 | * Call the console drivers on a range of log_buf | |
130 | */ |