]>
Commit | Line | Data |
---|---|---|
0d18235f | 1 | /* MI Command Set - symbol commands. |
1d506c26 | 2 | Copyright (C) 2003-2024 Free Software Foundation, Inc. |
0d18235f JB |
3 | |
4 | This file is part of GDB. | |
5 | ||
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 | |
a9762ec7 | 8 | the Free Software Foundation; either version 3 of the License, or |
0d18235f JB |
9 | (at your option) any later version. |
10 | ||
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. | |
15 | ||
16 | You should have received a copy of the GNU General Public License | |
a9762ec7 | 17 | along with this program. If not, see <http://www.gnu.org/licenses/>. */ |
0d18235f | 18 | |
0d18235f JB |
19 | #include "mi-cmds.h" |
20 | #include "symtab.h" | |
5af949e3 | 21 | #include "objfiles.h" |
0d18235f | 22 | #include "ui-out.h" |
7dc42066 AB |
23 | #include "source.h" |
24 | #include "mi-getopt.h" | |
0d18235f | 25 | |
2b03b41d SS |
26 | /* Print the list of all pc addresses and lines of code for the |
27 | provided (full or base) source file name. The entries are sorted | |
28 | in ascending PC order. */ | |
0d18235f | 29 | |
ce8f13f8 | 30 | void |
9158e49a TT |
31 | mi_cmd_symbol_list_lines (const char *command, const char *const *argv, |
32 | int argc) | |
0d18235f | 33 | { |
5af949e3 | 34 | struct gdbarch *gdbarch; |
9158e49a | 35 | const char *filename; |
0d18235f JB |
36 | struct symtab *s; |
37 | int i; | |
79a45e25 | 38 | struct ui_out *uiout = current_uiout; |
0d18235f JB |
39 | |
40 | if (argc != 1) | |
1b05df00 | 41 | error (_("-symbol-list-lines: Usage: SOURCE_FILENAME")); |
0d18235f JB |
42 | |
43 | filename = argv[0]; | |
44 | s = lookup_symtab (filename); | |
45 | ||
46 | if (s == NULL) | |
1b05df00 | 47 | error (_("-symbol-list-lines: Unknown source file name.")); |
0d18235f | 48 | |
2b03b41d SS |
49 | /* Now, dump the associated line table. The pc addresses are |
50 | already sorted by increasing values in the symbol table, so no | |
51 | need to perform any other sorting. */ | |
0d18235f | 52 | |
1acc9dca TT |
53 | struct objfile *objfile = s->compunit ()->objfile (); |
54 | gdbarch = objfile->arch (); | |
0d18235f | 55 | |
10f489e5 | 56 | ui_out_emit_list list_emitter (uiout, "lines"); |
5b607461 SM |
57 | if (s->linetable () != NULL && s->linetable ()->nitems > 0) |
58 | for (i = 0; i < s->linetable ()->nitems; i++) | |
01add95b SM |
59 | { |
60 | ui_out_emit_tuple tuple_emitter (uiout, NULL); | |
1acc9dca TT |
61 | uiout->field_core_addr ("pc", gdbarch, |
62 | s->linetable ()->item[i].pc (objfile)); | |
5b607461 | 63 | uiout->field_signed ("line", s->linetable ()->item[i].line); |
01add95b | 64 | } |
0d18235f | 65 | } |
7dc42066 AB |
66 | |
67 | /* Used by the -symbol-info-* and -symbol-info-module-* commands to print | |
68 | information about the symbol SYM in a block of index BLOCK (either | |
69 | GLOBAL_BLOCK or STATIC_BLOCK). KIND is the kind of symbol we searched | |
70 | for in order to find SYM, which impact which fields are displayed in the | |
71 | results. */ | |
72 | ||
73 | static void | |
c92d4de1 | 74 | output_debug_symbol (ui_out *uiout, domain_search_flags kind, |
7dc42066 AB |
75 | struct symbol *sym, int block) |
76 | { | |
77 | ui_out_emit_tuple tuple_emitter (uiout, NULL); | |
78 | ||
5d0027b9 SM |
79 | if (sym->line () != 0) |
80 | uiout->field_unsigned ("line", sym->line ()); | |
7dc42066 AB |
81 | uiout->field_string ("name", sym->print_name ()); |
82 | ||
c92d4de1 | 83 | if ((kind & (SEARCH_FUNCTION_DOMAIN | SEARCH_VAR_DOMAIN)) != 0) |
7dc42066 AB |
84 | { |
85 | string_file tmp_stream; | |
5f9c5a63 | 86 | type_print (sym->type (), "", &tmp_stream, -1); |
7dc42066 AB |
87 | uiout->field_string ("type", tmp_stream.string ()); |
88 | ||
d4bf9040 | 89 | std::string str = symbol_to_info_string (sym, block); |
7dc42066 AB |
90 | uiout->field_string ("description", str); |
91 | } | |
92 | } | |
93 | ||
94 | /* Actually output one nondebug symbol, puts a tuple emitter in place | |
95 | and then outputs the fields for this msymbol. */ | |
96 | ||
97 | static void | |
98 | output_nondebug_symbol (ui_out *uiout, | |
99 | const struct bound_minimal_symbol &msymbol) | |
100 | { | |
08feed99 | 101 | struct gdbarch *gdbarch = msymbol.objfile->arch (); |
7dc42066 AB |
102 | ui_out_emit_tuple tuple_emitter (uiout, NULL); |
103 | ||
104 | uiout->field_core_addr ("address", gdbarch, | |
4aeddc50 | 105 | msymbol.value_address ()); |
7dc42066 AB |
106 | uiout->field_string ("name", msymbol.minsym->print_name ()); |
107 | } | |
108 | ||
109 | /* This is the guts of the commands '-symbol-info-functions', | |
110 | '-symbol-info-variables', and '-symbol-info-types'. It searches for | |
111 | symbols matching KING, NAME_REGEXP, TYPE_REGEXP, and EXCLUDE_MINSYMS, | |
112 | and then prints the matching [m]symbols in an MI structured format. */ | |
113 | ||
114 | static void | |
c92d4de1 | 115 | mi_symbol_info (domain_search_flags kind, const char *name_regexp, |
c2512106 AB |
116 | const char *type_regexp, bool exclude_minsyms, |
117 | size_t max_results) | |
7dc42066 AB |
118 | { |
119 | global_symbol_searcher sym_search (kind, name_regexp); | |
120 | sym_search.set_symbol_type_regexp (type_regexp); | |
121 | sym_search.set_exclude_minsyms (exclude_minsyms); | |
c2512106 | 122 | sym_search.set_max_search_results (max_results); |
7dc42066 AB |
123 | std::vector<symbol_search> symbols = sym_search.search (); |
124 | ui_out *uiout = current_uiout; | |
125 | int i = 0; | |
126 | ||
127 | ui_out_emit_tuple outer_symbols_emitter (uiout, "symbols"); | |
128 | ||
129 | /* Debug symbols are placed first. */ | |
130 | if (i < symbols.size () && symbols[i].msymbol.minsym == nullptr) | |
131 | { | |
132 | ui_out_emit_list debug_symbols_list_emitter (uiout, "debug"); | |
133 | ||
134 | /* As long as we have debug symbols... */ | |
135 | while (i < symbols.size () && symbols[i].msymbol.minsym == nullptr) | |
136 | { | |
4206d69e | 137 | symtab *symtab = symbols[i].symbol->symtab (); |
7dc42066 AB |
138 | ui_out_emit_tuple symtab_tuple_emitter (uiout, nullptr); |
139 | ||
140 | uiout->field_string ("filename", | |
141 | symtab_to_filename_for_display (symtab)); | |
142 | uiout->field_string ("fullname", symtab_to_fullname (symtab)); | |
143 | ||
144 | ui_out_emit_list symbols_list_emitter (uiout, "symbols"); | |
145 | ||
146 | /* As long as we have debug symbols from this symtab... */ | |
147 | for (; (i < symbols.size () | |
148 | && symbols[i].msymbol.minsym == nullptr | |
4206d69e | 149 | && symbols[i].symbol->symtab () == symtab); |
7dc42066 AB |
150 | ++i) |
151 | { | |
152 | symbol_search &s = symbols[i]; | |
153 | ||
154 | output_debug_symbol (uiout, kind, s.symbol, s.block); | |
155 | } | |
156 | } | |
157 | } | |
158 | ||
159 | /* Non-debug symbols are placed after. */ | |
160 | if (i < symbols.size ()) | |
161 | { | |
162 | ui_out_emit_list nondebug_symbols_list_emitter (uiout, "nondebug"); | |
163 | ||
164 | /* As long as we have nondebug symbols... */ | |
165 | for (; i < symbols.size (); i++) | |
166 | { | |
167 | gdb_assert (symbols[i].msymbol.minsym != nullptr); | |
168 | output_nondebug_symbol (uiout, symbols[i].msymbol); | |
169 | } | |
170 | } | |
171 | } | |
172 | ||
c2512106 AB |
173 | /* Helper to parse the option text from an -max-results argument and return |
174 | the parsed value. If the text can't be parsed then an error is thrown. */ | |
175 | ||
176 | static size_t | |
9158e49a | 177 | parse_max_results_option (const char *arg) |
c2512106 | 178 | { |
9158e49a | 179 | char *ptr; |
c2512106 AB |
180 | long long val = strtoll (arg, &ptr, 10); |
181 | if (arg == ptr || *ptr != '\0' || val > SIZE_MAX || val < 0) | |
182 | error (_("invalid value for --max-results argument")); | |
183 | size_t max_results = (size_t) val; | |
184 | ||
185 | return max_results; | |
186 | } | |
187 | ||
7dc42066 AB |
188 | /* Helper for mi_cmd_symbol_info_{functions,variables} - depending on KIND. |
189 | Processes command line options from ARGV and ARGC. */ | |
190 | ||
191 | static void | |
c92d4de1 | 192 | mi_info_functions_or_variables (domain_search_flags kind, |
9158e49a | 193 | const char *const *argv, int argc) |
7dc42066 | 194 | { |
c2512106 | 195 | size_t max_results = SIZE_MAX; |
7dc42066 AB |
196 | const char *regexp = nullptr; |
197 | const char *t_regexp = nullptr; | |
198 | bool exclude_minsyms = true; | |
199 | ||
200 | enum opt | |
201 | { | |
c2512106 | 202 | INCLUDE_NONDEBUG_OPT, TYPE_REGEXP_OPT, NAME_REGEXP_OPT, MAX_RESULTS_OPT |
7dc42066 AB |
203 | }; |
204 | static const struct mi_opt opts[] = | |
205 | { | |
206 | {"-include-nondebug" , INCLUDE_NONDEBUG_OPT, 0}, | |
207 | {"-type", TYPE_REGEXP_OPT, 1}, | |
208 | {"-name", NAME_REGEXP_OPT, 1}, | |
c2512106 | 209 | {"-max-results", MAX_RESULTS_OPT, 1}, |
7dc42066 AB |
210 | { 0, 0, 0 } |
211 | }; | |
212 | ||
213 | int oind = 0; | |
9158e49a | 214 | const char *oarg = nullptr; |
7dc42066 AB |
215 | |
216 | while (1) | |
217 | { | |
218 | const char *cmd_string | |
c92d4de1 | 219 | = ((kind == SEARCH_FUNCTION_DOMAIN) |
7dc42066 AB |
220 | ? "-symbol-info-functions" : "-symbol-info-variables"); |
221 | int opt = mi_getopt (cmd_string, argc, argv, opts, &oind, &oarg); | |
222 | if (opt < 0) | |
223 | break; | |
224 | switch ((enum opt) opt) | |
225 | { | |
226 | case INCLUDE_NONDEBUG_OPT: | |
227 | exclude_minsyms = false; | |
228 | break; | |
229 | case TYPE_REGEXP_OPT: | |
230 | t_regexp = oarg; | |
231 | break; | |
232 | case NAME_REGEXP_OPT: | |
233 | regexp = oarg; | |
234 | break; | |
c2512106 AB |
235 | case MAX_RESULTS_OPT: |
236 | max_results = parse_max_results_option (oarg); | |
237 | break; | |
7dc42066 AB |
238 | } |
239 | } | |
240 | ||
c2512106 | 241 | mi_symbol_info (kind, regexp, t_regexp, exclude_minsyms, max_results); |
7dc42066 AB |
242 | } |
243 | ||
293b38d6 AB |
244 | /* Type for an iterator over a vector of module_symbol_search results. */ |
245 | typedef std::vector<module_symbol_search>::const_iterator | |
246 | module_symbol_search_iterator; | |
247 | ||
248 | /* Helper for mi_info_module_functions_or_variables. Display the results | |
249 | from ITER up to END or until we find a symbol that is in a different | |
250 | module, or in a different symtab than the first symbol we print. Update | |
251 | and return the new value for ITER. */ | |
252 | static module_symbol_search_iterator | |
253 | output_module_symbols_in_single_module_and_file | |
254 | (struct ui_out *uiout, module_symbol_search_iterator iter, | |
c92d4de1 | 255 | const module_symbol_search_iterator end, domain_search_flags kind) |
293b38d6 AB |
256 | { |
257 | /* The symbol for the module in which the first result resides. */ | |
258 | const symbol *first_module_symbol = iter->first.symbol; | |
259 | ||
260 | /* The symbol for the first result, and the symtab in which it resides. */ | |
261 | const symbol *first_result_symbol = iter->second.symbol; | |
4206d69e | 262 | symtab *first_symbtab = first_result_symbol->symtab (); |
293b38d6 AB |
263 | |
264 | /* Formatted output. */ | |
265 | ui_out_emit_tuple current_file (uiout, nullptr); | |
266 | uiout->field_string ("filename", | |
267 | symtab_to_filename_for_display (first_symbtab)); | |
268 | uiout->field_string ("fullname", symtab_to_fullname (first_symbtab)); | |
269 | ui_out_emit_list item_list (uiout, "symbols"); | |
270 | ||
271 | /* Repeatedly output result symbols until either we run out of symbols, | |
272 | we change module, or we change symtab. */ | |
273 | for (; (iter != end | |
274 | && first_module_symbol == iter->first.symbol | |
4206d69e | 275 | && first_symbtab == iter->second.symbol->symtab ()); |
293b38d6 AB |
276 | ++iter) |
277 | output_debug_symbol (uiout, kind, iter->second.symbol, | |
278 | iter->second.block); | |
279 | ||
280 | return iter; | |
281 | } | |
282 | ||
283 | /* Helper for mi_info_module_functions_or_variables. Display the results | |
284 | from ITER up to END or until we find a symbol that is in a different | |
285 | module than the first symbol we print. Update and return the new value | |
286 | for ITER. */ | |
287 | static module_symbol_search_iterator | |
288 | output_module_symbols_in_single_module | |
289 | (struct ui_out *uiout, module_symbol_search_iterator iter, | |
c92d4de1 | 290 | const module_symbol_search_iterator end, domain_search_flags kind) |
293b38d6 AB |
291 | { |
292 | gdb_assert (iter->first.symbol != nullptr); | |
293 | gdb_assert (iter->second.symbol != nullptr); | |
294 | ||
295 | /* The symbol for the module in which the first result resides. */ | |
296 | const symbol *first_module_symbol = iter->first.symbol; | |
297 | ||
298 | /* Create output formatting. */ | |
299 | ui_out_emit_tuple module_tuple (uiout, nullptr); | |
300 | uiout->field_string ("module", first_module_symbol->print_name ()); | |
301 | ui_out_emit_list files_list (uiout, "files"); | |
302 | ||
303 | /* The results are sorted so that symbols within the same file are next | |
304 | to each other in the list. Calling the output function once will | |
305 | print all results within a single file. We keep calling the output | |
306 | function until we change module. */ | |
307 | while (iter != end && first_module_symbol == iter->first.symbol) | |
308 | iter = output_module_symbols_in_single_module_and_file (uiout, iter, | |
309 | end, kind); | |
310 | return iter; | |
311 | } | |
312 | ||
313 | /* Core of -symbol-info-module-functions and -symbol-info-module-variables. | |
314 | KIND indicates what we are searching for, and ARGV and ARGC are the | |
315 | command line options passed to the MI command. */ | |
316 | ||
317 | static void | |
c92d4de1 TT |
318 | mi_info_module_functions_or_variables (domain_search_flags kind, |
319 | const char *const *argv, int argc) | |
293b38d6 AB |
320 | { |
321 | const char *module_regexp = nullptr; | |
322 | const char *regexp = nullptr; | |
323 | const char *type_regexp = nullptr; | |
324 | ||
325 | /* Process the command line options. */ | |
326 | ||
327 | enum opt | |
328 | { | |
329 | MODULE_REGEXP_OPT, TYPE_REGEXP_OPT, NAME_REGEXP_OPT | |
330 | }; | |
331 | static const struct mi_opt opts[] = | |
332 | { | |
333 | {"-module", MODULE_REGEXP_OPT, 1}, | |
334 | {"-type", TYPE_REGEXP_OPT, 1}, | |
335 | {"-name", NAME_REGEXP_OPT, 1}, | |
336 | { 0, 0, 0 } | |
337 | }; | |
338 | ||
339 | int oind = 0; | |
9158e49a | 340 | const char *oarg = nullptr; |
293b38d6 AB |
341 | |
342 | while (1) | |
343 | { | |
344 | const char *cmd_string | |
c92d4de1 | 345 | = ((kind == SEARCH_FUNCTION_DOMAIN) |
293b38d6 AB |
346 | ? "-symbol-info-module-functions" |
347 | : "-symbol-info-module-variables"); | |
348 | int opt = mi_getopt (cmd_string, argc, argv, opts, &oind, &oarg); | |
349 | if (opt < 0) | |
350 | break; | |
351 | switch ((enum opt) opt) | |
352 | { | |
353 | case MODULE_REGEXP_OPT: | |
354 | module_regexp = oarg; | |
355 | break; | |
356 | case TYPE_REGEXP_OPT: | |
357 | type_regexp = oarg; | |
358 | break; | |
359 | case NAME_REGEXP_OPT: | |
360 | regexp = oarg; | |
361 | break; | |
362 | } | |
363 | } | |
364 | ||
365 | std::vector<module_symbol_search> module_symbols | |
366 | = search_module_symbols (module_regexp, regexp, type_regexp, kind); | |
367 | ||
368 | struct ui_out *uiout = current_uiout; | |
369 | ui_out_emit_list all_matching_symbols (uiout, "symbols"); | |
370 | ||
371 | /* The results in the module_symbols list are ordered so symbols in the | |
372 | same module are next to each other. Repeatedly call the output | |
373 | function to print sequences of symbols that are in the same module | |
374 | until we have no symbols left to print. */ | |
375 | module_symbol_search_iterator iter = module_symbols.begin (); | |
376 | const module_symbol_search_iterator end = module_symbols.end (); | |
377 | while (iter != end) | |
378 | iter = output_module_symbols_in_single_module (uiout, iter, end, kind); | |
379 | } | |
380 | ||
7dc42066 AB |
381 | /* Implement -symbol-info-functions command. */ |
382 | ||
383 | void | |
9158e49a TT |
384 | mi_cmd_symbol_info_functions (const char *command, const char *const *argv, |
385 | int argc) | |
7dc42066 | 386 | { |
c92d4de1 | 387 | mi_info_functions_or_variables (SEARCH_FUNCTION_DOMAIN, argv, argc); |
7dc42066 AB |
388 | } |
389 | ||
293b38d6 AB |
390 | /* Implement -symbol-info-module-functions command. */ |
391 | ||
392 | void | |
9158e49a TT |
393 | mi_cmd_symbol_info_module_functions (const char *command, |
394 | const char *const *argv, int argc) | |
293b38d6 | 395 | { |
c92d4de1 | 396 | mi_info_module_functions_or_variables (SEARCH_FUNCTION_DOMAIN, argv, argc); |
293b38d6 AB |
397 | } |
398 | ||
399 | /* Implement -symbol-info-module-variables command. */ | |
400 | ||
401 | void | |
9158e49a TT |
402 | mi_cmd_symbol_info_module_variables (const char *command, |
403 | const char *const *argv, int argc) | |
293b38d6 | 404 | { |
c92d4de1 | 405 | mi_info_module_functions_or_variables (SEARCH_VAR_DOMAIN, argv, argc); |
293b38d6 AB |
406 | } |
407 | ||
db5960b4 AB |
408 | /* Implement -symbol-inf-modules command. */ |
409 | ||
410 | void | |
9158e49a TT |
411 | mi_cmd_symbol_info_modules (const char *command, const char *const *argv, |
412 | int argc) | |
db5960b4 | 413 | { |
c2512106 | 414 | size_t max_results = SIZE_MAX; |
db5960b4 AB |
415 | const char *regexp = nullptr; |
416 | ||
417 | enum opt | |
418 | { | |
c2512106 | 419 | NAME_REGEXP_OPT, MAX_RESULTS_OPT |
db5960b4 AB |
420 | }; |
421 | static const struct mi_opt opts[] = | |
422 | { | |
423 | {"-name", NAME_REGEXP_OPT, 1}, | |
c2512106 | 424 | {"-max-results", MAX_RESULTS_OPT, 1}, |
db5960b4 AB |
425 | { 0, 0, 0 } |
426 | }; | |
427 | ||
428 | int oind = 0; | |
9158e49a | 429 | const char *oarg = nullptr; |
db5960b4 AB |
430 | |
431 | while (1) | |
432 | { | |
433 | int opt = mi_getopt ("-symbol-info-modules", argc, argv, opts, | |
434 | &oind, &oarg); | |
435 | if (opt < 0) | |
436 | break; | |
437 | switch ((enum opt) opt) | |
438 | { | |
439 | case NAME_REGEXP_OPT: | |
440 | regexp = oarg; | |
441 | break; | |
c2512106 AB |
442 | case MAX_RESULTS_OPT: |
443 | max_results = parse_max_results_option (oarg); | |
444 | break; | |
db5960b4 AB |
445 | } |
446 | } | |
447 | ||
c92d4de1 | 448 | mi_symbol_info (SEARCH_MODULE_DOMAIN, regexp, nullptr, true, max_results); |
db5960b4 AB |
449 | } |
450 | ||
7dc42066 AB |
451 | /* Implement -symbol-info-types command. */ |
452 | ||
453 | void | |
9158e49a TT |
454 | mi_cmd_symbol_info_types (const char *command, const char *const *argv, |
455 | int argc) | |
7dc42066 | 456 | { |
c2512106 | 457 | size_t max_results = SIZE_MAX; |
7dc42066 AB |
458 | const char *regexp = nullptr; |
459 | ||
460 | enum opt | |
461 | { | |
c2512106 | 462 | NAME_REGEXP_OPT, MAX_RESULTS_OPT |
7dc42066 AB |
463 | }; |
464 | static const struct mi_opt opts[] = | |
465 | { | |
466 | {"-name", NAME_REGEXP_OPT, 1}, | |
c2512106 | 467 | {"-max-results", MAX_RESULTS_OPT, 1}, |
7dc42066 AB |
468 | { 0, 0, 0 } |
469 | }; | |
470 | ||
471 | int oind = 0; | |
9158e49a | 472 | const char *oarg = nullptr; |
7dc42066 AB |
473 | |
474 | while (true) | |
475 | { | |
476 | int opt = mi_getopt ("-symbol-info-types", argc, argv, opts, | |
477 | &oind, &oarg); | |
478 | if (opt < 0) | |
479 | break; | |
480 | switch ((enum opt) opt) | |
481 | { | |
482 | case NAME_REGEXP_OPT: | |
483 | regexp = oarg; | |
484 | break; | |
c2512106 AB |
485 | case MAX_RESULTS_OPT: |
486 | max_results = parse_max_results_option (oarg); | |
487 | break; | |
7dc42066 AB |
488 | } |
489 | } | |
490 | ||
c92d4de1 TT |
491 | mi_symbol_info (SEARCH_TYPE_DOMAIN | SEARCH_STRUCT_DOMAIN, regexp, nullptr, |
492 | true, max_results); | |
7dc42066 AB |
493 | } |
494 | ||
495 | /* Implement -symbol-info-variables command. */ | |
496 | ||
497 | void | |
9158e49a TT |
498 | mi_cmd_symbol_info_variables (const char *command, const char *const *argv, |
499 | int argc) | |
7dc42066 | 500 | { |
c92d4de1 | 501 | mi_info_functions_or_variables (SEARCH_VAR_DOMAIN, argv, argc); |
7dc42066 | 502 | } |