**** start-sanitize-chill ****
[deliverable/binutils-gdb.git] / gdb / sparc-stub.c
1 /****************************************************************************
2
3 THIS SOFTWARE IS NOT COPYRIGHTED
4
5 HP offers the following for use in the public domain. HP makes no
6 warranty with regard to the software or it's performance and the
7 user accepts the software "AS IS" with all faults.
8
9 HP DISCLAIMS ANY WARRANTIES, EXPRESS OR IMPLIED, WITH REGARD
10 TO THIS SOFTWARE INCLUDING BUT NOT LIMITED TO THE WARRANTIES
11 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
12
13 ****************************************************************************/
14
15 /****************************************************************************
16 * Header: remcom.c,v 1.34 91/03/09 12:29:49 glenne Exp $
17 *
18 * Module name: remcom.c $
19 * Revision: 1.34 $
20 * Date: 91/03/09 12:29:49 $
21 * Contributor: Lake Stevens Instrument Division$
22 *
23 * Description: low level support for gdb debugger. $
24 *
25 * Considerations: only works on target hardware $
26 *
27 * Written by: Glenn Engel $
28 * ModuleState: Experimental $
29 *
30 * NOTES: See Below $
31 *
32 * Modified for SPARC by Stu Grossman, Cygnus Support.
33 *
34 * To enable debugger support, two things need to happen. One, a
35 * call to set_debug_traps() is necessary in order to allow any breakpoints
36 * or error conditions to be properly intercepted and reported to gdb.
37 * Two, a breakpoint needs to be generated to begin communication. This
38 * is most easily accomplished by a call to breakpoint(). Breakpoint()
39 * simulates a breakpoint by executing a trap #1.
40 *
41 *************
42 *
43 * The following gdb commands are supported:
44 *
45 * command function Return value
46 *
47 * g return the value of the CPU registers hex data or ENN
48 * G set the value of the CPU registers OK or ENN
49 *
50 * mAA..AA,LLLL Read LLLL bytes at address AA..AA hex data or ENN
51 * MAA..AA,LLLL: Write LLLL bytes at address AA.AA OK or ENN
52 *
53 * c Resume at current address SNN ( signal NN)
54 * cAA..AA Continue at address AA..AA SNN
55 *
56 * s Step one instruction SNN
57 * sAA..AA Step one instruction from AA..AA SNN
58 *
59 * k kill
60 *
61 * ? What was the last sigval ? SNN (signal NN)
62 *
63 * bBB..BB Set baud rate to BB..BB OK or BNN, then sets
64 * baud rate
65 *
66 * All commands and responses are sent with a packet which includes a
67 * checksum. A packet consists of
68 *
69 * $<packet info>#<checksum>.
70 *
71 * where
72 * <packet info> :: <characters representing the command or response>
73 * <checksum> :: < two hex digits computed as modulo 256 sum of <packetinfo>>
74 *
75 * When a packet is received, it is first acknowledged with either '+' or '-'.
76 * '+' indicates a successful transfer. '-' indicates a failed transfer.
77 *
78 * Example:
79 *
80 * Host: Reply:
81 * $m0,10#2a +$00010203040506070809101112131415#42
82 *
83 ****************************************************************************/
84
85 #include <string.h>
86 #include <signal.h>
87 #include <memory.h>
88
89 /************************************************************************
90 *
91 * external low-level support routines
92 */
93
94 extern putDebugChar(); /* write a single character */
95 extern getDebugChar(); /* read and return a single char */
96
97 /************************************************************************/
98 /* BUFMAX defines the maximum number of characters in inbound/outbound buffers*/
99 /* at least NUMREGBYTES*2 are needed for register packets */
100 #define BUFMAX 2048
101
102 static int initialized; /* boolean flag. != 0 means we've been initialized */
103
104 static void set_mem_fault_trap();
105
106 static const char hexchars[]="0123456789abcdef";
107
108 #define NUMREGS 72
109
110 /* Number of bytes of registers. */
111 #define NUMREGBYTES (NUMREGS * 4)
112 enum regnames {G0, G1, G2, G3, G4, G5, G6, G7,
113 O0, O1, O2, O3, O4, O5, SP, O7,
114 L0, L1, L2, L3, L4, L5, L6, L7,
115 I0, I1, I2, I3, I4, I5, FP, I7,
116
117 F0, F1, F2, F3, F4, F5, F6, F7,
118 F8, F9, F10, F11, F12, F13, F14, F15,
119 F16, F17, F18, F19, F20, F21, F22, F23,
120 F24, F25, F26, F27, F28, F29, F30, F31,
121 Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR };
122
123 /*************************** ASSEMBLY CODE MACROS *************************/
124 /* */
125
126 #define BREAKPOINT() asm(" ta 1");
127
128 extern unsigned long rdtbr();
129
130 asm("
131 .text
132 .align 4
133
134 ! Read the TBR.
135
136 .globl _rdtbr
137 _rdtbr:
138 retl
139 mov %tbr, %o0
140
141 ! This function is called when any SPARC trap (except window overflow or
142 ! underflow) occurs. It makes sure that the invalid register window is still
143 ! available before jumping into C code. It will also restore the world if you
144 ! return from handle_exception.
145
146 trap_low:
147 mov %psr, %l0
148 mov %wim, %l3
149
150 srl %l3, %l0, %l4 ! wim >> cwp
151 cmp %l4, 1
152 bne window_fine ! Branch if not in the invalid window
153 nop
154
155 ! Handle window overflow
156
157 mov %g1, %l4 ! Save g1, we use it to hold the wim
158 srl %l3, 1, %g1 ! Rotate wim right
159 sll %l3, 8-1, %l5
160 or %l5, %g1, %g1
161
162 save %g0, %g0, %g0 ! Slip into next window
163 mov %g1, %wim ! Install the new wim
164
165 std %l0, [%sp + 0 * 4] ! save L & I registers
166 std %l2, [%sp + 2 * 4]
167 std %l4, [%sp + 4 * 4]
168 std %l6, [%sp + 6 * 4]
169
170 std %i0, [%sp + 8 * 4]
171 std %i2, [%sp + 10 * 4]
172 std %i4, [%sp + 12 * 4]
173 std %i6, [%sp + 14 * 4]
174
175 restore ! Go back to trap window.
176 mov %l4, %g1 ! Restore %g1
177
178 window_fine:
179 sub %fp, (16+1+6+1+72)*4, %sp ! Make room for input & locals
180 ! + hidden arg + arg spill
181 ! + doubleword alignment
182 ! + registers[72] local var
183
184 std %g0, [%fp + (-72 + 0) * 4] ! registers[Gx]
185 std %g2, [%fp + (-72 + 2) * 4]
186 std %g4, [%fp + (-72 + 4) * 4]
187 std %g6, [%fp + (-72 + 6) * 4]
188
189 std %i0, [%fp + (-72 + 8) * 4] ! registers[Ox]
190 std %i2, [%fp + (-72 + 10) * 4]
191 std %i4, [%fp + (-72 + 12) * 4]
192 std %i6, [%fp + (-72 + 14) * 4]
193 ! F0->F31 not implemented
194 mov %y, %l4
195 mov %tbr, %l5
196 st %l4, [%fp + (-72 + 64) * 4] ! Y
197 st %l0, [%fp + (-72 + 65) * 4] ! PSR
198 st %l3, [%fp + (-72 + 66) * 4] ! WIM
199 st %l5, [%fp + (-72 + 67) * 4] ! TBR
200 st %l1, [%fp + (-72 + 68) * 4] ! PC
201 st %l2, [%fp + (-72 + 69) * 4] ! NPC
202
203 ! CPSR and FPSR not impl
204
205 or %l0, 0xf20, %l4
206 mov %l4, %psr ! Turn on traps, disable interrupts
207
208 call _handle_exception
209 add %fp, -72 * 4, %o0 ! Pass address of registers
210
211 restore ! Ensure that previous window is valid
212 save %g0, %g0, %g0 ! by causing a window_underflow trap
213
214 ! Reload all of the registers that aren't on the stack
215
216 ld [%fp + (-72 + 1) * 4], %g1 ! registers[Gx]
217 ldd [%fp + (-72 + 2) * 4], %g2
218 ldd [%fp + (-72 + 4) * 4], %g4
219 ldd [%fp + (-72 + 6) * 4], %g6
220
221 ldd [%fp + (-72 + 8) * 4], %o0 ! registers[Ox]
222 ldd [%fp + (-72 + 10) * 4], %o2
223 ldd [%fp + (-72 + 12) * 4], %o4
224 ldd [%fp + (-72 + 14) * 4], %o6
225
226 ldd [%fp + (-72 + 64) * 4], %l0 ! Y & PSR
227 ldd [%fp + (-72 + 68) * 4], %l2 ! PC & NPC
228 mov %l0, %y
229 mov %l1, %psr ! Make sure that traps are disabled
230 ! for rett
231 jmpl %l2, %g0 ! Restore old PC
232 rett %l3 ! Restore old nPC
233 ");
234
235 /* Convert ch from a hex digit to an int */
236
237 static int
238 hex(ch)
239 unsigned char ch;
240 {
241 if (ch >= 'a' && ch <= 'f')
242 return ch-'a'+10;
243 if (ch >= '0' && ch <= '9')
244 return ch-'0';
245 if (ch >= 'A' && ch <= 'F')
246 return ch-'A'+10;
247 return -1;
248 }
249
250 /* scan for the sequence $<data>#<checksum> */
251
252 static void
253 getpacket(buffer)
254 char *buffer;
255 {
256 unsigned char checksum;
257 unsigned char xmitcsum;
258 int i;
259 int count;
260 unsigned char ch;
261
262 do
263 {
264 /* wait around for the start character, ignore all other characters */
265 while ((ch = getDebugChar()) != '$') ;
266
267 checksum = 0;
268 xmitcsum = -1;
269
270 count = 0;
271
272 /* now, read until a # or end of buffer is found */
273 while (count < BUFMAX)
274 {
275 ch = getDebugChar();
276 if (ch == '#')
277 break;
278 checksum = checksum + ch;
279 buffer[count] = ch;
280 count = count + 1;
281 }
282
283 if (count >= BUFMAX)
284 continue;
285
286 buffer[count] = 0;
287
288 if (ch == '#')
289 {
290 xmitcsum = hex(getDebugChar()) << 4;
291 xmitcsum |= hex(getDebugChar());
292 if (checksum != xmitcsum)
293 putDebugChar('-'); /* failed checksum */
294 else
295 {
296 putDebugChar('+'); /* successful transfer */
297 /* if a sequence char is present, reply the sequence ID */
298 if (buffer[2] == ':')
299 {
300 putDebugChar(buffer[0]);
301 putDebugChar(buffer[1]);
302 /* remove sequence chars from buffer */
303 count = strlen(buffer);
304 for (i=3; i <= count; i++)
305 buffer[i-3] = buffer[i];
306 }
307 }
308 }
309 }
310 while (checksum != xmitcsum);
311 }
312
313 /* send the packet in buffer. */
314
315 static void
316 putpacket(buffer)
317 unsigned char *buffer;
318 {
319 unsigned char checksum;
320 int count;
321 unsigned char ch;
322
323 /* $<packet info>#<checksum>. */
324 do
325 {
326 putDebugChar('$');
327 checksum = 0;
328 count = 0;
329
330 while (ch = buffer[count])
331 {
332 if (! putDebugChar(ch))
333 return;
334 checksum += ch;
335 count += 1;
336 }
337
338 putDebugChar('#');
339 putDebugChar(hexchars[checksum >> 4]);
340 putDebugChar(hexchars[checksum & 0xf]);
341
342 }
343 while (getDebugChar() != '+');
344 }
345
346 static char remcomInBuffer[BUFMAX];
347 static char remcomOutBuffer[BUFMAX];
348
349 /* Indicate to caller of mem2hex or hex2mem that there has been an
350 error. */
351 static volatile int mem_err = 0;
352
353 /* Convert the memory pointed to by mem into hex, placing result in buf.
354 * Return a pointer to the last char put in buf (null), in case of mem fault,
355 * return 0.
356 * If MAY_FAULT is non-zero, then we will handle memory faults by returning
357 * a 0, else treat a fault like any other fault in the stub.
358 */
359
360 static unsigned char *
361 mem2hex(mem, buf, count, may_fault)
362 unsigned char *mem;
363 unsigned char *buf;
364 int count;
365 int may_fault;
366 {
367 unsigned char ch;
368
369 set_mem_fault_trap(may_fault);
370
371 while (count-- > 0)
372 {
373 ch = *mem++;
374 if (mem_err)
375 return 0;
376 *buf++ = hexchars[ch >> 4];
377 *buf++ = hexchars[ch & 0xf];
378 }
379
380 *buf = 0;
381
382 set_mem_fault_trap(0);
383
384 return buf;
385 }
386
387 /* convert the hex array pointed to by buf into binary to be placed in mem
388 * return a pointer to the character AFTER the last byte written */
389
390 static char *
391 hex2mem(buf, mem, count, may_fault)
392 unsigned char *buf;
393 unsigned char *mem;
394 int count;
395 int may_fault;
396 {
397 int i;
398 unsigned char ch;
399
400 set_mem_fault_trap(may_fault);
401
402 for (i=0; i<count; i++)
403 {
404 ch = hex(*buf++) << 4;
405 ch |= hex(*buf++);
406 *mem++ = ch;
407 if (mem_err)
408 return 0;
409 }
410
411 set_mem_fault_trap(0);
412
413 return mem;
414 }
415
416 /* This table contains the mapping between SPARC hardware trap types, and
417 signals, which are primarily what GDB understands. It also indicates
418 which hardware traps we need to commandeer when initializing the stub. */
419
420 static struct hard_trap_info
421 {
422 unsigned char tt; /* Trap type code for SPARClite */
423 unsigned char signo; /* Signal that we map this trap into */
424 } hard_trap_info[] = {
425 {1, SIGSEGV}, /* instruction access error */
426 {2, SIGILL}, /* privileged instruction */
427 {3, SIGILL}, /* illegal instruction */
428 {4, SIGEMT}, /* fp disabled */
429 {36, SIGEMT}, /* cp disabled */
430 {7, SIGBUS}, /* mem address not aligned */
431 {9, SIGSEGV}, /* data access exception */
432 {10, SIGEMT}, /* tag overflow */
433 {128+1, SIGTRAP}, /* ta 1 - normal breakpoint instruction */
434 {0, 0} /* Must be last */
435 };
436
437 /* Each entry in the trap vector occupies four words. */
438
439 struct trap_entry
440 {
441 unsigned long ti[4];
442 };
443
444 extern struct trap_entry fltr_proto;
445 extern struct trap_entry fltr_set_mem_err;
446 asm ("
447 .data
448 .globl _fltr_proto
449 .align 4
450 _fltr_proto: ! First level trap routine prototype
451 sethi %hi(trap_low), %l0
452 jmpl %lo(trap_low)+%l0, %g0
453 nop
454 nop
455
456 ! Trap handler for memory errors. This just sets mem_err to be non-zero. It
457 ! assumes that %l1 is non-zero. This should be safe, as it is doubtful that
458 ! 0 would ever contain code that could mem fault. This routine will skip
459 ! past the faulting instruction after setting mem_err.
460
461 _fltr_set_mem_err:
462 sethi %hi(_mem_err), %l0
463 st %l1, [%l0 + %lo(_mem_err)]
464 jmpl %l2, %g0
465 rett %l2+4
466
467 .text
468 ");
469
470 /* Set up exception handlers for tracing and breakpoints */
471
472 void
473 set_debug_traps()
474 {
475 struct trap_entry *tb; /* Trap vector base address */
476 struct hard_trap_info *ht;
477
478 tb = (struct trap_entry *)(rdtbr() & ~0xfff);
479
480 for (ht = hard_trap_info; ht->tt && ht->signo; ht++)
481 tb[ht->tt] = fltr_proto;
482
483 /* In case GDB is started before us, ack any packets (presumably
484 "$?#xx") sitting there. */
485
486 putDebugChar ('+');
487
488 initialized = 1;
489 }
490
491 static void
492 set_mem_fault_trap(enable)
493 int enable;
494 {
495 struct trap_entry *tb; /* Trap vector base address */
496
497 mem_err = 0;
498
499 tb = (struct trap_entry *)(rdtbr() & ~0xfff);
500
501 if (enable)
502 tb[9] = fltr_set_mem_err;
503 else
504 tb[9] = fltr_proto;
505 }
506
507 /* Convert the SPARC hardware trap type code to a unix signal number. */
508
509 static int
510 computeSignal(tt)
511 int tt;
512 {
513 struct hard_trap_info *ht;
514
515 for (ht = hard_trap_info; ht->tt && ht->signo; ht++)
516 if (ht->tt == tt)
517 return ht->signo;
518
519 return SIGHUP; /* default for things we don't know about */
520 }
521
522 /*
523 * While we find nice hex chars, build an int.
524 * Return number of chars processed.
525 */
526
527 static int
528 hexToInt(char **ptr, int *intValue)
529 {
530 int numChars = 0;
531 int hexValue;
532
533 *intValue = 0;
534
535 while (**ptr)
536 {
537 hexValue = hex(**ptr);
538 if (hexValue < 0)
539 break;
540
541 *intValue = (*intValue << 4) | hexValue;
542 numChars ++;
543
544 (*ptr)++;
545 }
546
547 return (numChars);
548 }
549
550 /*
551 * This function does all command procesing for interfacing to gdb. It
552 * returns 1 if you should skip the instruction at the trap address, 0
553 * otherwise.
554 */
555
556 static void
557 handle_exception (registers)
558 unsigned long *registers;
559 {
560 int tt; /* Trap type */
561 int sigval;
562 int addr;
563 int length;
564 char *ptr;
565 unsigned long *sp;
566
567 /* First, we must force all of the windows to be spilled out */
568
569 asm(" save %sp, -64, %sp
570 save %sp, -64, %sp
571 save %sp, -64, %sp
572 save %sp, -64, %sp
573 save %sp, -64, %sp
574 save %sp, -64, %sp
575 save %sp, -64, %sp
576 save %sp, -64, %sp
577 restore
578 restore
579 restore
580 restore
581 restore
582 restore
583 restore
584 restore
585 ");
586
587 sp = (unsigned long *)registers[SP];
588
589 tt = (registers[TBR] >> 4) & 0xff;
590
591 /* reply to host that an exception has occurred */
592 sigval = computeSignal(tt);
593 ptr = remcomOutBuffer;
594
595 *ptr++ = 'T';
596 *ptr++ = hexchars[sigval >> 4];
597 *ptr++ = hexchars[sigval & 0xf];
598
599 *ptr++ = hexchars[PC >> 4];
600 *ptr++ = hexchars[PC & 0xf];
601 *ptr++ = ':';
602 ptr = mem2hex((char *)&registers[PC], ptr, 4, 0);
603 *ptr++ = ';';
604
605 *ptr++ = hexchars[FP >> 4];
606 *ptr++ = hexchars[FP & 0xf];
607 *ptr++ = ':';
608 ptr = mem2hex(sp + 8 + 6, ptr, 4, 0); /* FP */
609 *ptr++ = ';';
610
611 *ptr++ = hexchars[SP >> 4];
612 *ptr++ = hexchars[SP & 0xf];
613 *ptr++ = ':';
614 ptr = mem2hex((char *)&sp, ptr, 4, 0);
615 *ptr++ = ';';
616
617 *ptr++ = hexchars[NPC >> 4];
618 *ptr++ = hexchars[NPC & 0xf];
619 *ptr++ = ':';
620 ptr = mem2hex((char *)&registers[NPC], ptr, 4, 0);
621 *ptr++ = ';';
622
623 *ptr++ = hexchars[O7 >> 4];
624 *ptr++ = hexchars[O7 & 0xf];
625 *ptr++ = ':';
626 ptr = mem2hex((char *)&registers[O7], ptr, 4, 0);
627 *ptr++ = ';';
628
629 *ptr++ = 0;
630
631 putpacket(remcomOutBuffer);
632
633 while (1)
634 {
635 remcomOutBuffer[0] = 0;
636
637 getpacket(remcomInBuffer);
638 switch (remcomInBuffer[0])
639 {
640 case '?':
641 remcomOutBuffer[0] = 'S';
642 remcomOutBuffer[1] = hexchars[sigval >> 4];
643 remcomOutBuffer[2] = hexchars[sigval & 0xf];
644 remcomOutBuffer[3] = 0;
645 break;
646
647 case 'd':
648 /* toggle debug flag */
649 break;
650
651 case 'g': /* return the value of the CPU registers */
652 {
653 ptr = remcomOutBuffer;
654 ptr = mem2hex((char *)registers, ptr, 16 * 4, 0); /* G & O regs */
655 ptr = mem2hex(sp + 0, ptr, 8 * 4, 0); /* L regs */
656 ptr = mem2hex(sp + 8, ptr, 8 * 4, 0); /* I regs */
657 memset(ptr, '0', 32 * 8); /* Floating point */
658 mem2hex((char *)&registers[Y],
659 ptr + 32 * 4 * 2,
660 8 * 4,
661 0); /* Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR */
662 }
663 break;
664
665 case 'G': /* set the value of the CPU registers - return OK */
666 {
667 ptr = &remcomInBuffer[1];
668 hex2mem(ptr, (char *)registers, 16 * 4, 0); /* G & O regs */
669 hex2mem(ptr + 16 * 4 * 2, sp + 0, 8 * 4, 0); /* L regs */
670 hex2mem(ptr + 24 * 4 * 2, sp + 8, 8 * 4, 0); /* I regs */
671 hex2mem(ptr + 64 * 4 * 2, (char *)&registers[Y],
672 8 * 4, 0); /* Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR */
673 strcpy(remcomOutBuffer,"OK");
674 }
675 break;
676
677 case 'm': /* mAA..AA,LLLL Read LLLL bytes at address AA..AA */
678 /* Try to read %x,%x. */
679
680 ptr = &remcomInBuffer[1];
681
682 if (hexToInt(&ptr, &addr)
683 && *ptr++ == ','
684 && hexToInt(&ptr, &length))
685 {
686 if (mem2hex((char *)addr, remcomOutBuffer, length, 1))
687 break;
688
689 strcpy (remcomOutBuffer, "E03");
690 }
691 else
692 strcpy(remcomOutBuffer,"E01");
693 break;
694
695 case 'M': /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */
696 /* Try to read '%x,%x:'. */
697
698 ptr = &remcomInBuffer[1];
699
700 if (hexToInt(&ptr, &addr)
701 && *ptr++ == ','
702 && hexToInt(&ptr, &length)
703 && *ptr++ == ':')
704 {
705 if (hex2mem(ptr, (char *)addr, length, 1))
706 strcpy(remcomOutBuffer, "OK");
707 else
708 strcpy(remcomOutBuffer, "E03");
709 }
710 else
711 strcpy(remcomOutBuffer, "E02");
712 break;
713
714 case 'c': /* cAA..AA Continue at address AA..AA(optional) */
715 case 's': /* sAA..AA Step one instruction from AA..AA(optional) */
716 /* try to read optional parameter, pc unchanged if no parm */
717
718 ptr = &remcomInBuffer[1];
719 if (hexToInt(&ptr, &addr))
720 {
721 registers[PC] = addr;
722 registers[NPC] = addr + 4;
723 }
724
725 /* Need to flush the instruction cache here, as we may have deposited a
726 breakpoint, and the icache probably has no way of knowing that a data ref to
727 some location may have changed something that is in the instruction cache.
728 */
729
730 flush_i_cache();
731 return;
732
733 /* kill the program */
734 case 'k' : /* do nothing */
735 break;
736 #if 0
737 Disabled until we can unscrew this properly
738
739 case 'b': /* bBB... Set baud rate to BB... */
740 {
741 int baudrate;
742 extern void set_timer_3();
743
744 ptr = &remcomInBuffer[1];
745 if (!hexToInt(&ptr, &baudrate))
746 {
747 strcpy(remcomOutBuffer,"B01");
748 break;
749 }
750
751 /* Convert baud rate to uart clock divider */
752 switch (baudrate)
753 {
754 case 38400:
755 baudrate = 16;
756 break;
757 case 19200:
758 baudrate = 33;
759 break;
760 case 9600:
761 baudrate = 65;
762 break;
763 default:
764 strcpy(remcomOutBuffer,"B02");
765 goto x1;
766 }
767
768 putpacket("OK"); /* Ack before changing speed */
769 set_timer_3(baudrate); /* Set it */
770 }
771 x1: break;
772 #endif
773 } /* switch */
774
775 /* reply to the request */
776 putpacket(remcomOutBuffer);
777 }
778 }
779
780 /* This function will generate a breakpoint exception. It is used at the
781 beginning of a program to sync up with a debugger and can be used
782 otherwise as a quick means to stop program execution and "break" into
783 the debugger. */
784
785 void
786 breakpoint()
787 {
788 if (initialized)
789 BREAKPOINT();
790 }
This page took 0.045442 seconds and 4 git commands to generate.