1 /* Remote debugging interface for boot monitors, for GDB.
2 Copyright 1990, 1991, 1992, 1993 Free Software Foundation, Inc.
4 This file is part of GDB.
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
20 /* This file was derived from remote-eb.c, which did a similar job, but for
21 an AMD-29K running EBMON. That file was in turn derived from remote.c
22 as mentioned in the following comment (left in for comic relief):
24 "This is like remote.c but is for a different situation--
25 having a PC running os9000 hook up with a unix machine with
26 a serial line, and running ctty com2 on the PC. os9000 has a debug
27 monitor called ROMBUG running. Not to mention that the PC
28 has PC/NFS, so it can access the same executables that gdb can,
29 over the net in real time."
31 In reality, this module talks to a debug monitor called 'ROMBUG', which
32 We communicate with ROMBUG via a direct serial line, the network version
33 of ROMBUG is not available yet.
43 #include <sys/types.h>
47 #include "remote-utils.h"
51 #include "gdb-stabs.h"
54 # define TERMINAL struct termios
56 # define TERMINAL struct sgttyb
59 struct monitor_ops *current_monitor;
60 struct cmd_list_element *showlist;
61 extern struct target_ops rombug_ops; /* Forward declaration */
62 extern struct monitor_ops rombug_cmds; /* Forward declaration */
63 extern struct cmd_list_element *setlist;
64 extern struct cmd_list_element *unsetlist;
65 extern int attach_flag;
67 static void rombug_close();
68 static void rombug_fetch_register();
69 static void rombug_fetch_registers();
70 static void rombug_store_register();
72 static int sr_get_debug(); /* flag set by "set remotedebug" */
74 static int hashmark; /* flag set by "set hash" */
75 static int rombug_is_open = 0;
77 /* FIXME: Replace with sr_get_debug (). */
78 #define LOG_FILE "monitor.log"
80 static int monitor_log = 0;
82 static int timeout = 5;
83 static int is_trace_mode = 0;
84 /* Descriptor for I/O to remote machine. Initialize it to NULL*/
85 static serial_t monitor_desc = NULL;
87 /* Send data to monitor. Works just like printf. */
89 printf_monitor(va_alist)
99 pattern = va_arg(args, char *);
101 vsprintf(buf, pattern, args);
103 if (SERIAL_WRITE(monitor_desc, buf, strlen(buf)))
104 fprintf(stderr, "SERIAL_WRITE failed: %s\n", safe_strerror(errno));
107 /* Read a character from the remote system, doing all the fancy timeout stuff*/
114 c = SERIAL_READCHAR(monitor_desc, timeout);
119 if (monitor_log && isascii(c))
120 putc(c & 0x7f, log_file);
125 if (c == SERIAL_TIMEOUT)
128 return c; /* Polls shouldn't generate timeout errors */
130 error("Timeout reading from remote system.");
133 perror_with_name("remote-monitor");
136 /* Scan input from the remote system, until STRING is found. If DISCARD is
137 non-zero, then discard non-matching input, else print it out.
138 Let the user break out immediately. */
140 expect(string, discard)
148 printf ("Expecting \"%s\"\n", string);
153 c = readchar(timeout);
162 printf ("\nMatched\n");
170 fwrite(string, 1, (p - 1) - string, stdout);
179 /* Keep discarding input until we see the ROMBUG prompt.
181 The convention for dealing with the prompt is that you
183 o *then* wait for the prompt.
185 Thus the last thing that a procedure does with the serial line
186 will be an expect_prompt(). Exception: rombug_resume does not
187 wait for the prompt, because the terminal is being handed over
188 to the inferior. However, the next thing which happens after that
189 is a rombug_wait which does wait for the prompt.
190 Note that this includes abnormal exit, e.g. error(). This is
191 necessary to prevent getting into states from which we can't
194 expect_prompt(discard)
198 /* This is a convenient place to do this. The idea is to do it often
199 enough that we never lose much data if we terminate abnormally. */
203 expect("trace", discard);
206 expect (PROMPT, discard);
210 /* Get a hex digit from the remote system & return its value.
211 If ignore_space is nonzero, ignore spaces (not newline, tab, etc). */
213 get_hex_digit(ignore_space)
219 ch = readchar(timeout);
220 if (ch >= '0' && ch <= '9')
222 else if (ch >= 'A' && ch <= 'F')
223 return ch - 'A' + 10;
224 else if (ch >= 'a' && ch <= 'f')
225 return ch - 'a' + 10;
226 else if (ch == ' ' && ignore_space)
231 error("Invalid hex digit from remote system.");
236 /* Get a byte from monitor and put it in *BYT. Accept any number
244 val = get_hex_digit (1) << 4;
245 val |= get_hex_digit (0);
249 /* Get N 32-bit words from remote, each preceded by a space,
250 and put them in registers starting at REGNO. */
252 get_hex_regs (n, regno)
260 for (i = 0; i < n; i++)
265 for (j = 0; j < 4; j++)
267 #if TARGET_BYTE_ORDER == BIG_ENDIAN
269 val = (val << 8) + b;
272 val = val + (b << (j*8));
275 supply_register (regno++, (char *) &val);
279 /* This is called not only when we first attach, but also when the
280 user types "run" after having attached. */
282 rombug_create_inferior (execfile, args, env)
289 /* Nonzero value indicates that a process really is running. */
293 error("Can't pass arguments to remote ROMBUG process");
295 if (execfile == 0 || exec_bfd == 0)
296 error("No exec file specified");
298 entry_pt = (int) bfd_get_start_address (exec_bfd);
301 fputs ("\nIn Create_inferior()", log_file);
304 /* The "process" (board) is already stopped awaiting our commands, and
305 the program is already downloaded. We just set its PC and go. */
307 init_wait_for_inferior ();
308 proceed ((CORE_ADDR)entry_pt, TARGET_SIGNAL_DEFAULT, 0);
311 /* Open a connection to a remote debugger.
312 NAME is the filename used for communication. */
314 static char dev_name[100];
317 rombug_open(args, from_tty)
322 error ("Use `target RomBug DEVICE-NAME' to use a serial port, or \n\
323 `target RomBug HOST-NAME:PORT-NUMBER' to use a network connection.");
325 target_preopen(from_tty);
328 unpush_target(&rombug_ops);
330 strcpy(dev_name, args);
331 monitor_desc = SERIAL_OPEN(dev_name);
332 if (monitor_desc == NULL)
333 perror_with_name(dev_name);
335 /* if baud rate is set by 'set remotebaud' */
336 if (SERIAL_SETBAUDRATE (monitor_desc, sr_get_baud_rate()))
338 SERIAL_CLOSE (monitor_desc);
339 perror_with_name ("RomBug");
341 SERIAL_RAW(monitor_desc);
345 log_file = fopen (LOG_FILE, "w");
346 if (log_file == NULL)
347 perror_with_name (LOG_FILE);
349 push_monitor (&rombug_cmds);
350 printf_monitor("\r"); /* CR wakes up monitor */
353 push_target (&rombug_ops);
355 printf("Remote %s connected to %s\n", target_shortname,
360 rombug_fetch_registers();
364 * Close out all files and local state before this target loses control.
368 rombug_close (quitting)
371 if (rombug_is_open) {
372 SERIAL_CLOSE(monitor_desc);
378 if (ferror(log_file))
379 fprintf(stderr, "Error writing log file.\n");
380 if (fclose(log_file) != 0)
381 fprintf(stderr, "Error closing log file.\n");
387 rombug_link(mod_name, text_reloc)
389 CORE_ADDR *text_reloc;
395 printf_monitor("l %s \r", mod_name);
397 printf_monitor(".r \r");
398 expect(REG_DELIM, 1);
399 for (i=0; i <= 7; i++)
402 for (j = 0; j < 4; j++)
405 val = (val << 8) + b;
413 /* Terminate the open connection to the remote debugger.
414 Use this when you want to detach and do something else
417 rombug_detach (from_tty)
421 printf_monitor (GO_CMD);
425 pop_target(); /* calls rombug_close to do the real work */
427 printf ("Ending remote %s debugging\n", target_shortname);
431 * Tell the remote machine to resume.
434 rombug_resume (pid, step, sig)
436 enum target_signal sig;
439 fprintf (log_file, "\nIn Resume (step=%d, sig=%d)\n", step, sig);
444 printf_monitor (STEP_CMD);
445 /* wait for the echo. */
446 expect (STEP_CMD, 1);
450 printf_monitor (GO_CMD);
451 /* swallow the echo. */
457 * Wait until the remote machine stops, then return,
458 * storing status in status just as `wait' would.
462 rombug_wait (pid, status)
464 struct target_waitstatus *status;
466 int old_timeout = timeout;
467 struct section_offsets *offs;
469 struct obj_section *obj_sec;
472 fputs ("\nIn wait ()", log_file);
474 status->kind = TARGET_WAITKIND_EXITED;
475 status->value.integer = 0;
477 timeout = 0; /* Don't time out -- user program is running. */
478 expect_prompt(1); /* Wait for prompt, outputting extraneous text */
480 status->kind = TARGET_WAITKIND_STOPPED;
481 status->value.sig = TARGET_SIGNAL_TRAP;
482 timeout = old_timeout;
483 rombug_fetch_registers();
484 pc = read_register(PC_REGNUM);
485 addr = read_register(DATABASE_REG);
486 obj_sec = find_pc_section (pc);
489 if (obj_sec->objfile != symfile_objfile)
490 new_symfile_objfile(obj_sec->objfile, 1, 0);
491 offs = ((struct section_offsets *)
492 alloca (sizeof (struct section_offsets)
493 + (symfile_objfile->num_sections * sizeof (offs->offsets))));
494 memcpy (offs, symfile_objfile->section_offsets,
495 (sizeof (struct section_offsets) +
496 (symfile_objfile->num_sections * sizeof (offs->offsets))));
497 ANOFFSET (offs, SECT_OFF_DATA) = addr;
498 ANOFFSET (offs, SECT_OFF_BSS) = addr;
500 objfile_relocate(symfile_objfile, offs);
505 /* Return the name of register number regno in the form input and output by
506 monitor. Currently, register_names just happens to contain exactly what
507 monitor wants. Lets take advantage of that just as long as possible! */
522 for (p = reg_names[regno]; *p; p++)
526 p = (char *)reg_names[regno];
533 /* read the remote registers into the block regs. */
536 rombug_fetch_registers ()
542 printf_monitor (GET_REG);
553 for (regno = 8; regno <= 15; regno++)
555 expect(REG_DELIM, 1);
556 if (regno >= 8 && regno <= 13)
559 for (j = 0; j < 2; j++)
561 #if TARGET_BYTE_ORDER == BIG_ENDIAN
563 val = (val << 8) + b;
566 val = val + (b << (j*8));
570 if (regno == 8) i = 10;
571 if (regno >= 9 && regno <= 12) i = regno + 3;
572 if (regno == 13) i = 11;
573 supply_register (i, (char *) &val);
575 else if (regno == 14)
577 get_hex_regs(1, PC_REGNUM);
579 else if (regno == 15)
586 supply_register(regno, (char *) &val);
592 /* Fetch register REGNO, or all registers if REGNO is -1.
593 Returns errno value. */
595 rombug_fetch_register (regno)
602 fprintf (log_file, "\nIn Fetch Register (reg=%s)\n", get_reg_name (regno));
608 rombug_fetch_registers ();
612 char *name = get_reg_name (regno);
613 printf_monitor (GET_REG);
614 if (regno >= 10 && regno <= 15)
619 expect (REG_DELIM, 1);
621 for (j = 0; j < 2; j++)
623 #if TARGET_BYTE_ORDER == BIG_ENDIAN
625 val = (val << 8) + b;
628 val = val + (b << (j*8));
631 supply_register (regno, (char *) &val);
633 else if (regno == 8 || regno == 9)
639 expect (REG_DELIM, 1);
640 get_hex_regs (1, regno);
645 expect (REG_DELIM, 1);
661 /* Store the remote registers from the contents of the block REGS. */
664 rombug_store_registers ()
668 for (regno = 0; regno <= PC_REGNUM; regno++)
669 rombug_store_register(regno);
671 registers_changed ();
674 /* Store register REGNO, or all if REGNO == 0.
675 return errno value. */
677 rombug_store_register (regno)
683 fprintf (log_file, "\nIn Store_register (regno=%d)\n", regno);
686 rombug_store_registers ();
690 printf ("Setting register %s to 0x%x\n", get_reg_name (regno), read_register (regno));
692 name = get_reg_name(regno);
693 if (name == 0) return;
694 printf_monitor (SET_REG, name, read_register (regno));
700 /* Get ready to modify the registers array. On machines which store
701 individual registers, this doesn't need to do anything. On machines
702 which store all the registers in one fell swoop, this makes sure
703 that registers contains all the registers from the program being
707 rombug_prepare_to_store ()
709 /* Do nothing, since we can store individual regs */
715 printf ("\tAttached to %s at %d baud.\n",
716 dev_name, sr_get_baud_rate());
719 /* Copy LEN bytes of data from debugger memory at MYADDR
720 to inferior's memory at MEMADDR. Returns length moved. */
722 rombug_write_inferior_memory (memaddr, myaddr, len)
724 unsigned char *myaddr;
731 fprintf (log_file, "\nIn Write_inferior_memory (memaddr=%x, len=%d)\n", memaddr, len);
733 printf_monitor (MEM_SET_CMD, memaddr);
734 for (i = 0; i < len; i++)
736 expect (CMD_DELIM, 1);
737 printf_monitor ("%x \r", myaddr[i]);
739 printf ("\nSet 0x%x to 0x%x\n", memaddr + i, myaddr[i]);
741 expect (CMD_DELIM, 1);
743 printf_monitor (CMD_END);
749 /* Read LEN bytes from inferior memory at MEMADDR. Put the result
750 at debugger address MYADDR. Returns length moved. */
752 rombug_read_inferior_memory(memaddr, myaddr, len)
760 /* Number of bytes read so far. */
763 /* Starting address of this pass. */
764 unsigned long startaddr;
766 /* Number of bytes to read in this pass. */
770 fprintf (log_file, "\nIn Read_inferior_memory (memaddr=%x, len=%d)\n", memaddr, len);
772 /* Note that this code works correctly if startaddr is just less
773 than UINT_MAX (well, really CORE_ADDR_MAX if there was such a
774 thing). That is, something like
775 rombug_read_bytes (CORE_ADDR_MAX - 4, foo, 4)
776 works--it never adds len To memaddr and gets 0. */
777 /* However, something like
778 rombug_read_bytes (CORE_ADDR_MAX - 3, foo, 4)
779 doesn't need to work. Detect it and give up if there's an attempt
781 if (((memaddr - 1) + len) < memaddr) {
791 if ((startaddr % 16) != 0)
792 len_this_pass -= startaddr % 16;
793 if (len_this_pass > (len - count))
794 len_this_pass = (len - count);
796 printf ("\nDisplay %d bytes at %x\n", len_this_pass, startaddr);
798 printf_monitor (MEM_DIS_CMD, startaddr, 16);
800 for (i = 0; i < len_this_pass; i++)
802 get_hex_byte (&myaddr[count++]);
804 printf ("\nRead a 0x%x from 0x%x\n", myaddr[count-1], startaddr);
807 expect(CMD_DELIM, 1);
810 printf_monitor (CMD_END);
816 /* FIXME-someday! merge these two. */
818 rombug_xfer_inferior_memory (memaddr, myaddr, len, write, target)
823 struct target_ops *target; /* ignored */
826 return rombug_write_inferior_memory (memaddr, myaddr, len);
828 return rombug_read_inferior_memory (memaddr, myaddr, len);
832 rombug_kill (args, from_tty)
836 return; /* ignore attempts to kill target system */
839 /* Clean up when a program exits.
840 The program actually lives on in the remote processor's RAM, and may be
841 run again without a download. Don't leave it full of breakpoint
845 rombug_mourn_inferior ()
847 remove_breakpoints ();
848 generic_mourn_inferior (); /* Do all the proper things now */
851 #define MAX_MONITOR_BREAKPOINTS 16
853 extern int memory_breakpoint_size;
854 static CORE_ADDR breakaddr[MAX_MONITOR_BREAKPOINTS] = {0};
857 rombug_insert_breakpoint (addr, shadow)
864 fprintf (log_file, "\nIn Insert_breakpoint (addr=%x)\n", addr);
866 for (i = 0; i <= MAX_MONITOR_BREAKPOINTS; i++)
867 if (breakaddr[i] == 0)
871 printf ("Breakpoint at %x\n", addr);
872 rombug_read_inferior_memory(addr, shadow, memory_breakpoint_size);
873 printf_monitor(SET_BREAK_CMD, addr);
878 fprintf(stderr, "Too many breakpoints (> 16) for monitor\n");
883 * _remove_breakpoint -- Tell the monitor to remove a breakpoint
886 rombug_remove_breakpoint (addr, shadow)
893 fprintf (log_file, "\nIn Remove_breakpoint (addr=%x)\n", addr);
895 for (i = 0; i < MAX_MONITOR_BREAKPOINTS; i++)
896 if (breakaddr[i] == addr)
899 printf_monitor(CLR_BREAK_CMD, addr);
904 fprintf(stderr, "Can't find breakpoint associated with 0x%x\n", addr);
908 /* Load a file. This is usually an srecord, which is ascii. No
909 protocol, just sent line by line. */
911 #define DOWNLOAD_LINE_SIZE 100
916 /* this part comment out for os9* */
919 char buf[DOWNLOAD_LINE_SIZE];
923 printf ("Loading %s to monitor\n", arg);
925 download = fopen (arg, "r");
926 if (download == NULL)
928 error (sprintf (buf, "%s Does not exist", arg));
932 printf_monitor (LOAD_CMD);
933 /* expect ("Waiting for S-records from host... ", 1); */
935 while (!feof (download))
937 bytes_read = fread (buf, sizeof (char), DOWNLOAD_LINE_SIZE, download);
944 if (SERIAL_WRITE(monitor_desc, buf, bytes_read)) {
945 fprintf(stderr, "SERIAL_WRITE failed: (while downloading) %s\n", safe_strerror(errno));
949 while (i++ <=200000) {} ; /* Ugly HACK, probably needs flow control */
950 if (bytes_read < DOWNLOAD_LINE_SIZE)
952 if (!feof (download))
953 error ("Only read %d bytes\n", bytes_read);
962 if (!feof (download))
963 error ("Never got EOF while downloading");
968 /* Put a command string, in args, out to MONITOR.
969 Output from MONITOR is placed on the users terminal until the prompt
973 rombug_command (args, fromtty)
977 if (monitor_desc == NULL)
978 error("monitor target not open.");
981 fprintf (log_file, "\nIn command (args=%s)\n", args);
984 error("Missing command.");
986 printf_monitor("%s\r", args);
987 expect(CMD_DELIM, 0);
991 /* Connect the user directly to MONITOR. This command acts just like the
992 'cu' or 'tip' command. Use <CR>~. or <CR>~^D to break out. */
994 static struct ttystate ttystate;
998 { printf("\r\n[Exiting connect mode]\r\n");
999 /*SERIAL_RESTORE(0, &ttystate);*/
1003 connect_command (args, fromtty)
1014 if (monitor_desc == NULL)
1015 error("monitor target not open.");
1018 fprintf("This command takes no args. They have been ignored.\n");
1020 printf("[Entering connect mode. Use ~. or ~^D to escape]\n");
1022 serial_raw(0, &ttystate);
1024 make_cleanup(cleanup_tty, 0);
1032 FD_SET(0, &readfds);
1033 FD_SET(monitor_desc, &readfds);
1034 numfds = select(sizeof(readfds)*8, &readfds, 0, 0, 0);
1036 while (numfds == 0);
1039 perror_with_name("select");
1041 if (FD_ISSET(0, &readfds))
1042 { /* tty input, send to monitor */
1045 perror_with_name("connect");
1047 printf_monitor("%c", c);
1061 if (c == '.' || c == '\004')
1068 if (FD_ISSET(monitor_desc, &readfds))
1084 * Define the monitor command strings. Since these are passed directly
1085 * through to a printf style function, we need can include formatting
1086 * strings. We also need a CR or LF on the end.
1088 struct monitor_ops rombug_cmds = {
1089 "g \r", /* execute or usually GO command */
1090 "g \r", /* continue command */
1091 "t \r", /* single step */
1092 "b %x\r", /* set a breakpoint */
1093 "k %x\r", /* clear a breakpoint */
1094 "c %x\r", /* set memory to a value */
1095 "d %x %d\r", /* display memory */
1096 "$%08X", /* prompt memory commands use */
1097 ".%s %x\r", /* set a register */
1098 ":", /* delimiter between registers */
1099 ". \r", /* read a register */
1100 "mf \r", /* download command */
1101 "RomBug: ", /* monitor command prompt */
1102 ": ", /* end-of-command delimitor */
1103 ".\r" /* optional command terminator */
1106 struct target_ops rombug_ops = {
1108 "Microware's ROMBUG debug monitor",
1109 "Use a remote computer running the ROMBUG debug monitor.\n\
1110 Specify the serial device it is connected to (e.g. /dev/ttya).",
1117 rombug_fetch_register,
1118 rombug_store_register,
1119 rombug_prepare_to_store,
1120 rombug_xfer_inferior_memory,
1122 rombug_insert_breakpoint,
1123 rombug_remove_breakpoint, /* Breakpoints */
1128 0, /* Terminal handling */
1130 rombug_load, /* load */
1131 rombug_link, /* lookup_symbol */
1132 rombug_create_inferior,
1133 rombug_mourn_inferior,
1135 0, /* notice_signals */
1142 1, /* has execution */
1144 0, /* Section pointers */
1145 OPS_MAGIC, /* Always the last thing */
1149 _initialize_remote_os9k ()
1151 add_target (&rombug_ops);
1154 add_set_cmd ("hash", no_class, var_boolean, (char *)&hashmark,
1155 "Set display of activity while downloading a file.\nWhen enabled, a period \'.\' is displayed.",
1160 add_set_cmd ("timeout", no_class, var_zinteger,
1162 "Set timeout in seconds for remote MIPS serial I/O.",
1167 add_set_cmd ("monitor_log", no_class, var_zinteger,
1168 (char *) &monitor_log,
1169 "Set monitor activity log on(=1) or off(=0).",
1174 add_com ("rombug <command>", class_obscure, rombug_command,
1175 "Send a command to the debug monitor.");
1177 add_com ("connect", class_obscure, connect_command,
1178 "Connect the terminal directly up to a serial based command monitor.\nUse <CR>~. or <CR>~^D to break out.");