1 /* MI Command Set - symbol commands.
2    Copyright (C) 2003-2024 Free Software Foundation, Inc.
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
8    the Free Software Foundation; either version 3 of the License, or
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
17    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
18 
19 #include "mi-cmds.h"
20 #include "symtab.h"
21 #include "objfiles.h"
22 #include "ui-out.h"
23 #include "source.h"
24 #include "mi-getopt.h"
25 
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.  */
29 
30 void
mi_cmd_symbol_list_lines(const char * command,const char * const * argv,int argc)31 mi_cmd_symbol_list_lines (const char *command, const char *const *argv,
32                                 int argc)
33 {
34   struct gdbarch *gdbarch;
35   const char *filename;
36   struct symtab *s;
37   int i;
38   struct ui_out *uiout = current_uiout;
39 
40   if (argc != 1)
41     error (_("-symbol-list-lines: Usage: SOURCE_FILENAME"));
42 
43   filename = argv[0];
44   s = lookup_symtab (filename);
45 
46   if (s == NULL)
47     error (_("-symbol-list-lines: Unknown source file name."));
48 
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.  */
52 
53   struct objfile *objfile = s->compunit ()->objfile ();
54   gdbarch = objfile->arch ();
55 
56   ui_out_emit_list list_emitter (uiout, "lines");
57   if (s->linetable () != NULL && s->linetable ()->nitems > 0)
58     for (i = 0; i < s->linetable ()->nitems; i++)
59       {
60           ui_out_emit_tuple tuple_emitter (uiout, NULL);
61           uiout->field_core_addr ("pc", gdbarch,
62                                         s->linetable ()->item[i].pc (objfile));
63           uiout->field_signed ("line", s->linetable ()->item[i].line);
64       }
65 }
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
output_debug_symbol(ui_out * uiout,domain_search_flags kind,struct symbol * sym,int block)74 output_debug_symbol (ui_out *uiout, domain_search_flags kind,
75                          struct symbol *sym, int block)
76 {
77   ui_out_emit_tuple tuple_emitter (uiout, NULL);
78 
79   if (sym->line () != 0)
80     uiout->field_unsigned ("line", sym->line ());
81   uiout->field_string ("name", sym->print_name ());
82 
83   if ((kind & (SEARCH_FUNCTION_DOMAIN | SEARCH_VAR_DOMAIN)) != 0)
84     {
85       string_file tmp_stream;
86       type_print (sym->type (), "", &tmp_stream, -1);
87       uiout->field_string ("type", tmp_stream.string ());
88 
89       std::string str = symbol_to_info_string (sym, block);
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
output_nondebug_symbol(ui_out * uiout,const struct bound_minimal_symbol & msymbol)98 output_nondebug_symbol (ui_out *uiout,
99                               const struct bound_minimal_symbol &msymbol)
100 {
101   struct gdbarch *gdbarch = msymbol.objfile->arch ();
102   ui_out_emit_tuple tuple_emitter (uiout, NULL);
103 
104   uiout->field_core_addr ("address", gdbarch,
105                                 msymbol.value_address ());
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
mi_symbol_info(domain_search_flags kind,const char * name_regexp,const char * type_regexp,bool exclude_minsyms,size_t max_results)115 mi_symbol_info (domain_search_flags kind, const char *name_regexp,
116                     const char *type_regexp, bool exclude_minsyms,
117                     size_t max_results)
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);
122   sym_search.set_max_search_results (max_results);
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           {
137             symtab *symtab = symbols[i].symbol->symtab ();
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
149                       && symbols[i].symbol->symtab () == symtab);
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 
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
parse_max_results_option(const char * arg)177 parse_max_results_option (const char *arg)
178 {
179   char *ptr;
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 
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
mi_info_functions_or_variables(domain_search_flags kind,const char * const * argv,int argc)192 mi_info_functions_or_variables (domain_search_flags kind,
193                                         const char *const *argv, int argc)
194 {
195   size_t max_results = SIZE_MAX;
196   const char *regexp = nullptr;
197   const char *t_regexp = nullptr;
198   bool exclude_minsyms = true;
199 
200   enum opt
201     {
202      INCLUDE_NONDEBUG_OPT, TYPE_REGEXP_OPT, NAME_REGEXP_OPT, MAX_RESULTS_OPT
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},
209     {"-max-results", MAX_RESULTS_OPT, 1},
210     { 0, 0, 0 }
211   };
212 
213   int oind = 0;
214   const char *oarg = nullptr;
215 
216   while (1)
217     {
218       const char *cmd_string
219           = ((kind == SEARCH_FUNCTION_DOMAIN)
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;
235           case MAX_RESULTS_OPT:
236             max_results = parse_max_results_option (oarg);
237             break;
238           }
239     }
240 
241   mi_symbol_info (kind, regexp, t_regexp, exclude_minsyms, max_results);
242 }
243 
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
output_module_symbols_in_single_module_and_file(struct ui_out * uiout,module_symbol_search_iterator iter,const module_symbol_search_iterator end,domain_search_flags kind)253 output_module_symbols_in_single_module_and_file
254           (struct ui_out *uiout, module_symbol_search_iterator iter,
255            const module_symbol_search_iterator end, domain_search_flags kind)
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;
262   symtab *first_symbtab = first_result_symbol->symtab ();
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
275             && first_symbtab == iter->second.symbol->symtab ());
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
output_module_symbols_in_single_module(struct ui_out * uiout,module_symbol_search_iterator iter,const module_symbol_search_iterator end,domain_search_flags kind)288 output_module_symbols_in_single_module
289           (struct ui_out *uiout, module_symbol_search_iterator iter,
290            const module_symbol_search_iterator end, domain_search_flags kind)
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
mi_info_module_functions_or_variables(domain_search_flags kind,const char * const * argv,int argc)318 mi_info_module_functions_or_variables (domain_search_flags kind,
319                                                const char *const *argv, int argc)
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;
340   const char *oarg = nullptr;
341 
342   while (1)
343     {
344       const char *cmd_string
345           = ((kind == SEARCH_FUNCTION_DOMAIN)
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 
381 /* Implement -symbol-info-functions command.  */
382 
383 void
mi_cmd_symbol_info_functions(const char * command,const char * const * argv,int argc)384 mi_cmd_symbol_info_functions (const char *command, const char *const *argv,
385                                     int argc)
386 {
387   mi_info_functions_or_variables (SEARCH_FUNCTION_DOMAIN, argv, argc);
388 }
389 
390 /* Implement -symbol-info-module-functions command.  */
391 
392 void
mi_cmd_symbol_info_module_functions(const char * command,const char * const * argv,int argc)393 mi_cmd_symbol_info_module_functions (const char *command,
394                                              const char *const *argv, int argc)
395 {
396   mi_info_module_functions_or_variables (SEARCH_FUNCTION_DOMAIN, argv, argc);
397 }
398 
399 /* Implement -symbol-info-module-variables command.  */
400 
401 void
mi_cmd_symbol_info_module_variables(const char * command,const char * const * argv,int argc)402 mi_cmd_symbol_info_module_variables (const char *command,
403                                              const char *const *argv, int argc)
404 {
405   mi_info_module_functions_or_variables (SEARCH_VAR_DOMAIN, argv, argc);
406 }
407 
408 /* Implement -symbol-inf-modules command.  */
409 
410 void
mi_cmd_symbol_info_modules(const char * command,const char * const * argv,int argc)411 mi_cmd_symbol_info_modules (const char *command, const char *const *argv,
412                                   int argc)
413 {
414   size_t max_results = SIZE_MAX;
415   const char *regexp = nullptr;
416 
417   enum opt
418     {
419      NAME_REGEXP_OPT, MAX_RESULTS_OPT
420     };
421   static const struct mi_opt opts[] =
422   {
423     {"-name", NAME_REGEXP_OPT, 1},
424     {"-max-results", MAX_RESULTS_OPT, 1},
425     { 0, 0, 0 }
426   };
427 
428   int oind = 0;
429   const char *oarg = nullptr;
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;
442           case MAX_RESULTS_OPT:
443             max_results = parse_max_results_option (oarg);
444             break;
445           }
446     }
447 
448   mi_symbol_info (SEARCH_MODULE_DOMAIN, regexp, nullptr, true, max_results);
449 }
450 
451 /* Implement -symbol-info-types command.  */
452 
453 void
mi_cmd_symbol_info_types(const char * command,const char * const * argv,int argc)454 mi_cmd_symbol_info_types (const char *command, const char *const *argv,
455                                 int argc)
456 {
457   size_t max_results = SIZE_MAX;
458   const char *regexp = nullptr;
459 
460   enum opt
461     {
462      NAME_REGEXP_OPT, MAX_RESULTS_OPT
463     };
464   static const struct mi_opt opts[] =
465   {
466     {"-name", NAME_REGEXP_OPT, 1},
467     {"-max-results", MAX_RESULTS_OPT, 1},
468     { 0, 0, 0 }
469   };
470 
471   int oind = 0;
472   const char *oarg = nullptr;
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;
485           case MAX_RESULTS_OPT:
486             max_results = parse_max_results_option (oarg);
487             break;
488           }
489     }
490 
491   mi_symbol_info (SEARCH_TYPE_DOMAIN | SEARCH_STRUCT_DOMAIN, regexp, nullptr,
492                       true, max_results);
493 }
494 
495 /* Implement -symbol-info-variables command.  */
496 
497 void
mi_cmd_symbol_info_variables(const char * command,const char * const * argv,int argc)498 mi_cmd_symbol_info_variables (const char *command, const char *const *argv,
499                                     int argc)
500 {
501   mi_info_functions_or_variables (SEARCH_VAR_DOMAIN, argv, argc);
502 }
503