1 /* Remote debugging interface for MONITOR boot monitor, for GDB.
2 Copyright 1990, 1991, 1992 Free Software Foundation, Inc.
3 Contributed by Cygnus Support. Written by Rob Savoye for Cygnus.
5 This file is part of GDB.
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
21 /* This file was derived from remote-eb.c, which did a similar job, but for
22 an AMD-29K running EBMON. That file was in turn derived from remote.c
23 as mentioned in the following comment (left in for comic relief):
25 "This is like remote.c but is for an esoteric situation--
26 having an a29k board in a PC hooked up to a unix machine with
27 a serial line, and running ctty com1 on the PC, through which
28 the unix machine can run ebmon. Not to mention that the PC
29 has PC/NFS, so it can access the same executables that gdb can,
30 over the net in real time."
32 In reality, this module talks to a debug monitor called 'MONITOR', which
33 We communicate with MONITOR via either a direct serial line, or a TCP
34 (or possibly TELNET) stream to a terminal multiplexor,
35 which in turn talks to the target board.
37 This is based on remote-st2000.c. I left in the above note here for histerical
48 #include <sys/types.h>
54 # define TERMINAL struct termios
56 # define TERMINAL struct sgttyb
59 struct monitor_ops *current_monitor;
60 extern struct target_ops rom68k_ops; /* Forward declaration */
61 extern struct target_ops mon68_ops; /* Forward declaration */
62 extern struct target_ops bug_ops; /* Forward declaration */
63 extern struct monitor_ops rom68k_cmds; /* Forward declaration */
64 extern struct monitor_ops mon68_cmds; /* Forward declaration */
65 extern struct monitor_ops bug_cmds; /* Forward declaration */
66 extern struct cmd_list_element *setlist;
67 extern struct cmd_list_element *unsetlist;
68 struct cmd_list_element *showlist;
70 static void monitor_close();
71 static void monitor_fetch_register();
72 static void monitor_store_register();
73 static int kiodebug; /* flag set by "set remotedebug" */
74 static int hashmark; /* flag set by "set hash" */
76 #define LOG_FILE "monitor.log"
77 #if defined (LOG_FILE)
81 static int timeout = 24;
83 /* Descriptor for I/O to remote machine. Initialize it to -1 so that
84 monitor_open knows that we don't have a file open when the program
86 static serial_t monitor_desc;
88 /* Send data to monitor. Works just like printf. */
91 printf_monitor(va_alist)
101 pattern = va_arg(args, char *);
103 vsprintf(buf, pattern, args);
105 if (SERIAL_WRITE(monitor_desc, buf, strlen(buf)))
106 fprintf(stderr, "SERIAL_WRITE failed: %s\n", safe_strerror(errno));
109 /* Read a character from the remote system, doing all the fancy
117 c = SERIAL_READCHAR(monitor_desc, timeout);
124 putc(c & 0x7f, log_file);
130 if (c == SERIAL_TIMEOUT)
133 return c; /* Polls shouldn't generate timeout errors */
135 error("Timeout reading from remote system.");
138 perror_with_name("remote-monitor");
141 /* Scan input from the remote system, until STRING is found. If DISCARD is
142 non-zero, then discard non-matching input, else print it out.
143 Let the user break out immediately. */
145 expect(string, discard)
153 printf ("Expecting \"%s\"\n", string);
158 c = readchar(timeout);
167 printf ("\nMatched\n");
175 fwrite(string, 1, (p - 1) - string, stdout);
184 /* Keep discarding input until we see the MONITOR prompt.
186 The convention for dealing with the prompt is that you
188 o *then* wait for the prompt.
190 Thus the last thing that a procedure does with the serial line
191 will be an expect_prompt(). Exception: monitor_resume does not
192 wait for the prompt, because the terminal is being handed over
193 to the inferior. However, the next thing which happens after that
194 is a monitor_wait which does wait for the prompt.
195 Note that this includes abnormal exit, e.g. error(). This is
196 necessary to prevent getting into states from which we can't
199 expect_prompt(discard)
202 #if defined (LOG_FILE)
203 /* This is a convenient place to do this. The idea is to do it often
204 enough that we never lose much data if we terminate abnormally. */
207 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)
259 for (i = 0; i < n; i++)
264 for (j = 0; j < 8; j++)
265 val = (val << 4) + get_hex_digit (j == 0);
266 supply_register (regno++, (char *) &val);
270 /* This is called not only when we first attach, but also when the
271 user types "run" after having attached. */
273 monitor_create_inferior (execfile, args, env)
281 error("Can't pass arguments to remote MONITOR process");
283 if (execfile == 0 || exec_bfd == 0)
284 error("No exec file specified");
286 entry_pt = (int) bfd_get_start_address (exec_bfd);
288 #ifdef CREATE_INFERIOR_HOOK
289 CREATE_INFERIOR_HOOK (0); /* No process-ID */
292 fputs ("\nIn Create_inferior()", log_file);
295 /* The "process" (board) is already stopped awaiting our commands, and
296 the program is already downloaded. We just set its PC and go. */
298 clear_proceed_status ();
300 /* Tell wait_for_inferior that we've started a new process. */
301 init_wait_for_inferior ();
303 /* Set up the "saved terminal modes" of the inferior
304 based on what modes we are starting it with. */
305 target_terminal_init ();
307 /* Install inferior's terminal modes. */
308 target_terminal_inferior ();
310 /* insert_step_breakpoint (); FIXME, do we need this? */
311 proceed ((CORE_ADDR)entry_pt, -1, 0); /* Let 'er rip... */
314 /* Open a connection to a remote debugger.
315 NAME is the filename used for communication. */
317 static int baudrate = 9600;
318 static char dev_name[100];
321 general_open(args, name, from_tty)
329 target_preopen(from_tty);
331 n = sscanf(args, " %s %d %s", dev_name, &baudrate, junk);
334 error("Bad arguments. Usage: target %s <device> <speed>\n\
335 or target monitor <host> <port>\n", name);
339 monitor_desc = SERIAL_OPEN(dev_name);
342 perror_with_name(dev_name);
344 SERIAL_SETBAUDRATE(monitor_desc, baudrate);
346 SERIAL_RAW(monitor_desc);
348 #if defined (LOG_FILE)
349 log_file = fopen (LOG_FILE, "w");
350 if (log_file == NULL)
351 perror_with_name (LOG_FILE);
354 /* Hello? Are you there? */
355 printf_monitor("\r"); /* CR wakes up monitor */
360 printf("Remote %s connected to %s\n", target_shortname,
365 rom68k_open(args, from_tty)
369 push_target(&rom68k_ops);
370 push_monitor (&rom68k_cmds);
372 general_open (args, "rom68k", from_tty);
376 mon68_open(args, from_tty)
380 push_target(&mon68_ops);
381 push_monitor (&mon68_cmds);
383 general_open (args, "mon68", from_tty);
387 bug_open(args, from_tty)
391 push_target(&bug_ops);
392 push_monitor (&bug_cmds);
394 general_open (args, "bug", from_tty);
398 * _close -- Close out all files and local state before this target loses control.
402 monitor_close (quitting)
405 SERIAL_CLOSE(monitor_desc);
407 #if defined (LOG_FILE)
409 if (ferror(log_file))
410 fprintf(stderr, "Error writing log file.\n");
411 if (fclose(log_file) != 0)
412 fprintf(stderr, "Error closing log file.\n");
417 /* Terminate the open connection to the remote debugger.
418 Use this when you want to detach and do something else
421 monitor_detach (from_tty)
424 pop_target(); /* calls monitor_close to do the real work */
426 printf ("Ending remote %s debugging\n", target_shortname);
430 * _resume -- Tell the remote machine to resume.
433 monitor_resume (step, sig)
437 fprintf (log_file, "\nIn Resume (step=%d, sig=%d)\n", step, sig);
442 printf_monitor (STEP_CMD);
443 /* wait for the echo. */
444 expect (STEP_CMD, 1);
448 printf_monitor (GO_CMD);
449 /* swallow the echo. */
455 * _wait -- Wait until the remote machine stops, then return,
456 * storing status in status just as `wait' would.
460 monitor_wait (status)
463 int old_timeout = timeout;
465 fputs ("\nIn wait ()", log_file);
468 WSETEXIT ((*status), 0);
470 timeout = 0; /* Don't time out -- user program is running. */
472 expect_prompt(0); /* Wait for prompt, outputting extraneous text */
474 WSETSTOP ((*status), SIGTRAP);
476 timeout = old_timeout;
481 /* Return the name of register number regno in the form input and output by
482 monitor. Currently, register_names just happens to contain exactly what
483 monitor wants. Lets take advantage of that just as long as possible! */
497 for (p = reg_names[regno]; *p; p++)
504 /* read the remote registers into the block regs. */
507 monitor_fetch_registers ()
511 /* yeah yeah, i know this is horribly inefficient. but it isn't done
512 very often... i'll clean it up later. */
514 for (regno = 0; regno <= PC_REGNUM; regno++)
515 monitor_fetch_register(regno);
518 /* Fetch register REGNO, or all registers if REGNO is -1.
519 Returns errno value. */
521 monitor_fetch_register (regno)
527 fprintf (log_file, "\nIn Fetch Register (reg=%s)\n", get_reg_name (regno));
533 monitor_fetch_registers ();
537 char *name = get_reg_name (regno);
538 printf_monitor (GET_REG, name);
540 expect (REG_DELIM, 1);
541 if (strcasecmp (name, "SR") == 0)
544 for (j = 0; j < 4; j++)
545 val = (val << 4) + get_hex_digit (j == 0);
546 supply_register (regno, (char *) &val);
550 get_hex_regs (1, regno);
555 printf_monitor (CMD_END);
562 /* Store the remote registers from the contents of the block REGS. */
565 monitor_store_registers ()
569 for (regno = 0; regno <= PC_REGNUM; regno++)
570 monitor_store_register(regno);
572 registers_changed ();
575 /* Store register REGNO, or all if REGNO == 0.
576 return errno value. */
578 monitor_store_register (regno)
582 fprintf (log_file, "\nIn Store_register (regno=%d)\n", regno);
585 monitor_store_registers ();
589 printf ("Setting register %s to 0x%x\n", get_reg_name (regno), read_register (regno));
591 printf_monitor (SET_REG, get_reg_name (regno),
592 read_register (regno));
598 /* Get ready to modify the registers array. On machines which store
599 individual registers, this doesn't need to do anything. On machines
600 which store all the registers in one fell swoop, this makes sure
601 that registers contains all the registers from the program being
605 monitor_prepare_to_store ()
607 /* Do nothing, since we can store individual regs */
611 monitor_files_info ()
613 printf ("\tAttached to %s at %d baud.\n",
617 /* Copy LEN bytes of data from debugger memory at MYADDR
618 to inferior's memory at MEMADDR. Returns length moved. */
620 monitor_write_inferior_memory (memaddr, myaddr, len)
622 unsigned char *myaddr;
629 fprintf (log_file, "\nIn Write_inferior_memory (memaddr=%x, len=%d)\n", memaddr, len);
631 for (i = 0; i < len; i++)
633 printf_monitor (MEM_SET_CMD, memaddr + i);
634 expect (sprintf (buf, MEM_PROMPT, memaddr + i), 1);
636 printf_monitor ("%x", myaddr[i]);
638 printf ("\nSet 0x%x to 0x%x\n", memaddr + i, myaddr[i]);
641 /*** expect (sprintf (buf, MEM_PROMPT, memaddr + i +1), 1);
642 expect (CMD_DELIM); ***/
643 printf_monitor (CMD_END);
650 /* Read LEN bytes from inferior memory at MEMADDR. Put the result
651 at debugger address MYADDR. Returns length moved. */
653 monitor_read_inferior_memory(memaddr, myaddr, len)
661 /* Number of bytes read so far. */
664 /* Starting address of this pass. */
665 unsigned long startaddr;
667 /* Number of bytes to read in this pass. */
671 fprintf (log_file, "\nIn Read_inferior_memory (memaddr=%x, len=%d)\n", memaddr, len);
674 /* Note that this code works correctly if startaddr is just less
675 than UINT_MAX (well, really CORE_ADDR_MAX if there was such a
676 thing). That is, something like
677 monitor_read_bytes (CORE_ADDR_MAX - 4, foo, 4)
678 works--it never adds len To memaddr and gets 0. */
679 /* However, something like
680 monitor_read_bytes (CORE_ADDR_MAX - 3, foo, 4)
681 doesn't need to work. Detect it and give up if there's an attempt
683 if (((memaddr - 1) + len) < memaddr) {
693 if ((startaddr % 16) != 0)
694 len_this_pass -= startaddr % 16;
695 if (len_this_pass > (len - count))
696 len_this_pass = (len - count);
698 printf ("\nDisplay %d bytes at %x\n", len_this_pass, startaddr);
700 for (i = 0; i < len_this_pass; i++)
702 printf_monitor (MEM_DIS_CMD, startaddr);
703 expect (sprintf(buf, MEM_PROMPT, startaddr), 1);
704 get_hex_byte (&myaddr[count++]);
706 printf ("\nRead a 0x%x from 0x%x\n", myaddr[count-1], startaddr);
710 printf_monitor (CMD_END);
719 /* FIXME-someday! merge these two. */
721 monitor_xfer_inferior_memory (memaddr, myaddr, len, write, target)
726 struct target_ops *target; /* ignored */
729 return monitor_write_inferior_memory (memaddr, myaddr, len);
731 return monitor_read_inferior_memory (memaddr, myaddr, len);
735 monitor_kill (args, from_tty)
739 return; /* ignore attempts to kill target system */
742 /* Clean up when a program exits.
743 The program actually lives on in the remote processor's RAM, and may be
744 run again without a download. Don't leave it full of breakpoint
748 monitor_mourn_inferior ()
750 remove_breakpoints ();
751 generic_mourn_inferior (); /* Do all the proper things now */
754 #define MAX_MONITOR_BREAKPOINTS 16
756 extern int memory_breakpoint_size;
757 static CORE_ADDR breakaddr[MAX_MONITOR_BREAKPOINTS] = {0};
760 monitor_insert_breakpoint (addr, shadow)
767 fprintf (log_file, "\nIn Insert_breakpoint (addr=%x)\n", addr);
769 for (i = 0; i <= MAX_MONITOR_BREAKPOINTS; i++)
770 if (breakaddr[i] == 0)
774 printf ("Breakpoint at %x\n", addr);
775 monitor_read_inferior_memory(addr, shadow, memory_breakpoint_size);
776 printf_monitor(SET_BREAK_CMD, addr);
781 fprintf(stderr, "Too many breakpoints (> 16) for monitor\n");
786 * _remove_breakpoint -- Tell the monitor to remove a breakpoint
789 monitor_remove_breakpoint (addr, shadow)
796 fprintf (log_file, "\nIn Remove_breakpoint (addr=%x)\n", addr);
798 for (i = 0; i < MAX_MONITOR_BREAKPOINTS; i++)
799 if (breakaddr[i] == addr)
802 /* some monitors remove breakpoints based on the address */
803 if (strcasecmp (target_shortname, "bug") == 0)
804 printf_monitor(CLR_BREAK_CMD, addr);
806 printf_monitor(CLR_BREAK_CMD, i);
811 fprintf(stderr, "Can't find breakpoint associated with 0x%x\n", addr);
815 /* Load a file. This is usually an srecord, which is ascii. No
816 protocol, just sent line by line. */
818 #define DOWNLOAD_LINE_SIZE 100
824 char buf[DOWNLOAD_LINE_SIZE];
828 printf ("Loading %s to monitor\n", arg);
830 download = fopen (arg, "r");
831 if (download == NULL)
833 error (sprintf (buf, "%s Does not exist", arg));
837 printf_monitor (LOAD_CMD);
838 /* expect ("Waiting for S-records from host... ", 1); */
840 while (!feof (download))
842 bytes_read = fread (buf, sizeof (char), DOWNLOAD_LINE_SIZE, download);
849 if (SERIAL_WRITE(monitor_desc, buf, bytes_read)) {
850 fprintf(stderr, "SERIAL_WRITE failed: (while downloading) %s\n", safe_strerror(errno));
854 while (i++ <=200000) {} ; /* Ugly HACK, probably needs flow control */
855 if (bytes_read < DOWNLOAD_LINE_SIZE)
857 if (!feof (download))
858 error ("Only read %d bytes\n", bytes_read);
867 if (!feof (download))
868 error ("Never got EOF while downloading");
872 /* Put a command string, in args, out to MONITOR. Output from MONITOR is placed
873 on the users terminal until the prompt is seen. */
876 monitor_command (args, fromtty)
881 fprintf (log_file, "\nIn command (args=%s)\n", args);
883 if (monitor_desc < 0)
884 error("monitor target not open.");
887 error("Missing command.");
889 printf_monitor("%s\r", args);
895 /* Connect the user directly to MONITOR. This command acts just like the
896 'cu' or 'tip' command. Use <CR>~. or <CR>~^D to break out. */
898 static struct ttystate ttystate;
902 { printf("\r\n[Exiting connect mode]\r\n");
903 /*SERIAL_RESTORE(0, &ttystate);*/
907 connect_command (args, fromtty)
918 if (monitor_desc < 0)
919 error("monitor target not open.");
922 fprintf("This command takes no args. They have been ignored.\n");
924 printf("[Entering connect mode. Use ~. or ~^D to escape]\n");
926 serial_raw(0, &ttystate);
928 make_cleanup(cleanup_tty, 0);
937 FD_SET(monitor_desc, &readfds);
938 numfds = select(sizeof(readfds)*8, &readfds, 0, 0, 0);
943 perror_with_name("select");
945 if (FD_ISSET(0, &readfds))
946 { /* tty input, send to monitor */
949 perror_with_name("connect");
951 printf_monitor("%c", c);
965 if (c == '.' || c == '\004')
972 if (FD_ISSET(monitor_desc, &readfds))
988 * Define the monitor command strings. Since these are passed directly
989 * through to a printf style function, we need can include formatting
990 * strings. We also need a CR or LF on the end.
992 struct monitor_ops rom68k_cmds = {
993 "go \r", /* execute or usually GO command */
994 "go \r", /* continue command */
995 "st \r", /* single step */
996 "db %x\r", /* set a breakpoint */
997 "cb %x\r", /* clear a breakpoint */
998 "pm %x\r", /* set memory to a value */
999 "pm %x\r", /* display memory */
1000 "-%08X ", /* prompt memory commands use */
1001 "pr %s %x\r", /* set a register */
1002 ": ", /* delimiter between registers */
1003 "pr %s\r", /* read a register */
1004 "dc \r", /* download command */
1005 "ROM68K :->", /* monitor command prompt */
1006 "=", /* end-of-command delimitor */
1007 ".\r" /* optional command terminator */
1010 struct monitor_ops bug_cmds = {
1011 "go \r", /* execute or usually GO command */
1012 "go \r", /* continue command */
1013 "gn \r", /* single step */
1014 "br %x\r", /* set a breakpoint */
1015 "nobr %x\r", /* clear a breakpoint */
1016 "mm %x\r", /* set memory to a value */
1017 "mm %x\r", /* display memory */
1018 "%08X", /* prompt memory commands use */
1019 "rs %s %x\r", /* set a register */
1020 "=", /* delimiter between registers */
1021 "rm %s\r", /* read a register */
1022 "lo 0\r", /* download command */
1023 "Bug>", /* monitor command prompt */
1024 "? ", /* end-of-command delimitor */
1025 ".\r" /* optional command terminator */
1028 /* Define the target subroutine names */
1029 struct monitor_ops mon68_cmds = {
1030 "", /* execute or usually GO command */
1031 "", /* continue command */
1032 "", /* single step */
1033 "", /* set a breakpoint */
1034 "", /* clear a breakpoint */
1035 "", /* set memory to a value */
1036 "", /* display memory */
1037 "", /* set a register */
1038 "", /* delimiter between registers */
1039 "", /* read a register */
1040 "", /* download command */
1041 ">", /* monitor command prompt */
1042 "", /* end-of-command delimitor */
1043 "" /* optional command terminator */
1046 struct target_ops rom68k_ops = {
1048 "Integrated System's ROM68K remote debug monitor",
1049 "Use a remote computer running the ROM68K debug monitor, connected by a\n\
1050 serial line. Arguments are the name of the device for the serial line,\n\
1051 the speed to connect at in bits per second.",
1058 monitor_fetch_register,
1059 monitor_store_register,
1060 monitor_prepare_to_store,
1061 monitor_xfer_inferior_memory,
1063 monitor_insert_breakpoint,
1064 monitor_remove_breakpoint, /* Breakpoints */
1069 0, /* Terminal handling */
1071 monitor_load, /* load */
1072 0, /* lookup_symbol */
1073 monitor_create_inferior,
1074 monitor_mourn_inferior,
1076 0, /* notice_signals */
1083 1, /* all mem, mem, stack, regs, exec */
1085 0, /* Section pointers */
1086 OPS_MAGIC, /* Always the last thing */
1089 struct target_ops bug_ops = {
1091 "Motorola's BUG remote serial debug monitor",
1092 "Use a remote computer running Motorola's BUG debug monitor, connected by a\n\
1093 serial line. Arguments are the name of the device for the serial line,\n\
1094 the speed to connect at in bits per second.",
1101 monitor_fetch_register,
1102 monitor_store_register,
1103 monitor_prepare_to_store,
1104 monitor_xfer_inferior_memory,
1106 monitor_insert_breakpoint,
1107 monitor_remove_breakpoint, /* Breakpoints */
1112 0, /* Terminal handling */
1114 monitor_load, /* load */
1115 0, /* lookup_symbol */
1116 monitor_create_inferior,
1117 monitor_mourn_inferior,
1119 0, /* notice_signals */
1126 1, /* all mem, mem, stack, regs, exec */
1128 0, /* Section pointers */
1129 OPS_MAGIC, /* Always the last thing */
1132 struct target_ops mon68_ops = {
1134 "Intermetric's MON68 remote serial debug monitor",
1135 "Use a remote computer running the MON68 debug monitor, connected by a\n\
1136 serial line. Arguments are the name of the device for the serial line,\n\
1137 the speed to connect at in bits per second.",
1144 monitor_fetch_register,
1145 monitor_store_register,
1146 monitor_prepare_to_store,
1147 monitor_xfer_inferior_memory,
1149 monitor_insert_breakpoint,
1150 monitor_remove_breakpoint, /* Breakpoints */
1155 0, /* Terminal handling */
1157 monitor_load, /* load */
1158 0, /* lookup_symbol */
1159 monitor_create_inferior,
1160 monitor_mourn_inferior,
1162 0, /* notice_signals */
1169 1, /* all mem, mem, stack, regs, exec */
1171 0, /* Section pointers */
1172 OPS_MAGIC, /* Always the last thing */
1176 _initialize_remote_monitors ()
1179 add_set_cmd ("remotedebug", no_class, var_boolean,
1181 "Set debugging of I/O to a serial based Monitor.\n\
1182 When enabled, debugging info is displayed.",
1186 add_set_cmd ("hash", no_class, var_boolean,
1188 "Set display of activity while downloading a file.\n\
1189 When enabled, a period \'.\' is displayed.",
1193 /* generic monitor command */
1194 add_com ("monitor <command>", class_obscure, monitor_command,
1195 "Send a command to the debug monitor.");
1196 add_com ("connect", class_obscure, connect_command,
1197 "Connect the terminal directly up to a serial based command monitor.\n\
1198 Use <CR>~. or <CR>~^D to break out.");
1200 add_target (&rom68k_ops);
1201 /* add_target (&mon68_ops); */
1202 add_target (&bug_ops);