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 495 496 497 498 499 500 501
|
/* MI Command Set - symbol commands.
Copyright (C) 2003-2024 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 "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, const char *const *argv,
int argc)
{
struct gdbarch *gdbarch;
const 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 (current_program_space, 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. */
struct objfile *objfile = s->compunit ()->objfile ();
gdbarch = objfile->arch ();
ui_out_emit_list list_emitter (uiout, "lines");
if (s->linetable () != NULL && s->linetable ()->nitems > 0)
for (i = 0; i < s->linetable ()->nitems; i++)
{
ui_out_emit_tuple tuple_emitter (uiout, NULL);
uiout->field_core_addr ("pc", gdbarch,
s->linetable ()->item[i].pc (objfile));
uiout->field_signed ("line", s->linetable ()->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, domain_search_flags kind,
struct symbol *sym, int block)
{
ui_out_emit_tuple tuple_emitter (uiout, NULL);
if (sym->line () != 0)
uiout->field_unsigned ("line", sym->line ());
uiout->field_string ("name", sym->print_name ());
if ((kind & (SEARCH_FUNCTION_DOMAIN | SEARCH_VAR_DOMAIN)) != 0)
{
string_file tmp_stream;
type_print (sym->type (), "", &tmp_stream, -1);
uiout->field_string ("type", tmp_stream.string ());
std::string str = symbol_to_info_string (sym, block);
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 bound_minimal_symbol &msymbol)
{
struct gdbarch *gdbarch = msymbol.objfile->arch ();
ui_out_emit_tuple tuple_emitter (uiout, NULL);
uiout->field_core_addr ("address", gdbarch,
msymbol.value_address ());
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 (domain_search_flags 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 = symbols[i].symbol->symtab ();
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
&& symbols[i].symbol->symtab () == 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 (const char *arg)
{
char *ptr;
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 (domain_search_flags kind,
const char *const *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;
const char *oarg = nullptr;
while (1)
{
const char *cmd_string
= ((kind == SEARCH_FUNCTION_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, domain_search_flags 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 = first_result_symbol->symtab ();
/* 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 == iter->second.symbol->symtab ());
++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, domain_search_flags 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 (domain_search_flags kind,
const char *const *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;
const char *oarg = nullptr;
while (1)
{
const char *cmd_string
= ((kind == SEARCH_FUNCTION_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, const char *const *argv,
int argc)
{
mi_info_functions_or_variables (SEARCH_FUNCTION_DOMAIN, argv, argc);
}
/* Implement -symbol-info-module-functions command. */
void
mi_cmd_symbol_info_module_functions (const char *command,
const char *const *argv, int argc)
{
mi_info_module_functions_or_variables (SEARCH_FUNCTION_DOMAIN, argv, argc);
}
/* Implement -symbol-info-module-variables command. */
void
mi_cmd_symbol_info_module_variables (const char *command,
const char *const *argv, int argc)
{
mi_info_module_functions_or_variables (SEARCH_VAR_DOMAIN, argv, argc);
}
/* Implement -symbol-inf-modules command. */
void
mi_cmd_symbol_info_modules (const char *command, const char *const *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;
const 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 (SEARCH_MODULE_DOMAIN, regexp, nullptr, true, max_results);
}
/* Implement -symbol-info-types command. */
void
mi_cmd_symbol_info_types (const char *command, const char *const *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;
const 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 (SEARCH_TYPE_DOMAIN | SEARCH_STRUCT_DOMAIN, regexp, nullptr,
true, max_results);
}
/* Implement -symbol-info-variables command. */
void
mi_cmd_symbol_info_variables (const char *command, const char *const *argv,
int argc)
{
mi_info_functions_or_variables (SEARCH_VAR_DOMAIN, argv, argc);
}
|