diff --git a/gdb/.Sanitize b/gdb/.Sanitize index d4b358326b..99ffba9159 100644 --- a/gdb/.Sanitize +++ b/gdb/.Sanitize @@ -206,6 +206,7 @@ remote-adapt.c remote-eb.c remote-es1800.c remote-hms.c +remote-mips.c remote-mm.c remote-nindy.c remote-sim.c diff --git a/gdb/ChangeLog b/gdb/ChangeLog index e514688294..3cb822a6f5 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,23 @@ +Mon Feb 22 15:21:54 1993 Ian Lance Taylor (ian@cygnus.com) + + * remote-mips.c: New file; implements MIPS remote debugging + protocol. + * config/idt.mt: New file; uses remote-mips.c + * configure.in (mips-idt-ecoff): New target; uses idt.mt. + + * mips-tdep.c (mips_fpu): New variable; controls use of MIPS + floating point coprocessor. + (mips_push_dummy_frame): If not mips_fpu, don't save floating + point registers. + (mips_pop_frame): If not mips_fpu, don't restore floating point + registers. + (_initialize_mips_tdep): New function; let the user reset mips_fpu + variable. + * tm-mips.h (EXTRACT_RETURN_VALUE, STORE_RETURN_VALUE): If not + mips_fpu, don't use fp0 as floating point return register. + (FIX_CALL_DUMMY): If not mips_fpu, don't save floating point + registers. + Mon Feb 22 07:54:03 1993 Mike Werner (mtw@poseidon.cygnus.com) * gdb/testsuite: made modifications to testcases, etc., to allow diff --git a/gdb/config/.Sanitize b/gdb/config/.Sanitize index 50347bcdc3..c5cbc26f36 100644 --- a/gdb/config/.Sanitize +++ b/gdb/config/.Sanitize @@ -66,6 +66,7 @@ i386v.mt i386v32.mh i386v4.mh i386v4.mt +idt.mt irix3.mh irix3.mt irix4.mh diff --git a/gdb/config/idt.mt b/gdb/config/idt.mt new file mode 100644 index 0000000000..d7fcecb8fe --- /dev/null +++ b/gdb/config/idt.mt @@ -0,0 +1,3 @@ +# Target: Big-endian IDT board. +TDEPFILES= mips-pinsn.o mips-tdep.o exec.o remote-mips.o +TM_FILE= tm-bigmips.h diff --git a/gdb/configure.in b/gdb/configure.in index 72bcdbd7c5..0af76bf059 100644 --- a/gdb/configure.in +++ b/gdb/configure.in @@ -171,6 +171,7 @@ m88k-*-*) gdb_target=m88k ;; mips-big-*) gdb_target=bigmips ;; mips-dec-*) gdb_target=decstation ;; +mips-idt-ecoff) gdb_target=idt ;; mips-little-*) gdb_target=littlemips ;; mips-sgi-*) gdb_target=irix3 ;; mips-sony-*) gdb_target=bigmips ;; diff --git a/gdb/mips-tdep.c b/gdb/mips-tdep.c index 7f7d0f5b12..3e6c7a4fc5 100644 --- a/gdb/mips-tdep.c +++ b/gdb/mips-tdep.c @@ -1,5 +1,5 @@ /* Target-dependent code for the MIPS architecture, for GDB, the GNU Debugger. - Copyright 1988, 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + Copyright 1988, 1989, 1990, 1991, 1992, 1993 Free Software Foundation, Inc. Contributed by Alessandro Forin(af@cs.cmu.edu) at CMU and by Per Bothner(bothner@cs.wisc.edu) at U.Wisconsin. @@ -55,6 +55,10 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include +/* Some MIPS boards don't support floating point, so we permit the + user to turn it off. */ +int mips_fpu = 1; + #define PROC_LOW_ADDR(proc) ((proc)->pdr.adr) /* least address */ #define PROC_HIGH_ADDR(proc) ((proc)->pdr.iline) /* upper address bound */ #define PROC_FRAME_OFFSET(proc) ((proc)->pdr.frameoffset) @@ -316,16 +320,13 @@ init_extra_frame_info(fci) /* r0 bit means kernel trap */ int kernel_trap = PROC_REG_MASK(proc_desc) & 1; - if (fci->frame == 0) - { - /* Fixup frame-pointer - only needed for top frame */ - /* This may not be quite right, if proc has a real frame register */ - if (fci->pc == PROC_LOW_ADDR(proc_desc)) - fci->frame = read_register (SP_REGNUM); - else - fci->frame = READ_FRAME_REG(fci, PROC_FRAME_REG(proc_desc)) - + PROC_FRAME_OFFSET(proc_desc); - } + /* Fixup frame-pointer - only needed for top frame */ + /* This may not be quite right, if proc has a real frame register */ + if (fci->pc == PROC_LOW_ADDR(proc_desc)) + fci->frame = read_register (SP_REGNUM); + else + fci->frame = READ_FRAME_REG(fci, PROC_FRAME_REG(proc_desc)) + + PROC_FRAME_OFFSET(proc_desc); if (proc_desc == &temp_proc_desc) *fci->saved_regs = temp_saved_regs; @@ -381,11 +382,14 @@ init_extra_frame_info(fci) arguments without difficulty. */ FRAME -setup_arbitrary_frame (stack, pc) - FRAME_ADDR stack; - CORE_ADDR pc; +setup_arbitrary_frame (argc, argv) + int argc; + FRAME_ADDR *argv; { - return create_new_frame (stack, pc); + if (argc != 2) + error ("MIPS frame specifications require two arguments: sp and pc"); + + return create_new_frame (argv[0], argv[1]); } @@ -470,12 +474,12 @@ mips_push_dummy_frame() * Saved D18 (i.e. F19, F18) * ... * Saved D0 (i.e. F1, F0) - * CALL_DUMMY (subroutine stub; see m-mips.h) + * CALL_DUMMY (subroutine stub; see tm-mips.h) * Parameter build area (not yet implemented) * (low memory) */ PROC_REG_MASK(proc_desc) = GEN_REG_SAVE_MASK; - PROC_FREG_MASK(proc_desc) = FLOAT_REG_SAVE_MASK; + PROC_FREG_MASK(proc_desc) = mips_fpu ? FLOAT_REG_SAVE_MASK : 0; PROC_REG_OFFSET(proc_desc) = /* offset of (Saved R31) from FP */ -sizeof(long) - 4 * SPECIAL_REG_SAVE_COUNT; PROC_FREG_OFFSET(proc_desc) = /* offset of (Saved D18) from FP */ @@ -507,9 +511,11 @@ mips_push_dummy_frame() write_memory (sp - 8, (char *)&buffer, sizeof(REGISTER_TYPE)); buffer = read_register (LO_REGNUM); write_memory (sp - 12, (char *)&buffer, sizeof(REGISTER_TYPE)); - buffer = read_register (FCRCS_REGNUM); + buffer = read_register (mips_fpu ? FCRCS_REGNUM : ZERO_REGNUM); write_memory (sp - 16, (char *)&buffer, sizeof(REGISTER_TYPE)); - sp -= 4 * (GEN_REG_SAVE_COUNT+FLOAT_REG_SAVE_COUNT+SPECIAL_REG_SAVE_COUNT); + sp -= 4 * (GEN_REG_SAVE_COUNT + + (mips_fpu ? FLOAT_REG_SAVE_COUNT : 0) + + SPECIAL_REG_SAVE_COUNT); write_register (SP_REGNUM, sp); PROC_LOW_ADDR(proc_desc) = sp - CALL_DUMMY_SIZE + CALL_DUMMY_START_OFFSET; PROC_HIGH_ADDR(proc_desc) = sp; @@ -568,7 +574,8 @@ mips_pop_frame() write_register (HI_REGNUM, read_memory_integer(new_sp - 8, 4)); write_register (LO_REGNUM, read_memory_integer(new_sp - 12, 4)); - write_register (FCRCS_REGNUM, read_memory_integer(new_sp - 16, 4)); + if (mips_fpu) + write_register (FCRCS_REGNUM, read_memory_integer(new_sp - 16, 4)); } } @@ -686,7 +693,11 @@ isa_NAN(p, len) } else if (len == 8) { +#if TARGET_BYTE_ORDER == BIG_ENDIAN + exponent = *p; +#else exponent = *(p+1); +#endif exponent = exponent << 1 >> (32 - DOUBLE_EXP_BITS - 1); return ((exponent == -1) || (! exponent && *p * *(p+1))); } @@ -739,3 +750,17 @@ mips_skip_prologue(pc) return pc; } + +/* Let the user turn off floating point. */ + +void +_initialize_mips_tdep () +{ + add_show_from_set + (add_set_cmd ("mips_fpu", class_support, var_boolean, + (char *) &mips_fpu, + "Set use of floating point coprocessor.\n\ +Turn off to avoid using floating point instructions when calling functions\n\ +or dealing with return values.", &setlist), + &showlist); +} diff --git a/gdb/remote-mips.c b/gdb/remote-mips.c index 6c559f1752..73a653c254 100644 --- a/gdb/remote-mips.c +++ b/gdb/remote-mips.c @@ -48,7 +48,7 @@ static int mips_cksum PARAMS ((const unsigned char *hdr, int len)); static void -mips_send_packet PARAMS ((const char *s)); +mips_send_packet PARAMS ((const char *s, int get_ack)); static int mips_receive_packet PARAMS ((char *buff)); @@ -57,6 +57,9 @@ static int mips_request PARAMS ((char cmd, unsigned int addr, unsigned int data, int *perr)); +static void +mips_initialize PARAMS ((void)); + static void mips_open PARAMS ((char *name, int from_tty)); @@ -246,6 +249,9 @@ extern struct target_ops mips_ops; /* Set to 1 if the target is open. */ static int mips_is_open; +/* Set to 1 while the connection is being initialized. */ +static int mips_initializing; + /* The next sequence number to send. */ static int mips_send_seq; @@ -263,7 +269,7 @@ static int mips_send_retries = 10; static int mips_syn_garbage = 1050; /* The time to wait for a packet, in seconds. */ -static int mips_receive_wait = 30; +static int mips_receive_wait = 5; /* Set if we have sent a packet to the board but have not yet received a reply. */ @@ -273,13 +279,25 @@ static int mips_need_reply = 0; static int mips_debug = 0; /* Read a character from the remote, aborting on error. Returns -2 on - timeout (since that's what serial_readchar returns). */ + timeout (since that's what serial_readchar returns). FIXME: If we + see the string "" from the board, then we are debugging on the + main console port, and we have somehow dropped out of remote + debugging mode. In this case, we automatically go back in to + remote debugging mode. This is a hack, put in because I can't find + any way for a program running on the remote board to terminate + without also ending remote debugging mode. I assume users won't + have any trouble with this; for one thing, the IDT documentation + generally assumes that the remote debugging port is not the console + port. This is, however, very convenient for DejaGnu when you only + have one connected serial port. */ static int mips_readchar (timeout) int timeout; { int ch; + static int state = 0; + static char nextstate[5] = { '<', 'I', 'D', 'T', '>' }; ch = serial_readchar (timeout); if (ch == EOF) @@ -293,6 +311,34 @@ mips_readchar (timeout) else printf_filtered ("Timed out in read\n"); } + + /* If we have seen and we either time out, or we see a @ + (which was echoed from a packet we sent), reset the board as + described above. The first character in a packet after the SYN + (which is not echoed) is always an @ unless the packet is more + than 64 characters long, which ours never are. */ + if ((ch == -2 || ch == '@') + && state == 5 + && ! mips_initializing) + { + if (mips_debug > 0) + printf_filtered ("Reinitializing MIPS debugging mode\n"); + serial_write ("\rdb tty0\r", sizeof "\rdb tty0\r" - 1); + sleep (1); + + mips_need_reply = 0; + mips_initialize (); + + state = 0; + + error ("Remote board reset"); + } + + if (ch == nextstate[state]) + ++state; + else + state = 0; + return ch; } @@ -327,7 +373,11 @@ mips_receive_header (hdr, pgarbage, ch, timeout) what the program is outputting, if the debugging is being done on the console port. FIXME: Perhaps this should be filtered? */ - putchar (ch); + if (! mips_initializing || mips_debug > 0) + { + putchar (ch); + fflush (stdout); + } ++*pgarbage; if (*pgarbage > mips_syn_garbage) @@ -416,8 +466,9 @@ mips_cksum (hdr, data, len) /* Send a packet containing the given ASCII string. */ static void -mips_send_packet (s) +mips_send_packet (s, get_ack) const char *s; + int get_ack; { unsigned int len; unsigned char *packet; @@ -446,6 +497,9 @@ mips_send_packet (s) the sequence number we expect in the acknowledgement. */ mips_send_seq = (mips_send_seq + 1) % SEQ_MODULOS; + if (! get_ack) + return; + /* We can only have one outstanding data packet, so we just wait for the acknowledgement here. Keep retransmitting the packet until we get one, or until we've tried too many times. */ @@ -728,7 +782,7 @@ mips_request (cmd, addr, data, perr) if (mips_need_reply) fatal ("mips_request: Trying to send command before reply"); sprintf (buff, "0x0 %c 0x%x 0x%x", cmd, addr, data); - mips_send_packet (buff); + mips_send_packet (buff, 1); mips_need_reply = 1; } @@ -766,6 +820,64 @@ mips_request (cmd, addr, data, perr) return rresponse; } +/* Initialize a new connection to the MIPS board, and make sure we are + really connected. */ + +static void +mips_initialize () +{ + char cr; + int hold_wait; + int tries; + char buff[DATA_MAXLEN + 1]; + int err; + + if (mips_initializing) + return; + + mips_initializing = 1; + + mips_send_seq = 0; + mips_receive_seq = 0; + + /* The board seems to want to send us a packet. I don't know what + it means. The packet seems to be triggered by a carriage return + character, although perhaps any character would do. */ + cr = '\r'; + serial_write (&cr, 1); + + hold_wait = mips_receive_wait; + mips_receive_wait = 3; + + tries = 0; + while (catch_errors (mips_receive_packet, buff, (char *) NULL) == 0) + { + char cc; + + if (tries > 0) + error ("Could not connect to target"); + ++tries; + + /* We did not receive the packet we expected; try resetting the + board and trying again. */ + printf_filtered ("Failed to initialize; trying to reset board\n"); + cc = '\003'; + serial_write (&cc, 1); + sleep (2); + serial_write ("\rdb tty0\r", sizeof "\rdb tty0\r" - 1); + sleep (1); + cr = '\r'; + serial_write (&cr, 1); + } + + mips_receive_wait = hold_wait; + mips_initializing = 0; + + /* If this doesn't call error, we have connected; we don't care if + the request itself succeeds or fails. */ + mips_request ('r', (unsigned int) 0, (unsigned int) 0, &err); +} + /* Open a connection to the remote board. */ static void @@ -773,10 +885,6 @@ mips_open (name, from_tty) char *name; int from_tty; { - int err; - char cr; - char buff[DATA_MAXLEN + 1]; - if (name == 0) error ( "To open a MIPS remote debugging connection, you need to specify what serial\n\ @@ -785,28 +893,20 @@ device is attached to the target board (e.g., /dev/ttya)."); target_preopen (from_tty); if (mips_is_open) - mips_close (0); + unpush_target (&mips_ops); if (serial_open (name) == 0) perror_with_name (name); mips_is_open = 1; - /* The board seems to want to send us a packet. I don't know what - it means. */ - cr = '\r'; - serial_write (&cr, 1); - mips_receive_packet (buff); - - /* If this doesn't call error, we have connected; we don't care if - the request itself succeeds or fails. */ - mips_request ('r', (unsigned int) 0, (unsigned int) 0, &err); + mips_initialize (); if (from_tty) printf ("Remote MIPS debugging using %s\n", name); push_target (&mips_ops); /* Switch to using remote target now */ - start_remote (); /* Initialize gdb process mechanisms */ + /* FIXME: Should we call start_remote here? */ } /* Close a connection to the remote board. */ @@ -817,11 +917,14 @@ mips_close (quitting) { if (mips_is_open) { - /* Get the board out of remote debugging mode. */ - mips_request ('x', (unsigned int) 0, (unsigned int) 0, - (int *) NULL); - serial_close (); + int err; + mips_is_open = 0; + + /* Get the board out of remote debugging mode. */ + mips_request ('x', (unsigned int) 0, (unsigned int) 0, &err); + + serial_close (); } } @@ -852,7 +955,7 @@ mips_resume (step, siggnal) siggnal); mips_request (step ? 's' : 'c', - (unsigned int) read_register (PC_REGNUM), + (unsigned int) 1, (unsigned int) 0, (int *) NULL); } @@ -1099,6 +1202,28 @@ mips_files_info (ignore) printf ("Debugging a MIPS board over a serial line.\n"); } +/* Kill the process running on the board. This will actually only + work if we are doing remote debugging over the console input. I + think that if IDT/sim had the remote debug interrupt enabled on the + right port, we could interrupt the process with a break signal. */ + +static void +mips_kill () +{ +#if 0 + if (mips_is_open) + { + char cc; + + /* Send a ^C. */ + cc = '\003'; + serial_write (&cc, 1); + sleep (1); + target_mourn_inferior (); + } +#endif +} + /* Load an executable onto the board. */ static void @@ -1109,6 +1234,7 @@ mips_load (args, from_tty) bfd *abfd; asection *s; int err; + CORE_ADDR text; abfd = bfd_openr (args, 0); if (abfd == (bfd *) NULL) @@ -1117,6 +1243,7 @@ mips_load (args, from_tty) if (bfd_check_format (abfd, bfd_object) == 0) error ("%s: Not an object file", args); + text = UINT_MAX; for (s = abfd->sections; s != (asection *) NULL; s = s->next) { if ((s->flags & SEC_LOAD) != 0) @@ -1140,6 +1267,10 @@ mips_load (args, from_tty) mips_xfer_memory (vma, buffer, size, 1, &mips_ops); do_cleanups (old_chain); + + if ((bfd_get_section_flags (abfd, s) & SEC_CODE) != 0 + && vma < text) + text = vma; } } } @@ -1152,7 +1283,13 @@ mips_load (args, from_tty) bfd_close (abfd); - /* FIXME: Should we call symbol_file_add here? */ + /* FIXME: Should we call symbol_file_add here? The local variable + text exists just for this call. Making the call seems to confuse + gdb if more than one file is loaded in. Perhaps passing MAINLINE + as 1 would fix this, but it's not clear that that is correct + either since it is possible to load several files onto the board. + + symbol_file_add (args, from_tty, text, 0, 0, 0); */ } /* Start running on the target board. */ @@ -1165,7 +1302,6 @@ mips_create_inferior (execfile, args, env) { CORE_ADDR entry_pt; - /* FIXME: Actually, we probably could pass arguments. */ if (args && *args) error ("Can't pass arguments to remote MIPS board."); @@ -1176,6 +1312,8 @@ mips_create_inferior (execfile, args, env) init_wait_for_inferior (); + /* FIXME: Should we set inferior_pid here? */ + proceed (entry_pt, -1, 0); } @@ -1213,7 +1351,7 @@ Specify the serial device it is connected to (e.g., /dev/ttya).", /* to_doc */ NULL, /* to_terminal_ours_for_output */ NULL, /* to_terminal_ours */ NULL, /* to_terminal_info */ - NULL, /* to_kill */ + mips_kill, /* to_kill */ mips_load, /* to_load */ NULL, /* to_lookup_symbol */ mips_create_inferior, /* to_create_inferior */ diff --git a/gdb/tm-mips.h b/gdb/tm-mips.h index 0075662b52..9096b06f57 100644 --- a/gdb/tm-mips.h +++ b/gdb/tm-mips.h @@ -34,6 +34,11 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* Floating point is IEEE compliant */ #define IEEE_FLOAT +/* Some MIPS boards are provided both with and without a floating + point coprocessor; we provide a user settable variable to tell gdb + whether there is one or not. */ +extern int mips_fpu; + /* Define this if the C compiler puts an underscore at the front of external names before giving them to the linker. */ @@ -205,13 +210,13 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ into VALBUF. XXX floats */ #define EXTRACT_RETURN_VALUE(TYPE,REGBUF,VALBUF) \ - bcopy (REGBUF+REGISTER_BYTE (TYPE_CODE (TYPE) == TYPE_CODE_FLT ? FP0_REGNUM : 2), VALBUF, TYPE_LENGTH (TYPE)) + bcopy (REGBUF + REGISTER_BYTE ((TYPE_CODE (TYPE) == TYPE_CODE_FLT && mips_fpu) ? FP0_REGNUM : 2), VALBUF, TYPE_LENGTH (TYPE)) /* Write into appropriate registers a function return value of type TYPE, given in virtual format. */ #define STORE_RETURN_VALUE(TYPE,VALBUF) \ - write_register_bytes (REGISTER_BYTE (TYPE_CODE (TYPE) == TYPE_CODE_FLT ? FP0_REGNUM : 2), VALBUF, TYPE_LENGTH (TYPE)) + write_register_bytes (REGISTER_BYTE ((TYPE_CODE (TYPE) == TYPE_CODE_FLT && mips_fpu) ? FP0_REGNUM : 2), VALBUF, TYPE_LENGTH (TYPE)) /* Extract from an array REGBUF containing the (raw) register state the address in which a function should return its structure value, @@ -294,11 +299,11 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ 0, /* nop # ... to stop raw backtrace*/\ 0x27bd0000, /* addu sp,?0 # Pseudo prologue */\ /* Start here: */\ - MK_OP(061,SP_REGNUM,12,0), /* lwc1 $f12,0(sp) # Reload first 4 args*/\ + MK_OP(061,SP_REGNUM,12,0), /* lwc1 $f12,0(sp) # Reload FP regs*/\ MK_OP(061,SP_REGNUM,13,4), /* lwc1 $f13,4(sp) */\ MK_OP(061,SP_REGNUM,14,8), /* lwc1 $f14,8(sp) */\ MK_OP(061,SP_REGNUM,15,12), /* lwc1 $f15,12(sp) */\ - MK_OP(043,SP_REGNUM,4,0), /* lw $r4,0(sp) # Re-load FP regs*/\ + MK_OP(043,SP_REGNUM,4,0), /* lw $r4,0(sp) # Reload first 4 args*/\ MK_OP(043,SP_REGNUM,5,4), /* lw $r5,4(sp) */\ MK_OP(043,SP_REGNUM,6,8), /* lw $r6,8(sp) */\ MK_OP(043,SP_REGNUM,7,12), /* lw $r7,12(sp) */\ @@ -315,8 +320,19 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ into a call sequence of the above form stored at DUMMYNAME. */ #define FIX_CALL_DUMMY(dummyname, start_sp, fun, nargs, args, rettype, gcc_p)\ - (((int*)dummyname)[11] |= (((unsigned long)(fun)) >> 16), \ - ((int*)dummyname)[12] |= (unsigned short)(fun)) + do \ + { \ + ((int*)(dummyname))[11] |= ((unsigned long)(fun)) >> 16; \ + ((int*)(dummyname))[12] |= (unsigned short)(fun); \ + if (! mips_fpu) \ + { \ + ((int *) (dummyname))[3] = 0; \ + ((int *) (dummyname))[4] = 0; \ + ((int *) (dummyname))[5] = 0; \ + ((int *) (dummyname))[6] = 0; \ + } \ + } \ + while (0) /* There's a mess in stack frame creation. See comments in blockframe.c near reference to INIT_FRAME_PC_FIRST. */