ia64/xen-unstable

view xen/arch/x86/cdb.c @ 5276:c1a4141f0cdc

bitkeeper revision 1.1641 (429f3b38tjTPpWx1UAEWtuvYiFH0Qw)

serial.h needs spinlock.h

Signed-off-by: Vincent Hanquez <vincent@xensource.com>
author vh249@arcadians.cl.cam.ac.uk
date Thu Jun 02 17:00:40 2005 +0000 (2005-06-02)
parents 4c63d91b687f
children da199897c714
line source
1 /* Simple hacked-up version of pdb for use in post-mortem debugging of
2 Xen and domain 0. This should be a little cleaner, hopefully. Note
3 that we can't share a serial line with PDB. */
4 /* We try to avoid assuming much about what the rest of the system is
5 doing. In particular, dynamic memory allocation is out of the
6 question. */
7 /* Resuming after we've stopped used to work, but more through luck
8 than any actual intention. It doesn't at the moment. */
9 #include <xen/lib.h>
10 #include <asm/uaccess.h>
11 #include <xen/spinlock.h>
12 #include <xen/serial.h>
13 #include <xen/irq.h>
14 #include <asm/debugger.h>
15 #include <xen/init.h>
16 #include <xen/smp.h>
17 #include <asm/apic.h>
19 /* Printk isn't particularly safe just after we've trapped to the
20 debugger. so avoid it. */
21 #define dbg_printk(...)
23 static unsigned char opt_cdb[30] = "none";
24 string_param("cdb", opt_cdb);
26 struct xendbg_context {
27 int serhnd;
28 u8 reply_csum;
29 int currently_attached:1;
30 };
32 /* Like copy_from_user, but safe to call with interrupts disabled.
34 Trust me, and don't look behind the curtain. */
35 static unsigned
36 dbg_copy_from_user(void *dest, const void *src, unsigned len)
37 {
38 int __d0, __d1, __d2;
39 ASSERT(!local_irq_is_enabled());
40 __asm__ __volatile__(
41 "1: rep; movsb\n"
42 "2:\n"
43 ".section .fixup,\"ax\"\n"
44 "3: addl $4, %%esp\n"
45 " jmp 2b\n"
46 ".previous\n"
47 ".section __pre_ex_table,\"a\"\n"
48 " .align 4\n"
49 " .long 1b,3b\n"
50 ".previous\n"
51 ".section __ex_table,\"a\"\n"
52 " .align 4\n"
53 " .long 1b,2b\n"
54 ".previous\n"
55 : "=c"(__d2), "=D" (__d0), "=S" (__d1)
56 : "0"(len), "1"(dest), "2"(src)
57 : "memory");
58 ASSERT(!local_irq_is_enabled());
59 return __d2;
60 }
62 static void
63 xendbg_put_char(u8 data, struct xendbg_context *ctx)
64 {
65 ctx->reply_csum += data;
66 serial_putc(ctx->serhnd, data);
67 }
69 static int
70 hex_char_val(unsigned char c)
71 {
72 if (c >= '0' && c <= '9')
73 return c - '0';
74 else if (c >= 'a' && c <= 'f')
75 return c - 'a' + 10;
76 else if (c >= 'A' && c <= 'F')
77 return c - 'A' + 10;
78 else
79 BUG();
80 return -1;
81 }
83 /* Receive a command. Returns -1 on csum error, 0 otherwise. */
84 /* Does not acknowledge. */
85 static int
86 attempt_receive_packet(char *recv_buf, struct xendbg_context *ctx)
87 {
88 int count;
89 u8 csum;
90 u8 received_csum;
91 u8 ch;
93 /* Skip over everything up to the first '$' */
94 while ((ch = serial_getc(ctx->serhnd)) != '$')
95 ;
96 csum = 0;
97 for (count = 0; count < 4096; count++) {
98 ch = serial_getc(ctx->serhnd);
99 if (ch == '#')
100 break;
101 recv_buf[count] = ch;
102 csum += ch;
103 }
104 if (count == 4096) {
105 dbg_printk("WARNING: GDB sent a stupidly big packet.\n");
106 return -1;
107 }
108 recv_buf[count] = 0;
109 received_csum = hex_char_val(serial_getc(ctx->serhnd)) * 16 +
110 hex_char_val(serial_getc(ctx->serhnd));
111 if (received_csum == csum) {
112 return 0;
113 } else {
114 return -1;
115 }
116 }
118 /* Send a string of bytes to the debugger. */
119 static void
120 xendbg_send(const char *buf, int count, struct xendbg_context *ctx)
121 {
122 int x;
123 for (x = 0; x < count; x++)
124 xendbg_put_char(buf[x], ctx);
125 }
127 /* Receive a command, discarding up to ten packets with csum
128 * errors. Acknowledges all received packets. */
129 static int
130 receive_command(char *recv_buf, struct xendbg_context *ctx)
131 {
132 int r;
133 int count;
135 count = 0;
136 do {
137 r = attempt_receive_packet(recv_buf, ctx);
138 if (r < 0)
139 xendbg_put_char('-', ctx);
140 else
141 xendbg_put_char('+', ctx);
142 count++;
143 } while (r < 0 && count < 10);
144 return r;
145 }
147 static void
148 xendbg_start_reply(struct xendbg_context *ctx)
149 {
150 xendbg_put_char('$', ctx);
151 ctx->reply_csum = 0;
152 }
154 /* Return 0 if the reply was successfully received, !0 otherwise. */
155 static int
156 xendbg_finish_reply(struct xendbg_context *ctx)
157 {
158 char ch;
159 char buf[3];
161 sprintf(buf, "%.02x\n", ctx->reply_csum);
163 xendbg_put_char('#', ctx);
164 xendbg_send(buf, 2, ctx);
166 ch = serial_getc(ctx->serhnd);
167 if (ch == '+')
168 return 0;
169 else
170 return 1;
171 }
173 /* Swap the order of the bytes in a work. */
174 static inline unsigned
175 bswab32(unsigned val)
176 {
177 return (((val >> 0) & 0xff) << 24) |
178 (((val >> 8) & 0xff) << 16) |
179 (((val >> 16) & 0xff) << 8) |
180 (((val >> 24) & 0xff) << 0);
181 }
183 static int
184 handle_memory_read_command(unsigned long addr, unsigned long length,
185 struct xendbg_context *ctx)
186 {
187 int x;
188 unsigned char val;
189 int r;
190 char buf[2];
192 dbg_printk("Memory read starting at %lx, length %lx.\n", addr,
193 length);
194 xendbg_start_reply(ctx);
195 for (x = 0; x < length; x++) {
196 r = dbg_copy_from_user(&val, (void *)(addr + x), 1);
197 if (r != 0) {
198 dbg_printk("Error reading from %lx.\n", addr + x);
199 break;
200 }
201 sprintf(buf, "%.02x", val);
202 xendbg_send(buf, 2, ctx);
203 }
204 if (x == 0)
205 xendbg_send("E05", 3, ctx);
206 dbg_printk("Read done.\n");
207 return xendbg_finish_reply(ctx);
208 }
210 static int
211 xendbg_send_reply(const char *buf, struct xendbg_context *ctx)
212 {
213 xendbg_start_reply(ctx);
214 xendbg_send(buf, strlen(buf), ctx);
215 return xendbg_finish_reply(ctx);
216 }
218 static int
219 handle_register_read_command(struct cpu_user_regs *regs, struct xendbg_context *ctx)
220 {
221 char buf[121];
223 sprintf(buf,
224 "%.08x%.08x%.08x%.08x%.08x%.08x%.08x%.08x%.08x%.08x%.08x%.08x%.08x%.08x%.08x%.08x",
225 bswab32(regs->eax),
226 bswab32(regs->ecx),
227 bswab32(regs->edx),
228 bswab32(regs->ebx),
229 bswab32(regs->esp),
230 bswab32(regs->ebp),
231 bswab32(regs->esi),
232 bswab32(regs->edi),
233 bswab32(regs->eip),
234 bswab32(regs->eflags),
235 bswab32(regs->cs),
236 bswab32(regs->ss),
237 bswab32(regs->ds),
238 bswab32(regs->es),
239 bswab32(regs->fs),
240 bswab32(regs->gs));
241 return xendbg_send_reply(buf, ctx);
242 }
244 static int
245 process_command(char *received_packet, struct cpu_user_regs *regs,
246 struct xendbg_context *ctx)
247 {
248 char *ptr;
249 unsigned long addr, length;
250 int retry;
251 int counter;
252 int resume = 0;
254 /* Repeat until gdb acks the reply */
255 counter = 0;
256 do {
257 switch (received_packet[0]) {
258 case 'g': /* Read registers */
259 retry = handle_register_read_command(regs, ctx);
260 ASSERT(!local_irq_is_enabled());
261 break;
262 case 'm': /* Read memory */
263 addr = simple_strtoul(received_packet + 1, &ptr, 16);
264 if (ptr == received_packet + 1 ||
265 ptr[0] != ',') {
266 xendbg_send_reply("E03", ctx);
267 return 0;
268 }
269 length = simple_strtoul(ptr + 1, &ptr, 16);
270 if (ptr[0] != 0) {
271 xendbg_send_reply("E04", ctx);
272 return 0;
273 }
274 retry =
275 handle_memory_read_command(addr,
276 length,
277 ctx);
278 ASSERT(!local_irq_is_enabled());
279 break;
280 case 'G': /* Write registers */
281 case 'M': /* Write memory */
282 retry = xendbg_send_reply("E02", ctx);
283 break;
284 case 'D':
285 resume = 1;
286 ctx->currently_attached = 0;
287 retry = xendbg_send_reply("", ctx);
288 break;
289 case 'c': /* Resume at current address */
290 ctx->currently_attached = 1;
291 resume = 1;
292 retry = 0;
293 break;
294 case 'Z': /* We need to claim to support these or gdb
295 won't let you continue the process. */
296 case 'z':
297 retry = xendbg_send_reply("OK", ctx);
298 break;
300 case 's': /* Single step */
301 case '?':
302 retry = xendbg_send_reply("S01", ctx);
303 break;
304 default:
305 retry = xendbg_send_reply("", ctx);
306 break;
307 }
308 counter++;
309 } while (retry == 1 && counter < 10);
310 if (retry) {
311 dbg_printk("WARNING: gdb disappeared when we were trying to send it a reply.\n");
312 return 1;
313 }
314 return resume;
315 }
317 static struct xendbg_context
318 xdb_ctx = {
319 serhnd : -1
320 };
322 int
323 __trap_to_cdb(struct cpu_user_regs *regs)
324 {
325 int resume = 0;
326 int r;
327 static atomic_t xendbg_running = ATOMIC_INIT(1);
328 static char recv_buf[4096];
329 unsigned flags;
331 if (xdb_ctx.serhnd < 0) {
332 dbg_printk("Debugger not ready yet.\n");
333 return 0;
334 }
336 /* We rely on our caller to ensure we're only on one processor
337 * at a time... We should probably panic here, but given that
338 * we're a debugger we should probably be a little tolerant of
339 * things going wrong. */
340 /* We don't want to use a spin lock here, because we're doing
341 two distinct things:
343 1 -- we don't want to run on more than one processor at a time,
344 and
345 2 -- we want to do something sensible if we re-enter ourselves.
347 Spin locks are good for 1, but useless for 2. */
348 if (!atomic_dec_and_test(&xendbg_running)) {
349 printk("WARNING WARNING WARNING: Avoiding recursive xendbg.\n");
350 atomic_inc(&xendbg_running);
351 return 0;
352 }
354 smp_send_stop();
356 /* Try to make things a little more stable by disabling
357 interrupts while we're here. */
358 local_irq_save(flags);
360 watchdog_disable();
362 /* Shouldn't really do this, but otherwise we stop for no
363 obvious reason, which is Bad */
364 printk("Waiting for GDB to attach to XenDBG\n");
366 /* If gdb is already attached, tell it we've stopped again. */
367 if (xdb_ctx.currently_attached) {
368 do {
369 r = xendbg_send_reply("S01", &xdb_ctx);
370 } while (r != 0);
371 }
373 while (resume == 0) {
374 ASSERT(!local_irq_is_enabled());
375 r = receive_command(recv_buf, &xdb_ctx);
376 ASSERT(!local_irq_is_enabled());
377 if (r < 0) {
378 dbg_printk("GDB disappeared, trying to resume Xen...\n");
379 resume = 1;
380 } else {
381 ASSERT(!local_irq_is_enabled());
382 resume = process_command(recv_buf, regs, &xdb_ctx);
383 ASSERT(!local_irq_is_enabled());
384 }
385 }
386 watchdog_enable();
387 atomic_inc(&xendbg_running);
388 local_irq_restore(flags);
389 return 0;
390 }
392 static int
393 initialize_xendbg(void)
394 {
395 if (!strcmp(opt_cdb, "none"))
396 return 0;
397 xdb_ctx.serhnd = serial_parse_handle(opt_cdb);
398 if (xdb_ctx.serhnd == -1)
399 panic("Can't parse %s as CDB serial info.\n", opt_cdb);
401 /* Acknowledge any spurious GDB packets. */
402 xendbg_put_char('+', &xdb_ctx);
404 printk("Xendbg initialised.\n");
405 return 0;
406 }
408 __initcall(initialize_xendbg);