1 /* MI Command Set - disassemble commands.
2 Copyright (C) 2000-2024 Free Software Foundation, Inc.
3 Contributed by Cygnus Solutions (a Red Hat company).
4
5 This file is part of GDB.
6
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 3 of the License, or
10 (at your option) any later version.
11
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.
16
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>. */
19
20 #include "arch-utils.h"
21 #include "target.h"
22 #include "value.h"
23 #include "mi-cmds.h"
24 #include "mi-getopt.h"
25 #include "ui-out.h"
26 #include "disasm.h"
27
28 /* The arguments to be passed on the command line and parsed here are
29 either:
30
31 START-ADDRESS: address to start the disassembly at.
32 END-ADDRESS: address to end the disassembly at.
33
34 or:
35
36 FILENAME: The name of the file where we want disassemble from.
37 LINE: The line around which we want to disassemble. It will
38 disassemble the function that contains that line.
39 HOW_MANY: Number of disassembly lines to display. With source, it
40 is the number of disassembly lines only, not counting the source
41 lines.
42
43 always required:
44
45 MODE: 0 -- disassembly.
46 1 -- disassembly and source (with deprecated source-centric view).
47 2 -- disassembly and opcodes.
48 3 -- disassembly, source-centric and opcodes.
49 4 -- disassembly, and source (with pc-centric view).
50 5 -- disassembly, source (pc-centric) and opcodes. */
51
52 void
mi_cmd_disassemble(const char * command,const char * const * argv,int argc)53 mi_cmd_disassemble (const char *command, const char *const *argv, int argc)
54 {
55 struct gdbarch *gdbarch = get_current_arch ();
56 struct ui_out *uiout = current_uiout;
57 CORE_ADDR start;
58
59 int mode;
60 gdb_disassembly_flags disasm_flags;
61 struct symtab *s;
62
63 /* Which options have we processed ... */
64 bool file_seen = false;
65 bool line_seen = false;
66 bool num_seen = false;
67 bool start_seen = false;
68 bool end_seen = false;
69 bool addr_seen = false;
70 bool opcodes_seen = false;
71 bool source_seen = false;
72
73 /* ... and their corresponding value. */
74 const char *file_string = NULL;
75 int line_num = -1;
76 int how_many = -1;
77 CORE_ADDR low = 0;
78 CORE_ADDR high = 0;
79 CORE_ADDR addr = 0;
80
81 /* Flags to handle the --opcodes option. */
82 enum opcodes_mode
83 {
84 OPCODES_DEFAULT, OPCODES_NONE, OPCODES_DISPLAY, OPCODES_BYTES
85 };
86 enum opcodes_mode opcodes_mode = OPCODES_DEFAULT;
87
88 /* Handle the -source option. */
89 bool show_source = false;
90
91 /* Options processing stuff. */
92 int oind = 0;
93 const char *oarg;
94 enum opt
95 {
96 FILE_OPT, LINE_OPT, NUM_OPT, START_OPT, END_OPT, ADDR_OPT, OPCODES_OPT,
97 SHOW_SRC_OPT
98 };
99 static const struct mi_opt opts[] =
100 {
101 {"f", FILE_OPT, 1},
102 {"l", LINE_OPT, 1},
103 {"n", NUM_OPT, 1},
104 {"s", START_OPT, 1},
105 {"e", END_OPT, 1},
106 {"a", ADDR_OPT, 1},
107 {"-opcodes", OPCODES_OPT, 1},
108 {"-source", SHOW_SRC_OPT, 0},
109 { 0, 0, 0 }
110 };
111
112 /* Get the options with their arguments. Keep track of what we
113 encountered. */
114 while (1)
115 {
116 int opt = mi_getopt ("-data-disassemble", argc, argv, opts,
117 &oind, &oarg);
118 if (opt < 0)
119 break;
120 switch ((enum opt) opt)
121 {
122 case FILE_OPT:
123 file_string = oarg;
124 file_seen = true;
125 break;
126 case LINE_OPT:
127 line_num = atoi (oarg);
128 line_seen = true;
129 break;
130 case NUM_OPT:
131 how_many = atoi (oarg);
132 num_seen = true;
133 break;
134 case START_OPT:
135 low = parse_and_eval_address (oarg);
136 start_seen = true;
137 break;
138 case END_OPT:
139 high = parse_and_eval_address (oarg);
140 end_seen = true;
141 break;
142 case ADDR_OPT:
143 addr = parse_and_eval_address (oarg);
144 addr_seen = true;
145 break;
146 case OPCODES_OPT:
147 opcodes_seen = true;
148 if (strcmp (oarg, "none") == 0)
149 opcodes_mode = OPCODES_NONE;
150 else if (strcmp (oarg, "display") == 0)
151 opcodes_mode = OPCODES_DISPLAY;
152 else if (strcmp (oarg, "bytes") == 0)
153 opcodes_mode = OPCODES_BYTES;
154 else
155 error (_("-data-disassemble: unknown value for -opcodes argument"));
156 break;
157 case SHOW_SRC_OPT:
158 source_seen = true;
159 show_source = true;
160 break;
161 }
162 }
163 argv += oind;
164 argc -= oind;
165
166 /* Allow only filename + linenum (with how_many which is not
167 required) OR start_addr + end_addr OR addr. */
168
169 if (!(
170 ( line_seen && file_seen && !start_seen && !end_seen
171 && !addr_seen)
172
173 || (!line_seen && !file_seen && !num_seen && start_seen && end_seen
174 && !addr_seen)
175
176 || (!line_seen && !file_seen && !num_seen && !start_seen && !end_seen
177 && addr_seen))
178 || argc > 1)
179 error (_("-data-disassemble: Usage: "
180 "( -f filename -l linenum [-n howmany] |"
181 " -s startaddr -e endaddr | -a addr ) "
182 "[ --opcodes mode ] [ --source ] [ [--] mode ]."));
183
184 if (argc == 1)
185 {
186 mode = atoi (argv[0]);
187 if (mode < 0 || mode > 5)
188 error (_("-data-disassemble: Mode argument must be in the range 0-5."));
189 }
190 else
191 mode = 0;
192
193 if (mode != 0 && (source_seen || opcodes_seen))
194 error (_("-data-disassemble: --opcodes and --source can only be used with mode 0"));
195
196 /* Convert the mode into a set of disassembly flags. */
197
198 disasm_flags = 0; /* Initialize here for -Wall. */
199 switch (mode)
200 {
201 case 0:
202 break;
203 case 1:
204 disasm_flags |= DISASSEMBLY_SOURCE_DEPRECATED;
205 break;
206 case 2:
207 disasm_flags |= DISASSEMBLY_RAW_BYTES;
208 break;
209 case 3:
210 disasm_flags |= DISASSEMBLY_SOURCE_DEPRECATED | DISASSEMBLY_RAW_BYTES;
211 break;
212 case 4:
213 disasm_flags |= DISASSEMBLY_SOURCE;
214 break;
215 case 5:
216 disasm_flags |= DISASSEMBLY_SOURCE | DISASSEMBLY_RAW_BYTES;
217 break;
218 default:
219 gdb_assert_not_reached ("bad disassembly mode");
220 }
221
222 /* Now handle the (optional) --opcodes argument. This partially
223 overrides the mode value. */
224 if (opcodes_mode != OPCODES_DEFAULT)
225 {
226 /* Remove any existing flags related to opcodes display. */
227 disasm_flags &= ~(DISASSEMBLY_RAW_BYTES | DISASSEMBLY_RAW_INSN);
228
229 /* Add back any required flags. */
230 if (opcodes_mode == OPCODES_DISPLAY)
231 disasm_flags |= DISASSEMBLY_RAW_INSN;
232 else if (opcodes_mode == OPCODES_BYTES)
233 disasm_flags |= DISASSEMBLY_RAW_BYTES;
234 }
235
236 /* Handle the optional --source argument. */
237 if (show_source)
238 {
239 disasm_flags &= ~DISASSEMBLY_SOURCE_DEPRECATED;
240 disasm_flags |= DISASSEMBLY_SOURCE;
241 }
242
243 /* We must get the function beginning and end where line_num is
244 contained. */
245
246 if (line_seen && file_seen)
247 {
248 s = lookup_symtab (file_string);
249 if (s == NULL)
250 error (_("-data-disassemble: Invalid filename."));
251 if (!find_line_pc (s, line_num, &start))
252 error (_("-data-disassemble: Invalid line number"));
253 if (find_pc_partial_function (start, NULL, &low, &high) == 0)
254 error (_("-data-disassemble: "
255 "No function contains specified address"));
256 }
257 else if (addr_seen)
258 {
259 if (find_pc_partial_function (addr, NULL, &low, &high) == 0)
260 error (_("-data-disassemble: "
261 "No function contains specified address"));
262 }
263
264 gdb_disassembly (gdbarch, uiout,
265 disasm_flags,
266 how_many, low, high);
267 }
268