direct-io.hg

view xen/arch/x86/cdb.c @ 3787:13fe6a361bc3

bitkeeper revision 1.1179 (420c8b725LGvAqm86f8YBLnAnaHPvQ)

Fixup the fixup code a little.

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