849 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			849 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			C
		
	
	
	
| /*
 | |
|  * Copyright (c) 1995, 1996 Cygnus Support
 | |
|  *
 | |
|  * The authors hereby grant permission to use, copy, modify, distribute,
 | |
|  * and license this software and its documentation for any purpose, provided
 | |
|  * that existing copyright notices are retained in all copies and that this
 | |
|  * notice is included verbatim in any distributions. No written agreement,
 | |
|  * license, or royalty fee is required for any of the authorized uses.
 | |
|  * Modifications to this software may be copyrighted by their authors
 | |
|  * and need not follow the licensing terms described here, provided that
 | |
|  * the new terms are clearly indicated on the first page of each file where
 | |
|  * they apply.
 | |
|  */
 | |
| 
 | |
| /*
 | |
|  *   A debug packet whose contents are <data> looks like:
 | |
|  *
 | |
|  *        $ <data> # CSUM1 CSUM2
 | |
|  *
 | |
|  *        <data> must be ASCII alphanumeric and cannot include characters
 | |
|  *        '$' or '#'.  If <data> starts with two characters followed by
 | |
|  *        ':', then the existing stubs interpret this as a sequence number.
 | |
|  *
 | |
|  *       CSUM1 and CSUM2 are ascii hex representation of an 8-bit 
 | |
|  *        checksum of <data>, the most significant nibble is sent first.
 | |
|  *        the hex digits 0-9,a-f are used.
 | |
|  *
 | |
|  *   We respond with:
 | |
|  *
 | |
|  *        +       - if CSUM is correct and ready for next packet
 | |
|  *        -       - if CSUM is incorrect
 | |
|  *
 | |
|  *   <data> is as follows:
 | |
|  *   Most values are encoded in ascii hex digits.
 | |
|  */
 | |
| 
 | |
| #include "debug.h"
 | |
| #include <signal.h>
 | |
| 
 | |
| /*
 | |
|  * buffers that hold the packets while they're being constructed.
 | |
|  */
 | |
| char packet_in_buf[BUFMAX];
 | |
| char packet_out_buf[BUFMAX];
 | |
| int packet_index;
 | |
| 
 | |
| /*
 | |
|  * indicate to caller of mem2hex or hex2mem that there has been an error. 
 | |
|  * 0 means ok, 1 means error
 | |
|  */
 | |
| volatile int mem_err = 0;
 | |
| 
 | |
| /*
 | |
|  * 1 means print debugging messages from the target, 0 means be quiet. This is
 | |
|  * changed by gdb_debug().
 | |
|  */
 | |
| int remote_debug = 0;
 | |
| 
 | |
| /*
 | |
|  * indicate whether the debug vectors ahave been initialized
 | |
|  * 0 means not yet, 1 means yep, it's ready.
 | |
|  */
 | |
| int initialized = 0;
 | |
| 
 | |
| /*
 | |
|  * These variables are instantialted in the GDB stub code.
 | |
|  */
 | |
| 
 | |
| /* this is a list of signal to exception mappings. */
 | |
| extern struct trap_info hard_trap_info[];
 | |
| 
 | |
| /* this is a memory fault exception handler, used by mem2hex & hex2mem */
 | |
| extern void set_mem_fault_trap();
 | |
| 
 | |
| /*
 | |
|  * print debugging messages. This uses print, rather than one of the
 | |
|  * stdio routines, cause if there are stack or memory problems, the
 | |
|  * stdio routines don't work.
 | |
|  *	params are the debug level, and the string to print
 | |
|  *	it doesn't return anything.
 | |
|  */
 | |
| void
 | |
| debuglog(int level, char *msg)
 | |
| {
 | |
|   char *p;
 | |
|   unsigned char buf[BUFMAX];
 | |
|   char newmsg[BUFMAX];
 | |
|   int i;
 | |
| 
 | |
|   if (level > remote_debug)
 | |
|     return;
 | |
| 
 | |
|   if ((level <0) || (level > 100)) {
 | |
|     print ("ERROR: debug print level out of range");
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   /* convert some characters so it'll look right in the log */
 | |
|   p = newmsg;
 | |
|   for (i = 0 ; msg[i] != '\0'; i++) {
 | |
|     if (i > BUFMAX)
 | |
|       print ("\r\nERROR: Debug message too long\r\n");
 | |
|     switch (msg[i]) {
 | |
|     case '\n':                                  /* newlines */
 | |
|       *p++ = '\\';
 | |
|       *p++ = 'n';
 | |
|       continue;
 | |
|     case '\r':                                  /* carriage returns */
 | |
|       *p++ = '\\';
 | |
|       *p++ = 'r';
 | |
|       continue;
 | |
|     case '\033':                                /* escape */
 | |
|       *p++ = '\\';
 | |
|       *p++ = 'e';
 | |
|       continue;
 | |
|     case '\t':                                  /* tab */
 | |
|       *p++ = '\\';
 | |
|       *p++ = 't';
 | |
|       continue;
 | |
|     case '\b':                                  /* backspace */
 | |
|       *p++ = '\\';
 | |
|       *p++ = 'b';
 | |
|       continue;
 | |
|     default:                                    /* no change */
 | |
|       *p++ = msg[i];
 | |
|     }
 | |
| 
 | |
|     if (msg[i] < 26) {                          /* modify control characters */
 | |
|       *p++ = '^';
 | |
|       *p++ = msg[i] + 'A';
 | |
|       continue;
 | |
|     }
 | |
|     if (msg[i] >= 127) {			/* modify control characters */
 | |
|       *p++ = '!';
 | |
|       *p++ = msg[i] + 'A';
 | |
|       continue;
 | |
|     }
 | |
|   }
 | |
|   *p = '\0';                                    /* terminate the string */
 | |
|   print (newmsg);
 | |
|   print ("\r\n");
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * convert an ascii hex digit to a number.
 | |
|  *	param is hex digit.
 | |
|  *	returns a decimal digit.
 | |
|  */
 | |
| int
 | |
| hex2digit (int digit)
 | |
| {  
 | |
|   if (digit == 0)
 | |
|     return 0;
 | |
| 
 | |
|   if (digit >= '0' && digit <= '9')
 | |
|     return digit - '0';
 | |
|   if (digit >= 'a' && digit <= 'f')
 | |
|     return digit - 'a' + 10;
 | |
|   if (digit >= 'A' && digit <= 'F')
 | |
|     return digit - 'A' + 10;
 | |
|   
 | |
|   /* shouldn't ever get this far */
 | |
|   return ERROR;
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * convert number NIB to a hex digit.
 | |
|  *	param is a decimal digit.
 | |
|  *	returns a hex digit.
 | |
|  */
 | |
| char
 | |
| digit2hex(int digit)
 | |
| {
 | |
|   if (digit < 10)
 | |
|     return '0' + digit;
 | |
|   else
 | |
|     return 'a' + digit - 10;
 | |
| }
 | |
| 
 | |
| /* 
 | |
|  * Convert the memory pointed to by mem into hex, placing result in buf.
 | |
|  * Return a pointer to the last char put in buf (null), in case of mem fault,
 | |
|  * return 0.
 | |
|  * If MAY_FAULT is non-zero, then we will handle memory faults by returning
 | |
|  * a 0, else treat a fault like any other fault in the stub.
 | |
|  */
 | |
| unsigned char *
 | |
| mem2hex(unsigned char *mem, unsigned char *buf, int count, int may_fault)
 | |
| {
 | |
|   unsigned char ch;
 | |
| 
 | |
|   DEBUG (1, "In mem2hex");
 | |
| 
 | |
|   set_mem_fault_trap(MAY_FAULT);
 | |
| 
 | |
|   while (count-- > 0) {
 | |
|     ch = *mem++;
 | |
|     if (mem_err) {
 | |
|       DEBUG (1, "memory fault in mem2hex");
 | |
|       return 0;
 | |
|     }
 | |
|     *buf++ = digit2hex(ch >> 4);
 | |
|     *buf++ = digit2hex(ch & 0xf);
 | |
|   }
 | |
| 
 | |
|   *buf = 0;
 | |
| 
 | |
|   set_mem_fault_trap(OK);
 | |
| 
 | |
|   return buf;
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * Convert the hex array pointed to by buf into binary to be placed in mem
 | |
|  * return a pointer to the character AFTER the last byte written
 | |
|  */
 | |
| unsigned char *
 | |
| hex2mem(unsigned char *buf, unsigned char *mem, int count, int may_fault)
 | |
| {
 | |
|   int i;
 | |
|   unsigned char ch;
 | |
| 
 | |
|   DEBUG (1, "In hex2mem");
 | |
| 
 | |
|   set_mem_fault_trap(may_fault);
 | |
| 
 | |
|   for (i=0; i<count; i++) {
 | |
|     ch = hex2digit(*buf++) << 4;
 | |
|     ch |= hex2digit(*buf++);
 | |
|     *mem++ = ch;
 | |
|     if (mem_err)
 | |
|       return 0;
 | |
|   }
 | |
| 
 | |
|   set_mem_fault_trap(0);
 | |
| 
 | |
|   return mem;
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * while we find nice hex chars, build an int.
 | |
|  *	param is a pointer to the string.
 | |
|  *	returns the int in the param field, and the number of chars processed.
 | |
|  */
 | |
| int
 | |
| hex2int (char **ptr, int *intValue)
 | |
| {
 | |
|   int numChars = 0;
 | |
|   int hexValue;
 | |
| 
 | |
|   *intValue = 0;
 | |
| 
 | |
|   while (**ptr)
 | |
|     {
 | |
|       hexValue = hex2digit(**ptr);
 | |
|       if (hexValue < 0)
 | |
|         break;
 | |
| 
 | |
|       *intValue = (*intValue << 4) | hexValue;
 | |
|       numChars ++;
 | |
|       (*ptr)++;
 | |
|     }
 | |
|   return (numChars);
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * Scan for the sequence $<data>#<checksum>
 | |
|  */
 | |
| void
 | |
| getpacket(unsigned char *buffer)
 | |
| {
 | |
|   unsigned char checksum;
 | |
|   unsigned char xmitcsum;
 | |
|   int i;
 | |
|   int count;
 | |
|   unsigned char ch;
 | |
| 
 | |
|   do {
 | |
|     /* wait around for the start character, ignore all other characters */
 | |
|     while ((ch = (inbyte() & 0x7f)) != '$') ;
 | |
|     
 | |
|     checksum = 0;
 | |
|     xmitcsum = -1;
 | |
|     
 | |
|     count = 0;
 | |
|     
 | |
|     /* now, read until a # or end of buffer is found */
 | |
|     while (count < BUFMAX) {
 | |
|       ch = inbyte() & 0x7f;
 | |
|       if (ch == '#')
 | |
| 	break;
 | |
|       checksum = checksum + ch;
 | |
|       buffer[count] = ch;
 | |
|       count = count + 1;
 | |
|     }
 | |
|     
 | |
|     if (count >= BUFMAX)
 | |
|       continue;
 | |
|     
 | |
|     buffer[count] = 0;
 | |
|     
 | |
|     if (ch == '#') {
 | |
|       xmitcsum = hex2digit(inbyte() & 0x7f) << 4;
 | |
|       xmitcsum |= hex2digit(inbyte() & 0x7f);
 | |
| #if 1
 | |
|       /* Humans shouldn't have to figure out checksums to type to it. */
 | |
|       outbyte ('+');
 | |
|       return;
 | |
| #endif
 | |
|       if (checksum != xmitcsum)
 | |
| 	outbyte('-');	/* failed checksum */
 | |
|       else {
 | |
| 	outbyte('+'); /* successful transfer */
 | |
| 	/* if a sequence char is present, reply the sequence ID */
 | |
| 	if (buffer[2] == ':') {
 | |
| 	  outbyte(buffer[0]);
 | |
| 	  outbyte(buffer[1]);
 | |
| 	  /* remove sequence chars from buffer */
 | |
| 	  count = strlen(buffer);
 | |
| 	  for (i=3; i <= count; i++)
 | |
| 	    buffer[i-3] = buffer[i];
 | |
| 	}
 | |
|       }
 | |
|     }
 | |
|   }
 | |
|   while (checksum != xmitcsum);
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * Send the packet in buffer.
 | |
|  */
 | |
| void
 | |
| putpacket(unsigned char *buffer)
 | |
| {
 | |
|   unsigned char checksum;
 | |
|   int count;
 | |
|   unsigned char ch;
 | |
| 
 | |
|   /*  $<packet info>#<checksum>. */
 | |
|   do {
 | |
|     outbyte('$');
 | |
|     checksum = 0;
 | |
|     count = 0;
 | |
|     
 | |
|     while (ch = buffer[count]) {
 | |
|       if (! outbyte(ch))
 | |
| 	return;
 | |
|       checksum += ch;
 | |
|       count += 1;
 | |
|     }
 | |
|     
 | |
|     outbyte('#');
 | |
|     outbyte(digit2hex(checksum >> 4));
 | |
|     outbyte(digit2hex(checksum & 0xf));
 | |
|     
 | |
|   }
 | |
|   while ((inbyte() & 0x7f) != '+');
 | |
| }
 | |
| 
 | |
| /*
 | |
|  *
 | |
|  */
 | |
| void
 | |
| gdb_event_loop(int sigval, unsigned long *registers)
 | |
| {
 | |
|   int addr;
 | |
|   int length;
 | |
|   unsigned char *ptr;
 | |
|   ptr = packet_out_buf;
 | |
| 
 | |
|   DEBUG (1, "In gdb_event_loop");
 | |
| 
 | |
|   while (1) {
 | |
|     packet_out_buf[0] = 0;
 | |
|     
 | |
|     getpacket(packet_in_buf);      
 | |
|     ptr = &packet_in_buf[1];
 | |
| 
 | |
|     switch (packet_in_buf[0]) {
 | |
|     case '?':		/* get the last known signal */
 | |
|       gdb_last_signal(sigval);
 | |
|       break;
 | |
|       
 | |
|     case 'd':		/* toggle debug messages from the stub */
 | |
|       gdb_toggle();
 | |
|       break;
 | |
|       
 | |
|     case 'g':		/* return the value of the CPU registers */
 | |
|       target_read_registers(registers);
 | |
|       break;
 | |
|       
 | |
|     case 'G':	   /* set the value of the CPU registers - return OK */
 | |
|       target_write_registers(registers);
 | |
|       break;
 | |
|       
 | |
|     case 'm':	  /* mAA..AA,LLLL  Read LLLL bytes at address AA..AA */
 | |
|       /* Try to read %x,%x.  */
 | |
|       if (hex2int((char **)&ptr, &addr)
 | |
| 	  && *ptr++ == ','
 | |
| 	  && hex2int((char **)&ptr, &length)) {
 | |
| 	gdb_read_memory(addr, length);
 | |
|       } else {
 | |
| 	make_return_packet(1);
 | |
|       }
 | |
|       break;
 | |
|       
 | |
|     case 'M': /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */
 | |
|       /* Try to read '%x,%x:'.  */
 | |
|       if (hex2int((char **)&ptr, &addr)
 | |
| 	  && *ptr++ == ','
 | |
| 	  && hex2int((char **)&ptr, &length)
 | |
| 	  && *ptr++ == ':') {
 | |
| 	gdb_write_memory (addr, length, ptr);
 | |
|       } else {
 | |
| 	make_return_packet(2);
 | |
|       }
 | |
|       break;
 | |
|       
 | |
|     case 'c':    /* cAA..AA    Continue at address AA..AA(optional) */
 | |
|       /* try to read optional parameter, pc unchanged if no parm */
 | |
|       if (hex2int((char **)&ptr, &addr)) {
 | |
| 	write_pc(registers, addr);
 | |
|       }
 | |
|       
 | |
|       /*
 | |
|        * we need to flush the instruction cache here, as we may have
 | |
|        * deposited a breakpoint, and the icache probably has no way of
 | |
|        * knowing that a data ref to some location may have changed
 | |
|        * something that is in the instruction cache. 
 | |
|        */
 | |
|       
 | |
|       flush_i_cache();
 | |
|       /* by returning, we pick up execution where we left off */
 | |
|       return;
 | |
| 
 | |
|       /* kill the program */
 | |
|     case 'k' :
 | |
|       gdb_kill();
 | |
|       break;
 | |
|     case 'r':		/* Reset */
 | |
|       target_reset();
 | |
|       break;
 | |
|     }			/* switch */
 | |
|     
 | |
|     /* reply to the request */
 | |
|     putpacket(packet_out_buf);
 | |
|   }
 | |
|   DEBUG (1, "Leaving handle_exception()");
 | |
| }
 | |
| 
 | |
| /* Convert the hardware trap type code to a unix signal number. */
 | |
| 
 | |
| int
 | |
| computeSignal(int tt)
 | |
| {
 | |
|   struct trap_info *ht;
 | |
| 
 | |
|   for (ht = hard_trap_info; ht->tt && ht->signo; ht++)
 | |
|     if (ht->tt == tt)
 | |
|       return ht->signo;
 | |
| 
 | |
|   return SIGHUP;		/* default for things we don't know about */
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * Set up exception handlers for tracing and breakpoints
 | |
|  */
 | |
| void
 | |
| set_debug_traps()
 | |
| {
 | |
|   struct trap_info *ht;
 | |
| 
 | |
|   DEBUG (1, "Entering set_debug_traps()");
 | |
| 
 | |
|   if (hard_trap_info->tt == 0) {
 | |
|     print ("ERROR: ARG#$@%^&*!! no hard trap info!!\r\n");
 | |
|   }
 | |
| 
 | |
|   for (ht = hard_trap_info; ht->tt && ht->signo; ht++) {
 | |
|     exception_handler(ht->tt, (unsigned long)default_trap_hook);
 | |
|   }
 | |
| 
 | |
|   /* In case GDB is started before us, ack any packets (presumably
 | |
|      "$?#xx") sitting there.  */
 | |
| 
 | |
|   outbyte ('+');
 | |
|   initialized = 1;
 | |
| 
 | |
|   DEBUG (1, "Leaving set_debug_traps()");
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * make a return packet.
 | |
|  *	param is the value to return.
 | |
|  *		0 = OK, any other value is converted to a two digit hex number.
 | |
|  *	returns a string or "OK" or "ENN", where NN is the error number. Each N
 | |
|  *		is an ASCII encoded hex digit.
 | |
|  */
 | |
| char *
 | |
| make_return_packet(int val)
 | |
| {
 | |
|   if (val == 0) {
 | |
|      packet_out_buf[0] = 'O';
 | |
|      packet_out_buf[1] = 'K';
 | |
|      packet_out_buf[2] = 0;  
 | |
|   } else {
 | |
|     packet_out_buf[0] = 'E';
 | |
|     packet_out_buf[1] = digit2hex((val >> 4) & 0xf);
 | |
|     packet_out_buf[2] = digit2hex(val & 0xf);
 | |
|     packet_out_buf[3] = 0;
 | |
|   }
 | |
|   return(packet_out_buf);
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * g - read registers.
 | |
|  *	no params.
 | |
|  *	returns a vector of words, size is NUM_REGS.
 | |
|  */
 | |
| char *
 | |
| gdb_read_registers()
 | |
| {
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * G - write registers.
 | |
|  *	param is a vector of words, size is NUM_REGS.
 | |
|  *	returns an OK or an error number.
 | |
|  */
 | |
| char *
 | |
| gdb_write_registers(char *regs)
 | |
| {
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * m - read memory.
 | |
|  *	params are the address to start the read at and the number of
 | |
|  *		bytes to read.  
 | |
|  *	returns a vector of nbytes or an error number.
 | |
|  *	Can be fewer bytes than requested if able to read only part of the
 | |
|  *	data. 
 | |
|  */
 | |
| char *
 | |
| gdb_read_memory(long addr, int nbytes)
 | |
| {
 | |
|   if (mem2hex((char *)addr, packet_out_buf, nbytes, MAY_FAULT))
 | |
|     return(packet_out_buf);
 | |
|   else {
 | |
|     return(make_return_packet(3));
 | |
|   }
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * M write memory
 | |
|  *	params are the address to start writing to, the number of
 | |
|  *		bytes to write, and the new values of the bytes.
 | |
|  *	returns an OK or an error number.
 | |
|  */
 | |
| char *
 | |
| gdb_write_memory(long addr, int nbytes, char *mem)
 | |
| {
 | |
|  if (hex2mem(mem, (char *)addr, nbytes, MAY_FAULT))
 | |
|     return(make_return_packet(OK));
 | |
|   else {
 | |
|     return(make_return_packet(3));
 | |
|   }
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * c - continue at address.
 | |
|  *	param is the address to start at, and an optional signal. If
 | |
|  *		sig is zero, then ignore it.
 | |
|  *	returns an OK or an error number.
 | |
|  */
 | |
| char *
 | |
| gdb_continue(int sig, long addr)
 | |
| {
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * s - step instruction(s)
 | |
|  *	param is the address to start at, and an optional signal. If
 | |
|  *		sig is zero, then ignore it.
 | |
|  *	returns an OK or an error number.
 | |
|  */
 | |
| char *
 | |
| gdb_step(int sig, long addr)
 | |
| {
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * k - kill program.
 | |
|  *	no params.
 | |
|  *	returns an OK or an error number.
 | |
|  */
 | |
| char *
 | |
| gdb_kill()
 | |
| {
 | |
|   /* generically, we can't do anything for this command */
 | |
|   return(make_return_packet(OK));
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * ? - last signal.
 | |
|  *	no params.
 | |
|  *	returns the last signal number.
 | |
|  */
 | |
| char *
 | |
| gdb_last_signal(int val)
 | |
| {
 | |
|   DEBUG (1, "Entering gdb_last_signal()");
 | |
| 
 | |
|   packet_out_buf[0] = 'S';
 | |
|   packet_out_buf[1] = digit2hex(val >> 4);
 | |
|   packet_out_buf[2] = digit2hex(val & 0xf);
 | |
|   packet_out_buf[3] = 0;
 | |
| 
 | |
|   DEBUG (1, "Leaving gdb_last_signal()");
 | |
|   return (packet_out_buf);
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * b - change baud rate.
 | |
|  *	param is the new baudrate
 | |
|  *	returns the baud rate.
 | |
|  */
 | |
| char *
 | |
| gdb_baudrate(int baud)
 | |
| {
 | |
|   /* generically, we can't do anything for this command */
 | |
|   return(make_return_packet(OK));
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * T - dump state.
 | |
|  *	no params.
 | |
|  *	returns the signal number, the registers, the thread ID, and
 | |
|  *		possible extensions in a vector that looks like:
 | |
|  *			TAAn...:r...;n...:r...;n...:r...; where:
 | |
|  *                       AA = signal number
 | |
|  *                       n... = register number (hex)
 | |
|  *                       r... = register contents
 | |
|  *                       n... = `thread'
 | |
|  *                       r... = thread process ID.  This is a hex integer.
 | |
|  *                       n... = other string not starting with valid hex digit.
 | |
|  *                              gdb should ignore this n,r pair and go on to
 | |
|  *				the next. This way we can extend the protocol.
 | |
|  */
 | |
| char *
 | |
| gdb_dump_state()
 | |
| {
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * D - host requests a detach
 | |
|  *	no params.
 | |
|  *	returns either a S, T, W, or X command.
 | |
|  *	returns an OK or an error number.
 | |
|  */
 | |
| char *
 | |
| gdb_detach()
 | |
| {
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * H - set thread.
 | |
|  *	params are the command to execute and the thread ID.
 | |
|  *		cmd = 'c' for thread used in step and continue;
 | |
|  *		cmd = 'g' for thread used in other operations.
 | |
|  *		tid = -1 for all threads.
 | |
|  *		tid = zero, pick a thread,any thread.
 | |
|  *	returns an OK or an error number.
 | |
|  */
 | |
| char *
 | |
| gdb_set_thread(int cmd, int tid)
 | |
| {
 | |
|   /* generically, we can't do anything for this command */
 | |
|   return(make_return_packet(OK));
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * p - read one register.
 | |
|  *	param is the register number.
 | |
|  *	returns the register value or ENN.
 | |
|  */
 | |
| char *
 | |
| gdb_read_reg(int reg)
 | |
| {
 | |
|   /* generically, we can't do anything for this command */
 | |
|   return(make_return_packet(OK));
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * P - write one register.
 | |
|  *	params are the register number, and it's new value.
 | |
|  *	returns the register value or ENN.
 | |
|  */
 | |
| char *
 | |
| gdb_write_reg(int reg, long val)
 | |
| {
 | |
|   /* generically, we can't do anything for this command */
 | |
|   
 | |
|   return(make_return_packet(OK));
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * W - process exited.
 | |
|  *	no params.
 | |
|  *	returns the exit status.
 | |
|  */
 | |
| char *
 | |
| gdb_exited()
 | |
| {
 | |
|   /* generically, we can't do anything for this command */
 | |
|   return(make_return_packet(OK));
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * X - process terminated.
 | |
|  *	no params.
 | |
|  *	returns the last signal.
 | |
|  */
 | |
| char *
 | |
| gdb_terminated()
 | |
| {
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * O - hex encoding.
 | |
|  *	params are a vector of bytes, and the number of bytes to encode.
 | |
|  *	returns a vector of ASCII encoded hex numbers.
 | |
|  */
 | |
| char *
 | |
| gdb_hex(char *str, int nbytes)
 | |
| {
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * A - tread alive request.
 | |
|  *	param is the thread ID.
 | |
|  *	returns an OK or an error number.
 | |
|  */
 | |
| char *
 | |
| gdb_thread_alive(int tid)
 | |
| {
 | |
|   /* generically, we can't do anything for this command */
 | |
|   return(make_return_packet(OK));
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * ! - extended protocol.
 | |
|  *	no params.
 | |
|  *	returns an OK or an error number.
 | |
|  */
 | |
| char *
 | |
| gdb_extended()
 | |
| {
 | |
|   /* generically, we can't do anything for this command */
 | |
|   return(make_return_packet(OK));
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * d - toggle gdb stub diagnostics.
 | |
|  *	no params.
 | |
|  *	returns an OK or an error number.
 | |
|  */
 | |
| char *
 | |
| gdb_debug()
 | |
| {
 | |
|   if (remote_debug > 0)
 | |
|     remote_debug = 0;
 | |
|   else
 | |
|     remote_debug = 1;
 | |
| 
 | |
|   return(make_return_packet(OK));
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * d - toggle gdb stub.
 | |
|  *	no params.
 | |
|  *	returns an OK or an error number.
 | |
|  */
 | |
| char *
 | |
| gdb_toggle()
 | |
| {
 | |
|   static int level = 0;
 | |
| 
 | |
|   if (remote_debug) {
 | |
|     level = remote_debug;
 | |
|     remote_debug = 0;
 | |
|   } else {
 | |
|     remote_debug = level;
 | |
|   }
 | |
| 
 | |
|   return(make_return_packet(OK));
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * r - reset target
 | |
|  *	no params.
 | |
|  *	returns an OK or an error number.
 | |
|  */
 | |
| char *
 | |
| gdb_reset()
 | |
| {
 | |
|   /* generically, we can't do anything for this command */
 | |
|   return(make_return_packet(OK));
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * t - search backwards.
 | |
|  *	params are the address to start searching from, a pattern to match, and
 | |
|  *		the mask to use.
 | |
|  *	FIXME: not entirely sure what this is supposed to return.
 | |
|  */
 | |
| char *
 | |
| gdb_search(long addr, long pat, long mask)
 | |
| {
 | |
|   /* generically, we can't do anything for this command */
 | |
|   return(make_return_packet(OK));
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * q - general get query.
 | |
|  *	param is a string, that's the query to be executed.
 | |
|  *	FIXME: not entirely sure what this is supposed to return.
 | |
|  */
 | |
| char *
 | |
| gdb_get_query(char *query)
 | |
| {
 | |
|   /* generically, we can't do anything for this command */
 | |
|   return(make_return_packet(OK));
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * Q - general set query
 | |
|  *	param is a string, that's the query to be executed.
 | |
|  *	FIXME: not entirely sure what this means.
 | |
|  *	returns an OK or an error number.
 | |
|  */
 | |
| char *
 | |
| gdb_set(char *query)
 | |
| {
 | |
|   /* generically, we can't do anything for this command */
 | |
|   return(make_return_packet(OK));
 | |
| }
 | |
| 
 | |
| 
 |