more changes on original files
[linux-2.4.git] / arch / ppc64 / kernel / ppc-stub.c
1 /* 
2  * ppc-stub.c:  KGDB support for the Linux kernel.
3  *
4  * adapted from arch/sparc/kernel/sparc-stub.c for the PowerPC
5  * some stuff borrowed from Paul Mackerras' xmon
6  * Copyright (C) 1998 Michael AK Tesch (tesch@cs.wisc.edu)
7  *
8  * Modifications to run under Linux
9  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
10  *
11  * This file originally came from the gdb sources, and the
12  * copyright notices have been retained below.
13  */
14
15 /****************************************************************************
16
17                 THIS SOFTWARE IS NOT COPYRIGHTED
18
19    HP offers the following for use in the public domain.  HP makes no
20    warranty with regard to the software or its performance and the
21    user accepts the software "AS IS" with all faults.
22
23    HP DISCLAIMS ANY WARRANTIES, EXPRESS OR IMPLIED, WITH REGARD
24    TO THIS SOFTWARE INCLUDING BUT NOT LIMITED TO THE WARRANTIES
25    OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
26
27 ****************************************************************************/
28
29 /****************************************************************************
30  *  Header: remcom.c,v 1.34 91/03/09 12:29:49 glenne Exp $
31  *
32  *  Module name: remcom.c $
33  *  Revision: 1.34 $
34  *  Date: 91/03/09 12:29:49 $
35  *  Contributor:     Lake Stevens Instrument Division$
36  *
37  *  Description:     low level support for gdb debugger. $
38  *
39  *  Considerations:  only works on target hardware $
40  *
41  *  Written by:      Glenn Engel $
42  *  ModuleState:     Experimental $
43  *
44  *  NOTES:           See Below $
45  *
46  *  Modified for SPARC by Stu Grossman, Cygnus Support.
47  *
48  *  This code has been extensively tested on the Fujitsu SPARClite demo board.
49  *
50  *  To enable debugger support, two things need to happen.  One, a
51  *  call to set_debug_traps() is necessary in order to allow any breakpoints
52  *  or error conditions to be properly intercepted and reported to gdb.
53  *  Two, a breakpoint needs to be generated to begin communication.  This
54  *  is most easily accomplished by a call to breakpoint().  Breakpoint()
55  *  simulates a breakpoint by executing a trap #1.
56  *
57  *************
58  *
59  *    The following gdb commands are supported:
60  *
61  * command          function                               Return value
62  *
63  *    g             return the value of the CPU registers  hex data or ENN
64  *    G             set the value of the CPU registers     OK or ENN
65  *    qOffsets      Get section offsets.  Reply is Text=xxx;Data=yyy;Bss=zzz
66  *
67  *    mAA..AA,LLLL  Read LLLL bytes at address AA..AA      hex data or ENN
68  *    MAA..AA,LLLL: Write LLLL bytes at address AA.AA      OK or ENN
69  *
70  *    c             Resume at current address              SNN   ( signal NN)
71  *    cAA..AA       Continue at address AA..AA             SNN
72  *
73  *    s             Step one instruction                   SNN
74  *    sAA..AA       Step one instruction from AA..AA       SNN
75  *
76  *    k             kill
77  *
78  *    ?             What was the last sigval ?             SNN   (signal NN)
79  *
80  *    bBB..BB       Set baud rate to BB..BB                OK or BNN, then sets
81  *                                                         baud rate
82  *
83  * All commands and responses are sent with a packet which includes a
84  * checksum.  A packet consists of
85  *
86  * $<packet info>#<checksum>.
87  *
88  * where
89  * <packet info> :: <characters representing the command or response>
90  * <checksum>    :: <two hex digits computed as modulo 256 sum of <packetinfo>>
91  *
92  * When a packet is received, it is first acknowledged with either '+' or '-'.
93  * '+' indicates a successful transfer.  '-' indicates a failed transfer.
94  *
95  * Example:
96  *
97  * Host:                  Reply:
98  * $m0,10#2a               +$00010203040506070809101112131415#42
99  *
100  ****************************************************************************/
101
102 #include <linux/config.h>
103 #include <linux/kernel.h>
104 #include <linux/string.h>
105 #include <linux/mm.h>
106 #include <linux/smp.h>
107 #include <linux/smp_lock.h>
108
109 #include <asm/system.h>
110 #include <asm/signal.h>
111 #include <asm/kgdb.h>
112 #include <asm/pgtable.h>
113 #include <asm/ptrace.h>
114
115 void breakinst(void);
116
117 /*
118  * BUFMAX defines the maximum number of characters in inbound/outbound buffers
119  * at least NUMREGBYTES*2 are needed for register packets
120  */
121 #define BUFMAX 2048
122 static char remcomInBuffer[BUFMAX];
123 static char remcomOutBuffer[BUFMAX];
124
125 static int initialized = 0;
126 static int kgdb_active = 0;
127 static int kgdb_started = 0;
128 static u_int fault_jmp_buf[100];
129 static int kdebug;
130
131 static const char hexchars[]="0123456789abcdef";
132
133 /* Place where we save old trap entries for restoration - sparc*/
134 /* struct tt_entry kgdb_savettable[256]; */
135 /* typedef void (*trapfunc_t)(void); */
136
137 #if 0
138 /* Install an exception handler for kgdb */
139 static void exceptionHandler(int tnum, unsigned int *tfunc)
140 {
141         /* We are dorking with a live trap table, all irqs off */
142 }
143 #endif
144
145 int
146 kgdb_setjmp(long *buf)
147 {
148         asm ("mflr 0; stw 0,0(%0);"
149              "stw 1,4(%0); stw 2,8(%0);"
150              "mfcr 0; stw 0,12(%0);"
151              "stmw 13,16(%0)"
152              : : "r" (buf));
153         /* XXX should save fp regs as well */
154         return 0;
155 }
156 void
157 kgdb_longjmp(long *buf, int val)
158 {
159         if (val == 0)
160                 val = 1;
161         asm ("lmw 13,16(%0);"
162              "lwz 0,12(%0); mtcrf 0x38,0;"
163              "lwz 0,0(%0); lwz 1,4(%0); lwz 2,8(%0);"
164              "mtlr 0; mr 3,%1"
165              : : "r" (buf), "r" (val));
166 }
167 /* Convert ch from a hex digit to an int */
168 static int
169 hex(unsigned char ch)
170 {
171         if (ch >= 'a' && ch <= 'f')
172                 return ch-'a'+10;
173         if (ch >= '0' && ch <= '9')
174                 return ch-'0';
175         if (ch >= 'A' && ch <= 'F')
176                 return ch-'A'+10;
177         return -1;
178 }
179
180 /* Convert the memory pointed to by mem into hex, placing result in buf.
181  * Return a pointer to the last char put in buf (null), in case of mem fault,
182  * return 0.
183  */
184 static unsigned char *
185 mem2hex(char *mem, char *buf, int count)
186 {
187         unsigned char ch;
188
189         if (kgdb_setjmp((long*)fault_jmp_buf) == 0) {
190                 debugger_fault_handler = kgdb_fault_handler;
191                 while (count-- > 0) {
192                         ch = *mem++;
193                         *buf++ = hexchars[ch >> 4];
194                         *buf++ = hexchars[ch & 0xf];
195                 }
196         } else {
197                 /* error condition */
198         }
199         debugger_fault_handler = 0;
200         *buf = 0;
201         return buf;
202 }
203
204 /* convert the hex array pointed to by buf into binary to be placed in mem
205  * return a pointer to the character AFTER the last byte written.
206 */
207 static char *
208 hex2mem(char *buf, char *mem, int count)
209 {
210         int i;
211         unsigned char ch;
212
213         if (kgdb_setjmp((long*)fault_jmp_buf) == 0) {
214                 debugger_fault_handler = kgdb_fault_handler;
215                 for (i=0; i<count; i++) {
216                         ch = hex(*buf++) << 4;
217                         ch |= hex(*buf++);
218                         *mem++ = ch;
219                 }
220                 flush_icache_range((int)mem, (int)mem+count);
221         } else {
222                 /* error condition */
223         }
224         debugger_fault_handler = 0;
225         return mem;
226 }
227
228 /*
229  * While we find nice hex chars, build an int.
230  * Return number of chars processed.
231  */
232 static int
233 hexToInt(char **ptr, int *intValue)
234 {
235         int numChars = 0;
236         int hexValue;
237
238         *intValue = 0;
239
240         if (kgdb_setjmp((long*)fault_jmp_buf) == 0) {
241                 debugger_fault_handler = kgdb_fault_handler;
242                 while (**ptr) {
243                         hexValue = hex(**ptr);
244                         if (hexValue < 0)
245                                 break;
246
247                         *intValue = (*intValue << 4) | hexValue;
248                         numChars ++;
249
250                         (*ptr)++;
251                 }
252         } else {
253              /* error condition */
254         }
255         debugger_fault_handler = 0;
256
257         return (numChars);
258 }
259
260 /* scan for the sequence $<data>#<checksum>     */
261 static void
262 getpacket(char *buffer)
263 {
264         unsigned char checksum;
265         unsigned char xmitcsum;
266         int i;
267         int count;
268         unsigned char ch;
269
270         do {
271                 /* wait around for the start character, ignore all other
272                  * characters */
273                 while ((ch = (getDebugChar() & 0x7f)) != '$') ;
274
275                 checksum = 0;
276                 xmitcsum = -1;
277
278                 count = 0;
279
280                 /* now, read until a # or end of buffer is found */
281                 while (count < BUFMAX) {
282                         ch = getDebugChar() & 0x7f;
283                         if (ch == '#')
284                                 break;
285                         checksum = checksum + ch;
286                         buffer[count] = ch;
287                         count = count + 1;
288                 }
289
290                 if (count >= BUFMAX)
291                         continue;
292
293                 buffer[count] = 0;
294
295                 if (ch == '#') {
296                         xmitcsum = hex(getDebugChar() & 0x7f) << 4;
297                         xmitcsum |= hex(getDebugChar() & 0x7f);
298                         if (checksum != xmitcsum)
299                                 putDebugChar('-');      /* failed checksum */
300                         else {
301                                 putDebugChar('+'); /* successful transfer */
302                                 /* if a sequence char is present, reply the ID */
303                                 if (buffer[2] == ':') {
304                                         putDebugChar(buffer[0]);
305                                         putDebugChar(buffer[1]);
306                                         /* remove sequence chars from buffer */
307                                         count = strlen(buffer);
308                                         for (i=3; i <= count; i++)
309                                                 buffer[i-3] = buffer[i];
310                                 }
311                         }
312                 }
313         } while (checksum != xmitcsum);
314 }
315
316 /* send the packet in buffer.  */
317 static void putpacket(unsigned char *buffer)
318 {
319         unsigned char checksum;
320         int count;
321         unsigned char ch, recv;
322
323         /*  $<packet info>#<checksum>. */
324         do {
325                 putDebugChar('$');
326                 checksum = 0;
327                 count = 0;
328
329                 while ((ch = buffer[count])) {
330                         putDebugChar(ch);
331                         checksum += ch;
332                         count += 1;
333                 }
334
335                 putDebugChar('#');
336                 putDebugChar(hexchars[checksum >> 4]);
337                 putDebugChar(hexchars[checksum & 0xf]);
338                 recv = getDebugChar();
339         } while ((recv & 0x7f) != '+');
340 }
341
342 static void kgdb_flush_cache_all(void)
343 {
344         flush_instruction_cache();
345 }
346
347
348 /* Set up exception handlers for tracing and breakpoints
349  * [could be called kgdb_init()]
350  */
351 void set_debug_traps(void)
352 {
353 #if 0
354         unsigned char c;
355
356         save_and_cli(flags);
357
358         /* In case GDB is started before us, ack any packets (presumably
359          * "$?#xx") sitting there.
360          *
361          * I've found this code causes more problems than it solves,
362          * so that's why it's commented out.  GDB seems to work fine
363          * now starting either before or after the kernel   -bwb
364          */
365
366         while((c = getDebugChar()) != '$');
367         while((c = getDebugChar()) != '#');
368         c = getDebugChar(); /* eat first csum byte */
369         c = getDebugChar(); /* eat second csum byte */
370         putDebugChar('+'); /* ack it */
371 #endif
372         debugger = kgdb;
373         debugger_bpt = kgdb_bpt;
374         debugger_sstep = kgdb_sstep;
375         debugger_iabr_match = kgdb_iabr_match;
376         debugger_dabr_match = kgdb_dabr_match;
377
378         initialized = 1;
379 }
380
381 static void kgdb_fault_handler(struct pt_regs *regs)
382 {
383         kgdb_longjmp((long*)fault_jmp_buf, 1);
384 }
385
386 int kgdb_bpt(struct pt_regs *regs)
387 {
388         handle_exception(regs);
389         return 1;
390 }
391
392 int kgdb_sstep(struct pt_regs *regs)
393 {
394         handle_exception(regs);
395         return 1;
396 }
397
398 void kgdb(struct pt_regs *regs)
399 {
400         handle_exception(regs);
401 }
402
403 int kgdb_iabr_match(struct pt_regs *regs)
404 {
405         printk("kgdb doesn't support iabr, what?!?\n");
406         handle_exception(regs);
407         return 1;
408 }
409
410 int kgdb_dabr_match(struct pt_regs *regs)
411 {
412         printk("kgdb doesn't support dabr, what?!?\n");
413         handle_exception(regs);
414         return 1;
415 }
416
417 /* Convert the SPARC hardware trap type code to a unix signal number. */
418 /*
419  * This table contains the mapping between PowerPC hardware trap types, and
420  * signals, which are primarily what GDB understands.
421  */
422 static struct hard_trap_info
423 {
424         unsigned int tt;                /* Trap type code for powerpc */
425         unsigned char signo;            /* Signal that we map this trap into */
426 } hard_trap_info[] = {
427         { 0x200, SIGSEGV },                     /* machine check */
428         { 0x300, SIGSEGV },                     /* address error (store) */
429         { 0x400, SIGBUS },                      /* instruction bus error */
430         { 0x500, SIGINT },                      /* interrupt */
431         { 0x600, SIGBUS },                      /* alingment */
432         { 0x700, SIGTRAP },                     /* breakpoint trap */
433         { 0x800, SIGFPE },                      /* fpu unavail */
434         { 0x900, SIGALRM },                     /* decrementer */
435         { 0xa00, SIGILL },                      /* reserved */
436         { 0xb00, SIGILL },                      /* reserved */
437         { 0xc00, SIGCHLD },                     /* syscall */
438         { 0xd00, SIGTRAP },                     /* single-step/watch */
439         { 0xe00, SIGFPE },                      /* fp assist */
440         { 0, 0}                         /* Must be last */
441 };
442
443 static int computeSignal(unsigned int tt)
444 {
445         struct hard_trap_info *ht;
446
447         for (ht = hard_trap_info; ht->tt && ht->signo; ht++)
448                 if (ht->tt == tt)
449                         return ht->signo;
450
451         return SIGHUP;         /* default for things we don't know about */
452 }
453
454 #define PC_REGNUM 64
455 #define SP_REGNUM 1
456
457 /*
458  * This function does all command processing for interfacing to gdb.
459  */
460 static void
461 handle_exception (struct pt_regs *regs)
462 {
463         int sigval;
464         int addr;
465         int length;
466         char *ptr;
467         unsigned long msr;
468
469         if (debugger_fault_handler) {
470                 debugger_fault_handler(regs);
471                 panic("kgdb longjump failed!\n");
472         }
473         if (kgdb_active) {
474                 printk("interrupt while in kgdb, returning\n");
475                 return;
476         }
477         kgdb_active = 1;
478         kgdb_started = 1;
479
480 #ifdef KGDB_DEBUG
481         printk("kgdb: entering handle_exception; trap [0x%x]\n",
482                (unsigned int)regs->trap);
483 #endif
484
485         kgdb_interruptible(0);
486         lock_kernel();
487         msr = get_msr();
488         set_msr(msr & ~MSR_EE); /* disable interrupts */
489
490         if (regs->nip == (unsigned long)breakinst) {
491                 /* Skip over breakpoint trap insn */
492                 regs->nip += 4;
493         }
494
495         /* reply to host that an exception has occurred */
496         sigval = computeSignal(regs->trap);
497         ptr = remcomOutBuffer;
498
499 #if 0
500         *ptr++ = 'S';
501         *ptr++ = hexchars[sigval >> 4];
502         *ptr++ = hexchars[sigval & 0xf];
503 #else
504         *ptr++ = 'T';
505         *ptr++ = hexchars[sigval >> 4];
506         *ptr++ = hexchars[sigval & 0xf];
507         *ptr++ = hexchars[PC_REGNUM >> 4];
508         *ptr++ = hexchars[PC_REGNUM & 0xf];
509         *ptr++ = ':';
510         ptr = mem2hex((char *)&regs->nip, ptr, 4);
511         *ptr++ = ';';
512         *ptr++ = hexchars[SP_REGNUM >> 4];
513         *ptr++ = hexchars[SP_REGNUM & 0xf];
514         *ptr++ = ':';
515         ptr = mem2hex(((char *)&regs) + SP_REGNUM*4, ptr, 4);
516         *ptr++ = ';';
517 #endif
518
519         *ptr++ = 0;
520
521         putpacket(remcomOutBuffer);
522
523         /* XXX We may want to add some features dealing with poking the
524          * XXX page tables, ... (look at sparc-stub.c for more info)
525          * XXX also required hacking to the gdb sources directly...
526          */
527
528         while (1) {
529                 remcomOutBuffer[0] = 0;
530
531                 getpacket(remcomInBuffer);
532                 switch (remcomInBuffer[0]) {
533                 case '?':               /* report most recent signal */
534                         remcomOutBuffer[0] = 'S';
535                         remcomOutBuffer[1] = hexchars[sigval >> 4];
536                         remcomOutBuffer[2] = hexchars[sigval & 0xf];
537                         remcomOutBuffer[3] = 0;
538                         break;
539 #if 0
540                 case 'q': /* this screws up gdb for some reason...*/
541                 {
542                         extern long _start, sdata, __bss_start;
543
544                         ptr = &remcomInBuffer[1];
545                         if (strncmp(ptr, "Offsets", 7) != 0)
546                                 break;
547
548                         ptr = remcomOutBuffer;
549                         sprintf(ptr, "Text=%8.8x;Data=%8.8x;Bss=%8.8x",
550                                 &_start, &sdata, &__bss_start);
551                         break;
552                 }
553 #endif
554                 case 'd':
555                         /* toggle debug flag */
556                         kdebug ^= 1;
557                         break;
558
559                 case 'g':       /* return the value of the CPU registers.
560                                  * some of them are non-PowerPC names :(
561                                  * they are stored in gdb like:
562                                  * struct {
563                                  *     u32 gpr[32];
564                                  *     f64 fpr[32];
565                                  *     u32 pc, ps, cnd, lr; (ps=msr)
566                                  *     u32 cnt, xer, mq;
567                                  * }
568                                  */
569                 {
570                         int i;
571                         ptr = remcomOutBuffer;
572                         /* General Purpose Regs */
573                         ptr = mem2hex((char *)regs, ptr, 32 * 4);
574                         /* Floating Point Regs - FIXME */
575                         /*ptr = mem2hex((char *), ptr, 32 * 8);*/
576                         for(i=0; i<(32*8*2); i++) { /* 2chars/byte */
577                                 ptr[i] = '0';
578                         }
579                         ptr += 32*8*2;
580                         /* pc, msr, cr, lr, ctr, xer, (mq is unused) */
581                         ptr = mem2hex((char *)&regs->nip, ptr, 4);
582                         ptr = mem2hex((char *)&regs->msr, ptr, 4);
583                         ptr = mem2hex((char *)&regs->ccr, ptr, 4);
584                         ptr = mem2hex((char *)&regs->link, ptr, 4);
585                         ptr = mem2hex((char *)&regs->ctr, ptr, 4);
586                         ptr = mem2hex((char *)&regs->xer, ptr, 4);
587                 }
588                         break;
589
590                 case 'G':   /* set the value of the CPU registers */
591                 {
592                         ptr = &remcomInBuffer[1];
593
594                         /*
595                          * If the stack pointer has moved, you should pray.
596                          * (cause only god can help you).
597                          */
598
599                         /* General Purpose Regs */
600                         hex2mem(ptr, (char *)regs, 32 * 4);
601
602                         /* Floating Point Regs - FIXME?? */
603                         /*ptr = hex2mem(ptr, ??, 32 * 8);*/
604                         ptr += 32*8*2;
605
606                         /* pc, msr, cr, lr, ctr, xer, (mq is unused) */
607                         ptr = hex2mem(ptr, (char *)&regs->nip, 4);
608                         ptr = hex2mem(ptr, (char *)&regs->msr, 4);
609                         ptr = hex2mem(ptr, (char *)&regs->ccr, 4);
610                         ptr = hex2mem(ptr, (char *)&regs->link, 4);
611                         ptr = hex2mem(ptr, (char *)&regs->ctr, 4);
612                         ptr = hex2mem(ptr, (char *)&regs->xer, 4);
613
614                         strcpy(remcomOutBuffer,"OK");
615                 }
616                         break;
617                 case 'H':
618                         /* don't do anything, yet, just acknowledge */
619                         hexToInt(&ptr, &addr);
620                         strcpy(remcomOutBuffer,"OK");
621                         break;
622
623                 case 'm':       /* mAA..AA,LLLL  Read LLLL bytes at address AA..AA */
624                                 /* Try to read %x,%x.  */
625
626                         ptr = &remcomInBuffer[1];
627
628                         if (hexToInt(&ptr, &addr)
629                             && *ptr++ == ','
630                             && hexToInt(&ptr, &length)) {
631                                 if (mem2hex((char *)addr, remcomOutBuffer,length))
632                                         break;
633                                 strcpy (remcomOutBuffer, "E03");
634                         } else {
635                                 strcpy(remcomOutBuffer,"E01");
636                         }
637                         break;
638
639                 case 'M': /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */
640                         /* Try to read '%x,%x:'.  */
641
642                         ptr = &remcomInBuffer[1];
643
644                         if (hexToInt(&ptr, &addr)
645                             && *ptr++ == ','
646                             && hexToInt(&ptr, &length)
647                             && *ptr++ == ':') {
648                                 if (hex2mem(ptr, (char *)addr, length)) {
649                                         strcpy(remcomOutBuffer, "OK");
650                                 } else {
651                                         strcpy(remcomOutBuffer, "E03");
652                                 }
653                                 flush_icache_range(addr, addr+length);
654                         } else {
655                                 strcpy(remcomOutBuffer, "E02");
656                         }
657                         break;
658
659
660                 case 'k':    /* kill the program, actually just continue */
661                 case 'c':    /* cAA..AA  Continue; address AA..AA optional */
662                         /* try to read optional parameter, pc unchanged if no parm */
663
664                         ptr = &remcomInBuffer[1];
665                         if (hexToInt(&ptr, &addr)) {
666                                 regs->nip = addr;
667                         }
668
669 /* Need to flush the instruction cache here, as we may have deposited a
670  * breakpoint, and the icache probably has no way of knowing that a data ref to
671  * some location may have changed something that is in the instruction cache.
672  */
673                         kgdb_flush_cache_all();
674                         set_msr(msr);
675                         kgdb_interruptible(1);
676                         unlock_kernel();
677                         kgdb_active = 0;
678                         return;
679
680                 case 's':
681                         kgdb_flush_cache_all();
682                         regs->msr |= MSR_SE;
683 #if 0
684                         set_msr(msr | MSR_SE);
685 #endif
686                         unlock_kernel();
687                         kgdb_active = 0;
688                         return;
689
690                 case 'r':               /* Reset (if user process..exit ???)*/
691                         panic("kgdb reset.");
692                         break;
693                 }                       /* switch */
694                 if (remcomOutBuffer[0] && kdebug) {
695                         printk("remcomInBuffer: %s\n", remcomInBuffer);
696                         printk("remcomOutBuffer: %s\n", remcomOutBuffer);
697                 }
698                 /* reply to the request */
699                 putpacket(remcomOutBuffer);
700         } /* while(1) */
701 }
702
703 /* This function will generate a breakpoint exception.  It is used at the
704    beginning of a program to sync up with a debugger and can be used
705    otherwise as a quick means to stop program execution and "break" into
706    the debugger. */
707
708 void
709 breakpoint(void)
710 {
711         if (!initialized) {
712                 printk("breakpoint() called b4 kgdb init\n");
713                 return;
714         }
715
716         asm("   .globl breakinst
717              breakinst: .long 0x7d821008
718             ");
719 }
720
721 /* Output string in GDB O-packet format if GDB has connected. If nothing
722    output, returns 0 (caller must then handle output). */
723 int
724 kgdb_output_string (const char* s, unsigned int count)
725 {
726         char buffer[512];
727
728         if (!kgdb_started)
729             return 0;
730
731         count = (count <= (sizeof(buffer) / 2 - 2)) 
732                 ? count : (sizeof(buffer) / 2 - 2);
733
734         buffer[0] = 'O';
735         mem2hex (s, &buffer[1], count);
736         putpacket(buffer);
737
738         return 1;
739  }