summaryrefslogtreecommitdiff
path: root/gdb/mi/mi-symbol-cmds.c
blob: a5ce2d179d89607d4fdc64a8d2b31f8da173f9a8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
/* MI Command Set - symbol commands.
   Copyright (C) 2003-2020 Free Software Foundation, Inc.

   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 3 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, see <http://www.gnu.org/licenses/>.  */

#include "defs.h"
#include "mi-cmds.h"
#include "symtab.h"
#include "objfiles.h"
#include "ui-out.h"
#include "source.h"
#include "mi-getopt.h"

/* Print the list of all pc addresses and lines of code for the
   provided (full or base) source file name.  The entries are sorted
   in ascending PC order.  */

void
mi_cmd_symbol_list_lines (const char *command, char **argv, int argc)
{
  struct gdbarch *gdbarch;
  char *filename;
  struct symtab *s;
  int i;
  struct ui_out *uiout = current_uiout;

  if (argc != 1)
    error (_("-symbol-list-lines: Usage: SOURCE_FILENAME"));

  filename = argv[0];
  s = lookup_symtab (filename);

  if (s == NULL)
    error (_("-symbol-list-lines: Unknown source file name."));

  /* Now, dump the associated line table.  The pc addresses are
     already sorted by increasing values in the symbol table, so no
     need to perform any other sorting.  */

  gdbarch = get_objfile_arch (SYMTAB_OBJFILE (s));

  ui_out_emit_list list_emitter (uiout, "lines");
  if (SYMTAB_LINETABLE (s) != NULL && SYMTAB_LINETABLE (s)->nitems > 0)
    for (i = 0; i < SYMTAB_LINETABLE (s)->nitems; i++)
    {
      ui_out_emit_tuple tuple_emitter (uiout, NULL);
      uiout->field_core_addr ("pc", gdbarch, SYMTAB_LINETABLE (s)->item[i].pc);
      uiout->field_signed ("line", SYMTAB_LINETABLE (s)->item[i].line);
    }
}

/* Used by the -symbol-info-* and -symbol-info-module-* commands to print
   information about the symbol SYM in a block of index BLOCK (either
   GLOBAL_BLOCK or STATIC_BLOCK).  KIND is the kind of symbol we searched
   for in order to find SYM, which impact which fields are displayed in the
   results.  */

static void
output_debug_symbol (ui_out *uiout, enum search_domain kind,
		     struct symbol *sym, int block)
{
  ui_out_emit_tuple tuple_emitter (uiout, NULL);

  if (SYMBOL_LINE (sym) != 0)
    uiout->field_unsigned ("line", SYMBOL_LINE (sym));
  uiout->field_string ("name", sym->print_name ());

  if (kind == FUNCTIONS_DOMAIN || kind == VARIABLES_DOMAIN)
    {
      string_file tmp_stream;
      type_print (SYMBOL_TYPE (sym), "", &tmp_stream, -1);
      uiout->field_string ("type", tmp_stream.string ());

      std::string str = symbol_to_info_string (sym, block, kind);
      uiout->field_string ("description", str);
    }
}

/* Actually output one nondebug symbol, puts a tuple emitter in place
   and then outputs the fields for this msymbol.  */

static void
output_nondebug_symbol (ui_out *uiout,
			const struct bound_minimal_symbol &msymbol)
{
  struct gdbarch *gdbarch = get_objfile_arch (msymbol.objfile);
  ui_out_emit_tuple tuple_emitter (uiout, NULL);

  uiout->field_core_addr ("address", gdbarch,
			  BMSYMBOL_VALUE_ADDRESS (msymbol));
  uiout->field_string ("name", msymbol.minsym->print_name ());
}

/* This is the guts of the commands '-symbol-info-functions',
   '-symbol-info-variables', and '-symbol-info-types'.  It searches for
   symbols matching KING, NAME_REGEXP, TYPE_REGEXP, and EXCLUDE_MINSYMS,
   and then prints the matching [m]symbols in an MI structured format.  */

static void
mi_symbol_info (enum search_domain kind, const char *name_regexp,
		const char *type_regexp, bool exclude_minsyms,
		size_t max_results)
{
  global_symbol_searcher sym_search (kind, name_regexp);
  sym_search.set_symbol_type_regexp (type_regexp);
  sym_search.set_exclude_minsyms (exclude_minsyms);
  sym_search.set_max_search_results (max_results);
  std::vector<symbol_search> symbols = sym_search.search ();
  ui_out *uiout = current_uiout;
  int i = 0;

  ui_out_emit_tuple outer_symbols_emitter (uiout, "symbols");

  /* Debug symbols are placed first. */
  if (i < symbols.size () && symbols[i].msymbol.minsym == nullptr)
    {
      ui_out_emit_list debug_symbols_list_emitter (uiout, "debug");

      /* As long as we have debug symbols...  */
      while (i < symbols.size () && symbols[i].msymbol.minsym == nullptr)
	{
	  symtab *symtab = symbol_symtab (symbols[i].symbol);
	  ui_out_emit_tuple symtab_tuple_emitter (uiout, nullptr);

	  uiout->field_string ("filename",
			       symtab_to_filename_for_display (symtab));
	  uiout->field_string ("fullname", symtab_to_fullname (symtab));

	  ui_out_emit_list symbols_list_emitter (uiout, "symbols");

	  /* As long as we have debug symbols from this symtab...  */
	  for (; (i < symbols.size ()
		  && symbols[i].msymbol.minsym == nullptr
		  && symbol_symtab (symbols[i].symbol) == symtab);
	       ++i)
	    {
	      symbol_search &s = symbols[i];

	      output_debug_symbol (uiout, kind, s.symbol, s.block);
	    }
	}
    }

  /* Non-debug symbols are placed after.  */
  if (i < symbols.size ())
    {
      ui_out_emit_list nondebug_symbols_list_emitter (uiout, "nondebug");

      /* As long as we have nondebug symbols...  */
      for (; i < symbols.size (); i++)
	{
	  gdb_assert (symbols[i].msymbol.minsym != nullptr);
	  output_nondebug_symbol (uiout, symbols[i].msymbol);
	}
    }
}

/* Helper to parse the option text from an -max-results argument and return
   the parsed value.  If the text can't be parsed then an error is thrown.  */

static size_t
parse_max_results_option (char *arg)
{
  char *ptr = arg;
  long long val = strtoll (arg, &ptr, 10);
  if (arg == ptr || *ptr != '\0' || val > SIZE_MAX || val < 0)
    error (_("invalid value for --max-results argument"));
  size_t max_results = (size_t) val;

  return max_results;
}

/* Helper for mi_cmd_symbol_info_{functions,variables} - depending on KIND.
   Processes command line options from ARGV and ARGC.  */

static void
mi_info_functions_or_variables (enum search_domain kind, char **argv, int argc)
{
  size_t max_results = SIZE_MAX;
  const char *regexp = nullptr;
  const char *t_regexp = nullptr;
  bool exclude_minsyms = true;

  enum opt
    {
     INCLUDE_NONDEBUG_OPT, TYPE_REGEXP_OPT, NAME_REGEXP_OPT, MAX_RESULTS_OPT
    };
  static const struct mi_opt opts[] =
  {
    {"-include-nondebug" , INCLUDE_NONDEBUG_OPT, 0},
    {"-type", TYPE_REGEXP_OPT, 1},
    {"-name", NAME_REGEXP_OPT, 1},
    {"-max-results", MAX_RESULTS_OPT, 1},
    { 0, 0, 0 }
  };

  int oind = 0;
  char *oarg = nullptr;

  while (1)
    {
      const char *cmd_string
	= ((kind == FUNCTIONS_DOMAIN)
	   ? "-symbol-info-functions" : "-symbol-info-variables");
      int opt = mi_getopt (cmd_string, argc, argv, opts, &oind, &oarg);
      if (opt < 0)
	break;
      switch ((enum opt) opt)
	{
	case INCLUDE_NONDEBUG_OPT:
	  exclude_minsyms = false;
	  break;
	case TYPE_REGEXP_OPT:
	  t_regexp = oarg;
	  break;
	case NAME_REGEXP_OPT:
	  regexp = oarg;
	  break;
	case MAX_RESULTS_OPT:
	  max_results = parse_max_results_option (oarg);
	  break;
	}
    }

  mi_symbol_info (kind, regexp, t_regexp, exclude_minsyms, max_results);
}

/* Type for an iterator over a vector of module_symbol_search results.  */
typedef std::vector<module_symbol_search>::const_iterator
	module_symbol_search_iterator;

/* Helper for mi_info_module_functions_or_variables.  Display the results
   from ITER up to END or until we find a symbol that is in a different
   module, or in a different symtab than the first symbol we print.  Update
   and return the new value for ITER.  */
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, enum search_domain kind)
{
  /* The symbol for the module in which the first result resides.  */
  const symbol *first_module_symbol = iter->first.symbol;

  /* The symbol for the first result, and the symtab in which it resides.  */
  const symbol *first_result_symbol = iter->second.symbol;
  symtab *first_symbtab = symbol_symtab (first_result_symbol);

  /* Formatted output.  */
  ui_out_emit_tuple current_file (uiout, nullptr);
  uiout->field_string ("filename",
		       symtab_to_filename_for_display (first_symbtab));
  uiout->field_string ("fullname", symtab_to_fullname (first_symbtab));
  ui_out_emit_list item_list (uiout, "symbols");

  /* Repeatedly output result symbols until either we run out of symbols,
     we change module, or we change symtab.  */
  for (; (iter != end
	  && first_module_symbol == iter->first.symbol
	  && first_symbtab == symbol_symtab (iter->second.symbol));
       ++iter)
    output_debug_symbol (uiout, kind, iter->second.symbol,
			 iter->second.block);

  return iter;
}

/* Helper for mi_info_module_functions_or_variables.  Display the results
   from ITER up to END or until we find a symbol that is in a different
   module than the first symbol we print.  Update and return the new value
   for ITER.  */
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, enum search_domain kind)
{
  gdb_assert (iter->first.symbol != nullptr);
  gdb_assert (iter->second.symbol != nullptr);

  /* The symbol for the module in which the first result resides.  */
  const symbol *first_module_symbol = iter->first.symbol;

  /* Create output formatting.  */
  ui_out_emit_tuple module_tuple (uiout, nullptr);
  uiout->field_string ("module", first_module_symbol->print_name ());
  ui_out_emit_list files_list (uiout, "files");

  /* The results are sorted so that symbols within the same file are next
     to each other in the list.  Calling the output function once will
     print all results within a single file.  We keep calling the output
     function until we change module.  */
  while (iter != end && first_module_symbol == iter->first.symbol)
    iter = output_module_symbols_in_single_module_and_file (uiout, iter,
							    end, kind);
  return iter;
}

/* Core of -symbol-info-module-functions and -symbol-info-module-variables.
   KIND indicates what we are searching for, and ARGV and ARGC are the
   command line options passed to the MI command.  */

static void
mi_info_module_functions_or_variables (enum search_domain kind,
					char **argv, int argc)
{
  const char *module_regexp = nullptr;
  const char *regexp = nullptr;
  const char *type_regexp = nullptr;

  /* Process the command line options.  */

  enum opt
    {
     MODULE_REGEXP_OPT, TYPE_REGEXP_OPT, NAME_REGEXP_OPT
    };
  static const struct mi_opt opts[] =
  {
    {"-module", MODULE_REGEXP_OPT, 1},
    {"-type", TYPE_REGEXP_OPT, 1},
    {"-name", NAME_REGEXP_OPT, 1},
    { 0, 0, 0 }
  };

  int oind = 0;
  char *oarg = nullptr;

  while (1)
    {
      const char *cmd_string
	= ((kind == FUNCTIONS_DOMAIN)
	   ? "-symbol-info-module-functions"
	   : "-symbol-info-module-variables");
      int opt = mi_getopt (cmd_string, argc, argv, opts, &oind, &oarg);
      if (opt < 0)
	break;
      switch ((enum opt) opt)
	{
	case MODULE_REGEXP_OPT:
	  module_regexp = oarg;
	  break;
	case TYPE_REGEXP_OPT:
	  type_regexp = oarg;
	  break;
	case NAME_REGEXP_OPT:
	  regexp = oarg;
	  break;
	}
    }

  std::vector<module_symbol_search> module_symbols
    = search_module_symbols (module_regexp, regexp, type_regexp, kind);

  struct ui_out *uiout = current_uiout;
  ui_out_emit_list all_matching_symbols (uiout, "symbols");

  /* The results in the module_symbols list are ordered so symbols in the
     same module are next to each other.  Repeatedly call the output
     function to print sequences of symbols that are in the same module
     until we have no symbols left to print.  */
  module_symbol_search_iterator iter = module_symbols.begin ();
  const module_symbol_search_iterator end = module_symbols.end ();
  while (iter != end)
    iter = output_module_symbols_in_single_module (uiout, iter, end, kind);
}

/* Implement -symbol-info-functions command.  */

void
mi_cmd_symbol_info_functions (const char *command, char **argv, int argc)
{
  mi_info_functions_or_variables (FUNCTIONS_DOMAIN, argv, argc);
}

/* Implement -symbol-info-module-functions command.  */

void
mi_cmd_symbol_info_module_functions (const char *command, char **argv,
				     int argc)
{
  mi_info_module_functions_or_variables (FUNCTIONS_DOMAIN, argv, argc);
}

/* Implement -symbol-info-module-variables command.  */

void
mi_cmd_symbol_info_module_variables (const char *command, char **argv,
				     int argc)
{
  mi_info_module_functions_or_variables (VARIABLES_DOMAIN, argv, argc);
}

/* Implement -symbol-inf-modules command.  */

void
mi_cmd_symbol_info_modules (const char *command, char **argv, int argc)
{
  size_t max_results = SIZE_MAX;
  const char *regexp = nullptr;

  enum opt
    {
     NAME_REGEXP_OPT, MAX_RESULTS_OPT
    };
  static const struct mi_opt opts[] =
  {
    {"-name", NAME_REGEXP_OPT, 1},
    {"-max-results", MAX_RESULTS_OPT, 1},
    { 0, 0, 0 }
  };

  int oind = 0;
  char *oarg = nullptr;

  while (1)
    {
      int opt = mi_getopt ("-symbol-info-modules", argc, argv, opts,
			   &oind, &oarg);
      if (opt < 0)
	break;
      switch ((enum opt) opt)
	{
	case NAME_REGEXP_OPT:
	  regexp = oarg;
	  break;
	case MAX_RESULTS_OPT:
	  max_results = parse_max_results_option (oarg);
	  break;
	}
    }

  mi_symbol_info (MODULES_DOMAIN, regexp, nullptr, true, max_results);
}

/* Implement -symbol-info-types command.  */

void
mi_cmd_symbol_info_types (const char *command, char **argv, int argc)
{
  size_t max_results = SIZE_MAX;
  const char *regexp = nullptr;

  enum opt
    {
     NAME_REGEXP_OPT, MAX_RESULTS_OPT
    };
  static const struct mi_opt opts[] =
  {
    {"-name", NAME_REGEXP_OPT, 1},
    {"-max-results", MAX_RESULTS_OPT, 1},
    { 0, 0, 0 }
  };

  int oind = 0;
  char *oarg = nullptr;

  while (true)
    {
      int opt = mi_getopt ("-symbol-info-types", argc, argv, opts,
			   &oind, &oarg);
      if (opt < 0)
	break;
      switch ((enum opt) opt)
	{
	case NAME_REGEXP_OPT:
	  regexp = oarg;
	  break;
	case MAX_RESULTS_OPT:
	  max_results = parse_max_results_option (oarg);
	  break;
	}
    }

  mi_symbol_info (TYPES_DOMAIN, regexp, nullptr, true, max_results);
}

/* Implement -symbol-info-variables command.  */

void
mi_cmd_symbol_info_variables (const char *command, char **argv, int argc)
{
  mi_info_functions_or_variables (VARIABLES_DOMAIN, argv, argc);
}