/* MI Command Set - disassemble commands. Copyright 2000, 2001, 2002 Free Software Foundation, Inc. Contributed by Cygnus Solutions (a Red Hat company). This file is part of GDB. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "defs.h" #include "target.h" #include "value.h" #include "mi-cmds.h" #include "mi-getopt.h" #include "gdb_string.h" #include "ui-out.h" #include "disasm.h" /* The arguments to be passed on the command line and parsed here are: -s START-ADDRESS | -s START-ADDRESS -e END-ADDRESS | -f FILENAME -n LINENUM [-n HOW-MANY] [-p PREV-INSTRUCTIONS] [-P PEEK-LIMIT] -- MIXED-MODE START-ADDRESS: address to start the disassembly at. END-ADDRESS: address to end the disassembly at. or: START-ADDRESS: address to start the disassembly at. or: FILENAME: The name of the file where we want disassemble from. LINE: The line around which we want to disassemble. It will disassemble the function that contins that line. In the latter two cases, the '-n HOW-MANY' and '-p PREV-INSTRUCTIONS' options can be used to specify the range of instructions to display around FILENAME:LINE or START-ADDRESS. If HOW-MANY is not specified, it will disassemble the entire function around FILENAME:LINE or START-ADDRESS. In mixed mode, HOW-MANY counts the number of disassembly lines only, not the source lines. PREV-INSTRUCTIONS may not be specified without START-ADDRESS. On some systems, it is impossible to parse the instruction streams backwards from a given instruction. In those cases, we use find_pc_offset to seek backwards, using a known previous instruction in the program and aprsing from there. In such cases, the '-P PEEK-LIMIT' option can be used to set a limit on how many instructions backwards GDB will search. The MIXED-MODE arguemnt is always required. Zero means disassembly only; 1 means mixed source and disassembly, respectively. */ static void mi_cmd_disassemble_usage (const char *message) { const char *const usage = "[-P peeklimit]" " (" " [-f filename -l linenum [-n howmany] [-p startprev]]" " | [-s startaddr [-n howmany] [-p startprev]]" " | [-s startaddr -e endaddr]" " )" " [--] mixed_mode."; error ("mi_cmd_disassemble: %s Usage: %s", message, usage); } enum mi_cmd_result mi_cmd_disassemble (char *command, char **argv, int argc) { int mixed_source_and_assembly; struct symtab *s; /* Which options have we processed ... */ int file_seen = 0; int line_seen = 0; int start_seen = 0; int end_seen = 0; int num_seen = 0; int prev_seen = 0; int peeklimit_seen = 0; /* ... and their corresponding value. */ char *file_string = NULL; int line_num = -1; int how_many = -1; CORE_ADDR low = 0; CORE_ADDR high = 0; CORE_ADDR start = 0; int prev = 0; int peeklimit = -1; /* Options processing stuff. */ int optind = 0; char *optarg; enum opt { FILE_OPT, LINE_OPT, NUM_OPT, START_OPT, END_OPT, PREV_OPT, PEEKLIMIT_OPT }; static struct mi_opt opts[] = { {"f", FILE_OPT, 1}, {"l", LINE_OPT, 1}, {"n", NUM_OPT, 1}, {"s", START_OPT, 1}, {"e", END_OPT, 1}, {"p", PREV_OPT, 1}, {"P", PEEKLIMIT_OPT, 1}, {0} }; /* Get the options with their arguments. Keep track of what we encountered. */ while (1) { int opt = mi_getopt ("mi_cmd_disassemble", argc, argv, opts, &optind, &optarg); if (opt < 0) break; switch ((enum opt) opt) { case FILE_OPT: file_string = xstrdup (optarg); file_seen = 1; break; case LINE_OPT: line_num = atoi (optarg); line_seen = 1; break; case NUM_OPT: how_many = atoi (optarg); num_seen = 1; break; case START_OPT: start = parse_and_eval_address (optarg); start_seen = 1; break; case END_OPT: high = parse_and_eval_address (optarg); end_seen = 1; break; case PREV_OPT: prev = atoi (optarg); prev_seen = 1; break; case PEEKLIMIT_OPT: peeklimit = atoi (optarg); peeklimit_seen = 1; break; } } argv += optind; argc -= optind; if (argc < 1) mi_cmd_disassemble_usage ("Must specify mixed mode argument."); if (argc > 1) mi_cmd_disassemble_usage ("Extra arguments present."); if ((argv[0][0] == '\0') || (argv[0][1] != '\0')) mi_cmd_disassemble_usage ("Mixed mode argument must be 0 or 1."); if ((argv[0][0] != '0') && (argv[0][0] != '1')) mi_cmd_disassemble_usage ("Mixed mode argument must be 0 or 1."); mixed_source_and_assembly = (argv[0][0] == '1'); if (start_seen && line_seen) mi_cmd_disassemble_usage ("May not specify both a line number and a start address."); if ((line_seen && !file_seen) || (file_seen && !line_seen)) mi_cmd_disassemble_usage ("File and line number must be specified together."); if (line_seen && file_seen) { s = lookup_symtab (file_string); if (s == NULL) error ("mi_cmd_disassemble: Invalid filename."); if (! find_line_pc (s, line_num, &start)) error ("mi_cmd_disassemble: Invalid line number."); } else if (! start_seen) mi_cmd_disassemble_usage ("No starting point specified."); if (end_seen) { if (num_seen || prev_seen) mi_cmd_disassemble_usage ("May not specify both an ending address and -n or -p."); gdb_disassembly (uiout, start, high, mixed_source_and_assembly, how_many); return MI_CMD_DONE; } if (find_pc_partial_function (start, NULL, &low, &high) == 0) error ("mi_cmd_disassemble: No function contains the specified address."); if (! num_seen) { /* If only the start address is given, disassemble the entire function around the start address. */ gdb_disassembly (uiout, low, high, mixed_source_and_assembly, how_many); return MI_CMD_DONE; } /* And finally, now we know start_seen, !line_seen, !file_seen, !end_seen, and num_seen. */ if (prev_seen) { CORE_ADDR tmp; int ret; ret = find_pc_offset (start, &tmp, -prev, 1, peeklimit); if (tmp != INVALID_ADDRESS) start = tmp; } gdb_disassembly (uiout, start, high, mixed_source_and_assembly, how_many); return MI_CMD_DONE; }