X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gdb%2Fsymtab.c;h=d5e18a64d06c12d1153d2b8cb5fbb8ea4470a802;hb=1d94a5a36a614cf7ebe259d7660f4fa725f38ee2;hp=d8a7a16e0733694d6425a994a82c1aab8d82b1d1;hpb=cd2bb709940d33668fe6dbe8d4ffee0ed44c25e6;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/symtab.c b/gdb/symtab.c index d8a7a16e07..d5e18a64d0 100644 --- a/gdb/symtab.c +++ b/gdb/symtab.c @@ -1,6 +1,6 @@ /* Symbol table lookup for the GNU debugger, GDB. - Copyright (C) 1986-2018 Free Software Foundation, Inc. + Copyright (C) 1986-2019 Free Software Foundation, Inc. This file is part of GDB. @@ -43,6 +43,7 @@ #include "cli/cli-utils.h" #include "fnmatch.h" #include "hashtab.h" +#include "typeprint.h" #include "gdb_obstack.h" #include "block.h" @@ -404,12 +405,11 @@ iterate_over_some_symtabs (const char *name, gdb::function_view callback) { struct compunit_symtab *cust; - struct symtab *s; const char* base_name = lbasename (name); for (cust = first; cust != NULL && cust != after_last; cust = cust->next) { - ALL_COMPUNIT_FILETABS (cust, s) + for (symtab *s : compunit_filetabs (cust)) { if (compare_filenames_for_search (s->filename, name)) { @@ -463,7 +463,6 @@ void iterate_over_symtabs (const char *name, gdb::function_view callback) { - struct objfile *objfile; gdb::unique_xmalloc_ptr real_path; /* Here we are interested in canonicalizing an absolute path, not @@ -474,7 +473,7 @@ iterate_over_symtabs (const char *name, gdb_assert (IS_ABSOLUTE_PATH (real_path.get ())); } - ALL_OBJFILES (objfile) + for (objfile *objfile : all_objfiles (current_program_space)) { if (iterate_over_some_symtabs (name, real_path.get (), objfile->compunit_symtabs, NULL, @@ -485,7 +484,7 @@ iterate_over_symtabs (const char *name, /* Same search rules as above apply here, but now we look thru the psymtabs. */ - ALL_OBJFILES (objfile) + for (objfile *objfile : all_objfiles (current_program_space)) { if (objfile->sf && objfile->sf->qf->map_symtabs_matching_filename (objfile, @@ -708,14 +707,14 @@ eq_demangled_name_entry (const void *a, const void *b) name. The entry is hashed via just the mangled name. */ static void -create_demangled_names_hash (struct objfile *objfile) +create_demangled_names_hash (struct objfile_per_bfd_storage *per_bfd) { /* Choose 256 as the starting size of the hash table, somewhat arbitrarily. The hash table code will round this up to the next prime number. Choosing a much larger table size wastes memory, and saves only about 1% in symbol reading. */ - objfile->per_bfd->demangled_names_hash = htab_create_alloc + per_bfd->demangled_names_hash = htab_create_alloc (256, hash_demangled_name_entry, eq_demangled_name_entry, NULL, xcalloc, xfree); } @@ -773,13 +772,12 @@ symbol_find_demangled_name (struct general_symbol_info *gsymbol, void symbol_set_names (struct general_symbol_info *gsymbol, const char *linkage_name, int len, int copy_name, - struct objfile *objfile) + struct objfile_per_bfd_storage *per_bfd) { struct demangled_name_entry **slot; /* A 0-terminated copy of the linkage name. */ const char *linkage_name_copy; struct demangled_name_entry entry; - struct objfile_per_bfd_storage *per_bfd = objfile->per_bfd; if (gsymbol->language == language_ada) { @@ -802,7 +800,7 @@ symbol_set_names (struct general_symbol_info *gsymbol, } if (per_bfd->demangled_names_hash == NULL) - create_demangled_names_hash (objfile); + create_demangled_names_hash (per_bfd); if (linkage_name[len] != '\0') { @@ -817,6 +815,11 @@ symbol_set_names (struct general_symbol_info *gsymbol, else linkage_name_copy = linkage_name; + /* Set the symbol language. */ + char *demangled_name_ptr + = symbol_find_demangled_name (gsymbol, linkage_name_copy); + gdb::unique_xmalloc_ptr demangled_name (demangled_name_ptr); + entry.mangled = linkage_name_copy; slot = ((struct demangled_name_entry **) htab_find_slot (per_bfd->demangled_names_hash, @@ -829,9 +832,7 @@ symbol_set_names (struct general_symbol_info *gsymbol, || (gsymbol->language == language_go && (*slot)->demangled[0] == '\0')) { - char *demangled_name = symbol_find_demangled_name (gsymbol, - linkage_name_copy); - int demangled_len = demangled_name ? strlen (demangled_name) : 0; + int demangled_len = demangled_name ? strlen (demangled_name.get ()) : 0; /* Suppose we have demangled_name==NULL, copy_name==0, and linkage_name_copy==linkage_name. In this case, we already have the @@ -869,10 +870,7 @@ symbol_set_names (struct general_symbol_info *gsymbol, } if (demangled_name != NULL) - { - strcpy ((*slot)->demangled, demangled_name); - xfree (demangled_name); - } + strcpy ((*slot)->demangled, demangled_name.get()); else (*slot)->demangled[0] = '\0'; } @@ -1012,9 +1010,12 @@ matching_obj_sections (struct obj_section *obj_first, /* Otherwise check that they are in corresponding objfiles. */ - ALL_OBJFILES (obj) - if (obj->obfd == first->owner) - break; + for (objfile *objfile : all_objfiles (current_program_space)) + if (objfile->obfd == first->owner) + { + obj = objfile; + break; + } gdb_assert (obj != NULL); if (obj->separate_debug_objfile != NULL @@ -1032,7 +1033,6 @@ matching_obj_sections (struct obj_section *obj_first, void expand_symtab_containing_pc (CORE_ADDR pc, struct obj_section *section) { - struct objfile *objfile; struct bound_minimal_symbol msymbol; /* If we know that this is not a text address, return failure. This is @@ -1047,16 +1047,16 @@ expand_symtab_containing_pc (CORE_ADDR pc, struct obj_section *section) || MSYMBOL_TYPE (msymbol.minsym) == mst_file_bss)) return; - ALL_OBJFILES (objfile) - { - struct compunit_symtab *cust = NULL; + for (objfile *objfile : all_objfiles (current_program_space)) + { + struct compunit_symtab *cust = NULL; - if (objfile->sf) - cust = objfile->sf->qf->find_pc_sect_compunit_symtab (objfile, msymbol, - pc, section, 0); - if (cust) - return; - } + if (objfile->sf) + cust = objfile->sf->qf->find_pc_sect_compunit_symtab (objfile, msymbol, + pc, section, 0); + if (cust) + return; + } } /* Hash function for the symbol cache. */ @@ -1746,7 +1746,7 @@ fixup_symbol_section (struct symbol *sym, struct objfile *objfile) addr = SYMBOL_VALUE_ADDRESS (sym); break; case LOC_BLOCK: - addr = BLOCK_START (SYMBOL_BLOCK_VALUE (sym)); + addr = BLOCK_ENTRY_PC (SYMBOL_BLOCK_VALUE (sym)); break; default: @@ -2141,12 +2141,12 @@ lookup_local_symbol (const char *name, if (language == language_cplus || language == language_fortran) { - struct block_symbol sym + struct block_symbol blocksym = cp_lookup_symbol_imports_or_template (scope, name, block, domain); - if (sym.symbol != NULL) - return sym; + if (blocksym.symbol != NULL) + return blocksym; } if (BLOCK_FUNCTION (block) != NULL && block_inlined_p (block)) @@ -2164,23 +2164,23 @@ lookup_local_symbol (const char *name, struct objfile * lookup_objfile_from_block (const struct block *block) { - struct objfile *obj; - struct compunit_symtab *cust; - if (block == NULL) return NULL; block = block_global_block (block); /* Look through all blockvectors. */ - ALL_COMPUNITS (obj, cust) - if (block == BLOCKVECTOR_BLOCK (COMPUNIT_BLOCKVECTOR (cust), - GLOBAL_BLOCK)) - { - if (obj->separate_debug_objfile_backlink) - obj = obj->separate_debug_objfile_backlink; + for (objfile *obj : all_objfiles (current_program_space)) + { + for (compunit_symtab *cust : objfile_compunits (obj)) + if (block == BLOCKVECTOR_BLOCK (COMPUNIT_BLOCKVECTOR (cust), + GLOBAL_BLOCK)) + { + if (obj->separate_debug_objfile_backlink) + obj = obj->separate_debug_objfile_backlink; - return obj; - } + return obj; + } + } return NULL; } @@ -2253,8 +2253,6 @@ static struct block_symbol lookup_symbol_in_objfile_symtabs (struct objfile *objfile, int block_index, const char *name, const domain_enum domain) { - struct compunit_symtab *cust; - gdb_assert (block_index == GLOBAL_BLOCK || block_index == STATIC_BLOCK); if (symbol_lookup_debug > 1) @@ -2267,7 +2265,7 @@ lookup_symbol_in_objfile_symtabs (struct objfile *objfile, int block_index, name, domain_name (domain)); } - ALL_OBJFILE_COMPUNITS (objfile, cust) + for (compunit_symtab *cust : objfile_compunits (objfile)) { const struct blockvector *bv; const struct block *block; @@ -2575,7 +2573,6 @@ struct block_symbol lookup_static_symbol (const char *name, const domain_enum domain) { struct symbol_cache *cache = get_symbol_cache (current_program_space); - struct objfile *objfile; struct block_symbol result; struct block_symbol_cache *bsc; struct symbol_cache_slot *slot; @@ -2591,7 +2588,7 @@ lookup_static_symbol (const char *name, const domain_enum domain) return result; } - ALL_OBJFILES (objfile) + for (objfile *objfile : all_objfiles (current_program_space)) { result = lookup_symbol_in_objfile (objfile, STATIC_BLOCK, name, domain); if (result.symbol != NULL) @@ -2762,12 +2759,11 @@ static struct type * basic_lookup_transparent_type_1 (struct objfile *objfile, int block_index, const char *name) { - const struct compunit_symtab *cust; const struct blockvector *bv; const struct block *block; const struct symbol *sym; - ALL_OBJFILE_COMPUNITS (objfile, cust) + for (compunit_symtab *cust : objfile_compunits (objfile)) { bv = COMPUNIT_BLOCKVECTOR (cust); block = BLOCKVECTOR_BLOCK (bv, block_index); @@ -2792,7 +2788,6 @@ basic_lookup_transparent_type_1 (struct objfile *objfile, int block_index, struct type * basic_lookup_transparent_type (const char *name) { - struct objfile *objfile; struct type *t; /* Now search all the global symbols. Do the symtab's first, then @@ -2800,19 +2795,19 @@ basic_lookup_transparent_type (const char *name) of the desired name as a global, then do psymtab-to-symtab conversion on the fly and return the found symbol. */ - ALL_OBJFILES (objfile) - { - t = basic_lookup_transparent_type_1 (objfile, GLOBAL_BLOCK, name); - if (t) - return t; - } + for (objfile *objfile : all_objfiles (current_program_space)) + { + t = basic_lookup_transparent_type_1 (objfile, GLOBAL_BLOCK, name); + if (t) + return t; + } - ALL_OBJFILES (objfile) - { - t = basic_lookup_transparent_type_quick (objfile, GLOBAL_BLOCK, name); - if (t) - return t; - } + for (objfile *objfile : all_objfiles (current_program_space)) + { + t = basic_lookup_transparent_type_quick (objfile, GLOBAL_BLOCK, name); + if (t) + return t; + } /* Now search the static file-level symbols. Not strictly correct, but more useful than an error. @@ -2821,19 +2816,19 @@ basic_lookup_transparent_type (const char *name) of the desired name as a file-level static, then do psymtab-to-symtab conversion on the fly and return the found symbol. */ - ALL_OBJFILES (objfile) - { - t = basic_lookup_transparent_type_1 (objfile, STATIC_BLOCK, name); - if (t) - return t; - } + for (objfile *objfile : all_objfiles (current_program_space)) + { + t = basic_lookup_transparent_type_1 (objfile, STATIC_BLOCK, name); + if (t) + return t; + } - ALL_OBJFILES (objfile) - { - t = basic_lookup_transparent_type_quick (objfile, STATIC_BLOCK, name); - if (t) - return t; - } + for (objfile *objfile : all_objfiles (current_program_space)) + { + t = basic_lookup_transparent_type_quick (objfile, STATIC_BLOCK, name); + if (t) + return t; + } return (struct type *) 0; } @@ -2860,7 +2855,9 @@ iterate_over_symbols (const struct block *block, if (symbol_matches_domain (SYMBOL_LANGUAGE (sym), SYMBOL_DOMAIN (sym), domain)) { - if (!callback (sym)) + struct block_symbol block_sym = {sym, block}; + + if (!callback (&block_sym)) return; } } @@ -2872,9 +2869,7 @@ iterate_over_symbols (const struct block *block, struct compunit_symtab * find_pc_sect_compunit_symtab (CORE_ADDR pc, struct obj_section *section) { - struct compunit_symtab *cust; struct compunit_symtab *best_cust = NULL; - struct objfile *objfile; CORE_ADDR distance = 0; struct bound_minimal_symbol msymbol; @@ -2907,76 +2902,81 @@ find_pc_sect_compunit_symtab (CORE_ADDR pc, struct obj_section *section) It also happens for objfiles that have their functions reordered. For these, the symtab we are looking for is not necessarily read in. */ - ALL_COMPUNITS (objfile, cust) - { - struct block *b; - const struct blockvector *bv; - - bv = COMPUNIT_BLOCKVECTOR (cust); - b = BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK); + for (objfile *obj_file : all_objfiles (current_program_space)) + { + for (compunit_symtab *cust : objfile_compunits (obj_file)) + { + struct block *b; + const struct blockvector *bv; - if (BLOCK_START (b) <= pc - && BLOCK_END (b) > pc - && (distance == 0 - || BLOCK_END (b) - BLOCK_START (b) < distance)) - { - /* For an objfile that has its functions reordered, - find_pc_psymtab will find the proper partial symbol table - and we simply return its corresponding symtab. */ - /* In order to better support objfiles that contain both - stabs and coff debugging info, we continue on if a psymtab - can't be found. */ - if ((objfile->flags & OBJF_REORDERED) && objfile->sf) - { - struct compunit_symtab *result; - - result - = objfile->sf->qf->find_pc_sect_compunit_symtab (objfile, - msymbol, - pc, section, - 0); - if (result != NULL) - return result; - } - if (section != 0) - { - struct block_iterator iter; - struct symbol *sym = NULL; + bv = COMPUNIT_BLOCKVECTOR (cust); + b = BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK); - ALL_BLOCK_SYMBOLS (b, iter, sym) - { - fixup_symbol_section (sym, objfile); - if (matching_obj_sections (SYMBOL_OBJ_SECTION (objfile, sym), - section)) - break; - } - if (sym == NULL) - continue; /* No symbol in this symtab matches - section. */ - } - distance = BLOCK_END (b) - BLOCK_START (b); - best_cust = cust; - } - } + if (BLOCK_START (b) <= pc + && BLOCK_END (b) > pc + && (distance == 0 + || BLOCK_END (b) - BLOCK_START (b) < distance)) + { + /* For an objfile that has its functions reordered, + find_pc_psymtab will find the proper partial symbol table + and we simply return its corresponding symtab. */ + /* In order to better support objfiles that contain both + stabs and coff debugging info, we continue on if a psymtab + can't be found. */ + if ((obj_file->flags & OBJF_REORDERED) && obj_file->sf) + { + struct compunit_symtab *result; + + result + = obj_file->sf->qf->find_pc_sect_compunit_symtab (obj_file, + msymbol, + pc, + section, + 0); + if (result != NULL) + return result; + } + if (section != 0) + { + struct block_iterator iter; + struct symbol *sym = NULL; + + ALL_BLOCK_SYMBOLS (b, iter, sym) + { + fixup_symbol_section (sym, obj_file); + if (matching_obj_sections (SYMBOL_OBJ_SECTION (obj_file, + sym), + section)) + break; + } + if (sym == NULL) + continue; /* No symbol in this symtab matches + section. */ + } + distance = BLOCK_END (b) - BLOCK_START (b); + best_cust = cust; + } + } + } if (best_cust != NULL) return best_cust; /* Not found in symtabs, search the "quick" symtabs (e.g. psymtabs). */ - ALL_OBJFILES (objfile) - { - struct compunit_symtab *result; - - if (!objfile->sf) - continue; - result = objfile->sf->qf->find_pc_sect_compunit_symtab (objfile, - msymbol, - pc, section, - 1); - if (result != NULL) - return result; - } + for (objfile *objf : all_objfiles (current_program_space)) + { + struct compunit_symtab *result; + + if (!objf->sf) + continue; + result = objf->sf->qf->find_pc_sect_compunit_symtab (objf, + msymbol, + pc, section, + 1); + if (result != NULL) + return result; + } return NULL; } @@ -2996,35 +2996,33 @@ find_pc_compunit_symtab (CORE_ADDR pc) struct symbol * find_symbol_at_address (CORE_ADDR address) { - struct objfile *objfile; - - ALL_OBJFILES (objfile) - { - if (objfile->sf == NULL - || objfile->sf->qf->find_compunit_symtab_by_address == NULL) - continue; - - struct compunit_symtab *symtab - = objfile->sf->qf->find_compunit_symtab_by_address (objfile, address); - if (symtab != NULL) - { - const struct blockvector *bv = COMPUNIT_BLOCKVECTOR (symtab); + for (objfile *objfile : all_objfiles (current_program_space)) + { + if (objfile->sf == NULL + || objfile->sf->qf->find_compunit_symtab_by_address == NULL) + continue; - for (int i = GLOBAL_BLOCK; i <= STATIC_BLOCK; ++i) - { - struct block *b = BLOCKVECTOR_BLOCK (bv, i); - struct block_iterator iter; - struct symbol *sym; + struct compunit_symtab *symtab + = objfile->sf->qf->find_compunit_symtab_by_address (objfile, address); + if (symtab != NULL) + { + const struct blockvector *bv = COMPUNIT_BLOCKVECTOR (symtab); - ALL_BLOCK_SYMBOLS (b, iter, sym) + for (int i = GLOBAL_BLOCK; i <= STATIC_BLOCK; ++i) { - if (SYMBOL_CLASS (sym) == LOC_STATIC - && SYMBOL_VALUE_ADDRESS (sym) == address) - return sym; + struct block *b = BLOCKVECTOR_BLOCK (bv, i); + struct block_iterator iter; + struct symbol *sym; + + ALL_BLOCK_SYMBOLS (b, iter, sym) + { + if (SYMBOL_CLASS (sym) == LOC_STATIC + && SYMBOL_VALUE_ADDRESS (sym) == address) + return sym; + } } - } - } - } + } + } return NULL; } @@ -3050,10 +3048,8 @@ struct symtab_and_line find_pc_sect_line (CORE_ADDR pc, struct obj_section *section, int notcurrent) { struct compunit_symtab *cust; - struct symtab *iter_s; struct linetable *l; int len; - int i; struct linetable_entry *item; const struct blockvector *bv; struct bound_minimal_symbol msymbol; @@ -3188,7 +3184,7 @@ find_pc_sect_line (CORE_ADDR pc, struct obj_section *section, int notcurrent) They all have the same apriori range, that we found was right; but they have different line tables. */ - ALL_COMPUNIT_FILETABS (cust, iter_s) + for (symtab *iter_s : compunit_filetabs (cust)) { /* Find the best line in this symtab. */ l = SYMTAB_LINETABLE (iter_s); @@ -3212,10 +3208,10 @@ find_pc_sect_line (CORE_ADDR pc, struct obj_section *section, int notcurrent) if (item->pc > pc && (!alt || item->pc < alt->pc)) alt = item; - auto pc_compare = [](const CORE_ADDR & pc, + auto pc_compare = [](const CORE_ADDR & comp_pc, const struct linetable_entry & lhs)->bool { - return pc < lhs.pc; + return comp_pc < lhs.pc; }; struct linetable_entry *first = item; @@ -3320,7 +3316,7 @@ find_pc_line_symtab (CORE_ADDR pc) If not found, return NULL. */ struct symtab * -find_line_symtab (struct symtab *symtab, int line, +find_line_symtab (struct symtab *sym_tab, int line, int *index, int *exact_match) { int exact = 0; /* Initialized here to avoid a compiler warning. */ @@ -3333,8 +3329,8 @@ find_line_symtab (struct symtab *symtab, int line, struct symtab *best_symtab; /* First try looking it up in the given symtab. */ - best_linetable = SYMTAB_LINETABLE (symtab); - best_symtab = symtab; + best_linetable = SYMTAB_LINETABLE (sym_tab); + best_symtab = sym_tab; best_index = find_line_common (best_linetable, line, &exact, 0); if (best_index < 0 || !exact) { @@ -3350,52 +3346,54 @@ find_line_symtab (struct symtab *symtab, int line, BEST_INDEX and BEST_LINETABLE identify the item for it. */ int best; - struct objfile *objfile; - struct compunit_symtab *cu; - struct symtab *s; - if (best_index >= 0) best = best_linetable->item[best_index].line; else best = 0; - ALL_OBJFILES (objfile) - { - if (objfile->sf) - objfile->sf->qf->expand_symtabs_with_fullname (objfile, - symtab_to_fullname (symtab)); - } - - ALL_FILETABS (objfile, cu, s) - { - struct linetable *l; - int ind; + for (objfile *objfile : all_objfiles (current_program_space)) + { + if (objfile->sf) + objfile->sf->qf->expand_symtabs_with_fullname + (objfile, symtab_to_fullname (sym_tab)); + } - if (FILENAME_CMP (symtab->filename, s->filename) != 0) - continue; - if (FILENAME_CMP (symtab_to_fullname (symtab), - symtab_to_fullname (s)) != 0) - continue; - l = SYMTAB_LINETABLE (s); - ind = find_line_common (l, line, &exact, 0); - if (ind >= 0) - { - if (exact) - { - best_index = ind; - best_linetable = l; - best_symtab = s; - goto done; - } - if (best == 0 || l->item[ind].line < best) - { - best = l->item[ind].line; - best_index = ind; - best_linetable = l; - best_symtab = s; - } - } - } + for (objfile *objfile : all_objfiles (current_program_space)) + { + for (compunit_symtab *cu : objfile_compunits (objfile)) + { + for (symtab *s : compunit_filetabs (cu)) + { + struct linetable *l; + int ind; + + if (FILENAME_CMP (sym_tab->filename, s->filename) != 0) + continue; + if (FILENAME_CMP (symtab_to_fullname (sym_tab), + symtab_to_fullname (s)) != 0) + continue; + l = SYMTAB_LINETABLE (s); + ind = find_line_common (l, line, &exact, 0); + if (ind >= 0) + { + if (exact) + { + best_index = ind; + best_linetable = l; + best_symtab = s; + goto done; + } + if (best == 0 || l->item[ind].line < best) + { + best = l->item[ind].line; + best_index = ind; + best_linetable = l; + best_symtab = s; + } + } + } + } + } } done: if (best_index < 0) @@ -3638,7 +3636,7 @@ find_function_start_sal (symbol *sym, bool funfirstline) { fixup_symbol_section (sym, NULL); symtab_and_line sal - = find_function_start_sal_1 (BLOCK_START (SYMBOL_BLOCK_VALUE (sym)), + = find_function_start_sal_1 (BLOCK_ENTRY_PC (SYMBOL_BLOCK_VALUE (sym)), SYMBOL_OBJ_SECTION (symbol_objfile (sym), sym), funfirstline); sal.symbol = sym; @@ -3718,7 +3716,7 @@ skip_prologue_sal (struct symtab_and_line *sal) fixup_symbol_section (sym, NULL); objfile = symbol_objfile (sym); - pc = BLOCK_START (SYMBOL_BLOCK_VALUE (sym)); + pc = BLOCK_ENTRY_PC (SYMBOL_BLOCK_VALUE (sym)); section = SYMBOL_OBJ_SECTION (objfile, sym); name = SYMBOL_LINKAGE_NAME (sym); } @@ -3779,7 +3777,7 @@ skip_prologue_sal (struct symtab_and_line *sal) /* Check if gdbarch_skip_prologue left us in mid-line, and the next line is still part of the same function. */ if (skip && start_sal.pc != pc - && (sym ? (BLOCK_START (SYMBOL_BLOCK_VALUE (sym)) <= start_sal.end + && (sym ? (BLOCK_ENTRY_PC (SYMBOL_BLOCK_VALUE (sym)) <= start_sal.end && start_sal.end < BLOCK_END (SYMBOL_BLOCK_VALUE (sym))) : (lookup_minimal_symbol_by_pc_section (start_sal.end, section).minsym == lookup_minimal_symbol_by_pc_section (pc, section).minsym))) @@ -3983,7 +3981,7 @@ find_function_alias_target (bound_minimal_symbol msymbol) symbol *sym = find_pc_function (func_addr); if (sym != NULL && SYMBOL_CLASS (sym) == LOC_BLOCK - && BLOCK_START (SYMBOL_BLOCK_VALUE (sym)) == func_addr) + && BLOCK_ENTRY_PC (SYMBOL_BLOCK_VALUE (sym)) == func_addr) return sym; return NULL; @@ -4186,9 +4184,6 @@ output_partial_symbol_filename (const char *filename, const char *fullname, static void info_sources_command (const char *ignore, int from_tty) { - struct compunit_symtab *cu; - struct symtab *s; - struct objfile *objfile; struct output_source_filename_data data; if (!have_full_symbols () && !have_partial_symbols ()) @@ -4203,12 +4198,18 @@ info_sources_command (const char *ignore, int from_tty) printf_filtered ("Source files for which symbols have been read in:\n\n"); data.first = 1; - ALL_FILETABS (objfile, cu, s) - { - const char *fullname = symtab_to_fullname (s); + for (objfile *objfile : all_objfiles (current_program_space)) + { + for (compunit_symtab *cu : objfile_compunits (objfile)) + { + for (symtab *s : compunit_filetabs (cu)) + { + const char *fullname = symtab_to_fullname (s); - output_source_filename (fullname, &data); - } + output_source_filename (fullname, &data); + } + } + } printf_filtered ("\n\n"); printf_filtered ("Source files for which symbols " @@ -4265,6 +4266,49 @@ symbol_search::compare_search_syms (const symbol_search &sym_a, SYMBOL_PRINT_NAME (sym_b.symbol)); } +/* Returns true if the type_name of symbol_type of SYM matches TREG. + If SYM has no symbol_type or symbol_name, returns false. */ + +bool +treg_matches_sym_type_name (const compiled_regex &treg, + const struct symbol *sym) +{ + struct type *sym_type; + std::string printed_sym_type_name; + + if (symbol_lookup_debug > 1) + { + fprintf_unfiltered (gdb_stdlog, + "treg_matches_sym_type_name\n sym %s\n", + SYMBOL_NATURAL_NAME (sym)); + } + + sym_type = SYMBOL_TYPE (sym); + if (sym_type == NULL) + return false; + + { + scoped_switch_to_sym_language_if_auto l (sym); + + printed_sym_type_name = type_to_string (sym_type); + } + + + if (symbol_lookup_debug > 1) + { + fprintf_unfiltered (gdb_stdlog, + " sym_type_name %s\n", + printed_sym_type_name.c_str ()); + } + + + if (printed_sym_type_name.empty ()) + return false; + + return treg.exec (printed_sym_type_name.c_str (), 0, NULL, 0) == 0; +} + + /* Sort the symbols in RESULT and remove duplicates. */ static void @@ -4280,7 +4324,9 @@ sort_search_symbols_remove_dups (std::vector *result) Only symbols of KIND are searched: VARIABLES_DOMAIN - search all symbols, excluding functions, type names, - and constants (enums) + and constants (enums). + if T_REGEXP is not NULL, only returns var that have + a type matching regular expression T_REGEXP. FUNCTIONS_DOMAIN - search all functions TYPES_DOMAIN - search all type names ALL_DOMAIN - an internal error for this function @@ -4291,16 +4337,14 @@ sort_search_symbols_remove_dups (std::vector *result) std::vector search_symbols (const char *regexp, enum search_domain kind, + const char *t_regexp, int nfiles, const char *files[]) { - struct compunit_symtab *cust; const struct blockvector *bv; struct block *b; int i = 0; struct block_iterator iter; struct symbol *sym; - struct objfile *objfile; - struct minimal_symbol *msymbol; int found_misc = 0; static const enum minimal_symbol_type types[] = {mst_data, mst_text, mst_abs}; @@ -4316,6 +4360,7 @@ search_symbols (const char *regexp, enum search_domain kind, enum minimal_symbol_type ourtype4; std::vector result; gdb::optional preg; + gdb::optional treg; gdb_assert (kind <= TYPES_DOMAIN); @@ -4365,6 +4410,13 @@ search_symbols (const char *regexp, enum search_domain kind, preg.emplace (regexp, cflags, _("Invalid regexp")); } + if (t_regexp != NULL) + { + int cflags = REG_NOSUB | (case_sensitivity == case_sensitive_off + ? REG_ICASE : 0); + treg.emplace (t_regexp, cflags, _("Invalid regexp")); + } + /* Search through the partial symtabs *first* for all symbols matching the regexp. That way we don't have to reproduce all of the machinery below. */ @@ -4376,8 +4428,9 @@ search_symbols (const char *regexp, enum search_domain kind, lookup_name_info::match_any (), [&] (const char *symname) { - return (!preg || preg->exec (symname, - 0, NULL, 0) == 0); + return (!preg.has_value () + || preg->exec (symname, + 0, NULL, 0) == 0); }, NULL, kind); @@ -4400,122 +4453,147 @@ search_symbols (const char *regexp, enum search_domain kind, if (nfiles == 0 && (kind == VARIABLES_DOMAIN || kind == FUNCTIONS_DOMAIN)) { - ALL_MSYMBOLS (objfile, msymbol) - { - QUIT; + for (objfile *objfile : all_objfiles (current_program_space)) + { + for (minimal_symbol *msymbol : objfile_msymbols (objfile)) + { + QUIT; - if (msymbol->created_by_gdb) - continue; + if (msymbol->created_by_gdb) + continue; - if (MSYMBOL_TYPE (msymbol) == ourtype - || MSYMBOL_TYPE (msymbol) == ourtype2 - || MSYMBOL_TYPE (msymbol) == ourtype3 - || MSYMBOL_TYPE (msymbol) == ourtype4) - { - if (!preg - || preg->exec (MSYMBOL_NATURAL_NAME (msymbol), 0, - NULL, 0) == 0) - { - /* Note: An important side-effect of these lookup functions - is to expand the symbol table if msymbol is found, for the - benefit of the next loop on ALL_COMPUNITS. */ - if (kind == FUNCTIONS_DOMAIN - ? (find_pc_compunit_symtab - (MSYMBOL_VALUE_ADDRESS (objfile, msymbol)) == NULL) - : (lookup_symbol_in_objfile_from_linkage_name - (objfile, MSYMBOL_LINKAGE_NAME (msymbol), VAR_DOMAIN) - .symbol == NULL)) - found_misc = 1; - } - } - } + if (MSYMBOL_TYPE (msymbol) == ourtype + || MSYMBOL_TYPE (msymbol) == ourtype2 + || MSYMBOL_TYPE (msymbol) == ourtype3 + || MSYMBOL_TYPE (msymbol) == ourtype4) + { + if (!preg.has_value () + || preg->exec (MSYMBOL_NATURAL_NAME (msymbol), 0, + NULL, 0) == 0) + { + /* Note: An important side-effect of these + lookup functions is to expand the symbol + table if msymbol is found, for the benefit of + the next loop on compunits. */ + if (kind == FUNCTIONS_DOMAIN + ? (find_pc_compunit_symtab + (MSYMBOL_VALUE_ADDRESS (objfile, msymbol)) + == NULL) + : (lookup_symbol_in_objfile_from_linkage_name + (objfile, MSYMBOL_LINKAGE_NAME (msymbol), + VAR_DOMAIN) + .symbol == NULL)) + found_misc = 1; + } + } + } + } } - ALL_COMPUNITS (objfile, cust) - { - bv = COMPUNIT_BLOCKVECTOR (cust); - for (i = GLOBAL_BLOCK; i <= STATIC_BLOCK; i++) - { - b = BLOCKVECTOR_BLOCK (bv, i); - ALL_BLOCK_SYMBOLS (b, iter, sym) - { - struct symtab *real_symtab = symbol_symtab (sym); - - QUIT; - - /* Check first sole REAL_SYMTAB->FILENAME. It does not need to be - a substring of symtab_to_fullname as it may contain "./" etc. */ - if ((file_matches (real_symtab->filename, files, nfiles, 0) - || ((basenames_may_differ - || file_matches (lbasename (real_symtab->filename), - files, nfiles, 1)) - && file_matches (symtab_to_fullname (real_symtab), - files, nfiles, 0))) - && ((!preg - || preg->exec (SYMBOL_NATURAL_NAME (sym), 0, - NULL, 0) == 0) - && ((kind == VARIABLES_DOMAIN - && SYMBOL_CLASS (sym) != LOC_TYPEDEF - && SYMBOL_CLASS (sym) != LOC_UNRESOLVED - && SYMBOL_CLASS (sym) != LOC_BLOCK - /* LOC_CONST can be used for more than just enums, - e.g., c++ static const members. - We only want to skip enums here. */ - && !(SYMBOL_CLASS (sym) == LOC_CONST - && (TYPE_CODE (SYMBOL_TYPE (sym)) - == TYPE_CODE_ENUM))) - || (kind == FUNCTIONS_DOMAIN - && SYMBOL_CLASS (sym) == LOC_BLOCK) - || (kind == TYPES_DOMAIN - && SYMBOL_CLASS (sym) == LOC_TYPEDEF)))) - { - /* match */ - result.emplace_back (i, sym); - } - } - } - } + for (objfile *objfile : all_objfiles (current_program_space)) + { + for (compunit_symtab *cust : objfile_compunits (objfile)) + { + bv = COMPUNIT_BLOCKVECTOR (cust); + for (i = GLOBAL_BLOCK; i <= STATIC_BLOCK; i++) + { + b = BLOCKVECTOR_BLOCK (bv, i); + ALL_BLOCK_SYMBOLS (b, iter, sym) + { + struct symtab *real_symtab = symbol_symtab (sym); + + QUIT; + + /* Check first sole REAL_SYMTAB->FILENAME. It does + not need to be a substring of symtab_to_fullname as + it may contain "./" etc. */ + if ((file_matches (real_symtab->filename, files, nfiles, 0) + || ((basenames_may_differ + || file_matches (lbasename (real_symtab->filename), + files, nfiles, 1)) + && file_matches (symtab_to_fullname (real_symtab), + files, nfiles, 0))) + && ((!preg.has_value () + || preg->exec (SYMBOL_NATURAL_NAME (sym), 0, + NULL, 0) == 0) + && ((kind == VARIABLES_DOMAIN + && SYMBOL_CLASS (sym) != LOC_TYPEDEF + && SYMBOL_CLASS (sym) != LOC_UNRESOLVED + && SYMBOL_CLASS (sym) != LOC_BLOCK + /* LOC_CONST can be used for more than + just enums, e.g., c++ static const + members. We only want to skip enums + here. */ + && !(SYMBOL_CLASS (sym) == LOC_CONST + && (TYPE_CODE (SYMBOL_TYPE (sym)) + == TYPE_CODE_ENUM)) + && (!treg.has_value () + || treg_matches_sym_type_name (*treg, sym))) + || (kind == FUNCTIONS_DOMAIN + && SYMBOL_CLASS (sym) == LOC_BLOCK + && (!treg.has_value () + || treg_matches_sym_type_name (*treg, + sym))) + || (kind == TYPES_DOMAIN + && SYMBOL_CLASS (sym) == LOC_TYPEDEF)))) + { + /* match */ + result.emplace_back (i, sym); + } + } + } + } + } if (!result.empty ()) sort_search_symbols_remove_dups (&result); /* If there are no eyes, avoid all contact. I mean, if there are - no debug symbols, then add matching minsyms. */ + no debug symbols, then add matching minsyms. But if the user wants + to see symbols matching a type regexp, then never give a minimal symbol, + as we assume that a minimal symbol does not have a type. */ - if (found_misc || (nfiles == 0 && kind != FUNCTIONS_DOMAIN)) + if ((found_misc || (nfiles == 0 && kind != FUNCTIONS_DOMAIN)) + && !treg.has_value ()) { - ALL_MSYMBOLS (objfile, msymbol) - { - QUIT; + for (objfile *objfile : all_objfiles (current_program_space)) + { + for (minimal_symbol *msymbol : objfile_msymbols (objfile)) + { + QUIT; - if (msymbol->created_by_gdb) - continue; + if (msymbol->created_by_gdb) + continue; - if (MSYMBOL_TYPE (msymbol) == ourtype - || MSYMBOL_TYPE (msymbol) == ourtype2 - || MSYMBOL_TYPE (msymbol) == ourtype3 - || MSYMBOL_TYPE (msymbol) == ourtype4) - { - if (!preg || preg->exec (MSYMBOL_NATURAL_NAME (msymbol), 0, + if (MSYMBOL_TYPE (msymbol) == ourtype + || MSYMBOL_TYPE (msymbol) == ourtype2 + || MSYMBOL_TYPE (msymbol) == ourtype3 + || MSYMBOL_TYPE (msymbol) == ourtype4) + { + if (!preg.has_value () + || preg->exec (MSYMBOL_NATURAL_NAME (msymbol), 0, NULL, 0) == 0) - { - /* For functions we can do a quick check of whether the - symbol might be found via find_pc_symtab. */ - if (kind != FUNCTIONS_DOMAIN - || (find_pc_compunit_symtab - (MSYMBOL_VALUE_ADDRESS (objfile, msymbol)) == NULL)) - { - if (lookup_symbol_in_objfile_from_linkage_name - (objfile, MSYMBOL_LINKAGE_NAME (msymbol), VAR_DOMAIN) - .symbol == NULL) - { - /* match */ - result.emplace_back (i, msymbol, objfile); - } - } - } - } - } + { + /* For functions we can do a quick check of whether the + symbol might be found via find_pc_symtab. */ + if (kind != FUNCTIONS_DOMAIN + || (find_pc_compunit_symtab + (MSYMBOL_VALUE_ADDRESS (objfile, msymbol)) + == NULL)) + { + if (lookup_symbol_in_objfile_from_linkage_name + (objfile, MSYMBOL_LINKAGE_NAME (msymbol), + VAR_DOMAIN) + .symbol == NULL) + { + /* match */ + result.emplace_back (i, msymbol, objfile); + } + } + } + } + } + } } return result; @@ -4532,6 +4610,7 @@ print_symbol_info (enum search_domain kind, struct symbol *sym, int block, const char *last) { + scoped_switch_to_sym_language_if_auto l (sym); struct symtab *s = symbol_symtab (sym); if (last != NULL) @@ -4598,7 +4677,9 @@ print_msymbol_info (struct bound_minimal_symbol msymbol) matches. */ static void -symtab_symbol_info (const char *regexp, enum search_domain kind, int from_tty) +symtab_symbol_info (bool quiet, + const char *regexp, enum search_domain kind, + const char *t_regexp, int from_tty) { static const char * const classnames[] = {"variable", "function", "type"}; @@ -4608,13 +4689,33 @@ symtab_symbol_info (const char *regexp, enum search_domain kind, int from_tty) gdb_assert (kind <= TYPES_DOMAIN); /* Must make sure that if we're interrupted, symbols gets freed. */ - std::vector symbols = search_symbols (regexp, kind, 0, NULL); + std::vector symbols = search_symbols (regexp, kind, + t_regexp, 0, NULL); - if (regexp != NULL) - printf_filtered (_("All %ss matching regular expression \"%s\":\n"), - classnames[kind], regexp); - else - printf_filtered (_("All defined %ss:\n"), classnames[kind]); + if (!quiet) + { + if (regexp != NULL) + { + if (t_regexp != NULL) + printf_filtered + (_("All %ss matching regular expression \"%s\"" + " with type matching regulation expression \"%s\":\n"), + classnames[kind], regexp, t_regexp); + else + printf_filtered (_("All %ss matching regular expression \"%s\":\n"), + classnames[kind], regexp); + } + else + { + if (t_regexp != NULL) + printf_filtered + (_("All defined %ss" + " with type matching regulation expression \"%s\" :\n"), + classnames[kind], t_regexp); + else + printf_filtered (_("All defined %ss:\n"), classnames[kind]); + } + } for (const symbol_search &p : symbols) { @@ -4624,7 +4725,8 @@ symtab_symbol_info (const char *regexp, enum search_domain kind, int from_tty) { if (first) { - printf_filtered (_("\nNon-debugging symbols:\n")); + if (!quiet) + printf_filtered (_("\nNon-debugging symbols:\n")); first = 0; } print_msymbol_info (p.msymbol); @@ -4642,22 +4744,53 @@ symtab_symbol_info (const char *regexp, enum search_domain kind, int from_tty) } static void -info_variables_command (const char *regexp, int from_tty) +info_variables_command (const char *args, int from_tty) { - symtab_symbol_info (regexp, VARIABLES_DOMAIN, from_tty); + std::string regexp; + std::string t_regexp; + bool quiet = false; + + while (args != NULL + && extract_info_print_args (&args, &quiet, ®exp, &t_regexp)) + ; + + if (args != NULL) + report_unrecognized_option_error ("info variables", args); + + symtab_symbol_info (quiet, + regexp.empty () ? NULL : regexp.c_str (), + VARIABLES_DOMAIN, + t_regexp.empty () ? NULL : t_regexp.c_str (), + from_tty); } + static void -info_functions_command (const char *regexp, int from_tty) +info_functions_command (const char *args, int from_tty) { - symtab_symbol_info (regexp, FUNCTIONS_DOMAIN, from_tty); + std::string regexp; + std::string t_regexp; + bool quiet = false; + + while (args != NULL + && extract_info_print_args (&args, &quiet, ®exp, &t_regexp)) + ; + + if (args != NULL) + report_unrecognized_option_error ("info functions", args); + + symtab_symbol_info (quiet, + regexp.empty () ? NULL : regexp.c_str (), + FUNCTIONS_DOMAIN, + t_regexp.empty () ? NULL : t_regexp.c_str (), + from_tty); } static void info_types_command (const char *regexp, int from_tty) { - symtab_symbol_info (regexp, TYPES_DOMAIN, from_tty); + symtab_symbol_info (false, regexp, TYPES_DOMAIN, NULL, from_tty); } /* Breakpoint all functions matching regular expression. */ @@ -4700,6 +4833,7 @@ rbreak_command (const char *regexp, int from_tty) std::vector symbols = search_symbols (regexp, FUNCTIONS_DOMAIN, + NULL, nfiles, files); scoped_rbreak_breakpoints finalize; @@ -4988,7 +5122,7 @@ find_gnu_ifunc (const symbol *sym) symbol_name_match_type::SEARCH_NAME); struct objfile *objfile = symbol_objfile (sym); - CORE_ADDR address = BLOCK_START (SYMBOL_BLOCK_VALUE (sym)); + CORE_ADDR address = BLOCK_ENTRY_PC (SYMBOL_BLOCK_VALUE (sym)); minimal_symbol *ifunc = NULL; iterate_over_minimal_symbols (objfile, lookup_name, @@ -5069,9 +5203,6 @@ default_collect_symbol_completion_matches_break_on won't be that many. */ struct symbol *sym; - struct compunit_symtab *cust; - struct minimal_symbol *msymbol; - struct objfile *objfile; const struct block *b; const struct block *surrounding_static_block, *surrounding_global_block; struct block_iterator iter; @@ -5141,25 +5272,31 @@ default_collect_symbol_completion_matches_break_on if (code == TYPE_CODE_UNDEF) { - ALL_MSYMBOLS (objfile, msymbol) + for (objfile *objfile : all_objfiles (current_program_space)) { - QUIT; + for (minimal_symbol *msymbol : objfile_msymbols (objfile)) + { + QUIT; - if (completion_skip_symbol (mode, msymbol)) - continue; + if (completion_skip_symbol (mode, msymbol)) + continue; - completion_list_add_msymbol (tracker, msymbol, lookup_name, - sym_text, word); + completion_list_add_msymbol (tracker, msymbol, lookup_name, + sym_text, word); - completion_list_objc_symbol (tracker, msymbol, lookup_name, - sym_text, word); + completion_list_objc_symbol (tracker, msymbol, lookup_name, + sym_text, word); + } } } /* Add completions for all currently loaded symbol tables. */ - ALL_COMPUNITS (objfile, cust) - add_symtab_completions (cust, tracker, mode, lookup_name, - sym_text, word, code); + for (objfile *objfile : all_objfiles (current_program_space)) + { + for (compunit_symtab *cust : objfile_compunits (objfile)) + add_symtab_completions (cust, tracker, mode, lookup_name, + sym_text, word, code); + } /* Look through the partial symtabs for all symbols which begin by matching SYM_TEXT. Expand all CUs that you find to the list. */ @@ -5453,9 +5590,6 @@ maybe_add_partial_symtab_filename (const char *filename, const char *fullname, completion_list make_source_files_completion_list (const char *text, const char *word) { - struct compunit_symtab *cu; - struct symtab *s; - struct objfile *objfile; size_t text_len = strlen (text); completion_list list; const char *base_name; @@ -5466,28 +5600,34 @@ make_source_files_completion_list (const char *text, const char *word) filename_seen_cache filenames_seen; - ALL_FILETABS (objfile, cu, s) + for (objfile *objfile : all_objfiles (current_program_space)) { - if (not_interesting_fname (s->filename)) - continue; - if (!filenames_seen.seen (s->filename) - && filename_ncmp (s->filename, text, text_len) == 0) - { - /* This file matches for a completion; add it to the current - list of matches. */ - add_filename_to_list (s->filename, text, word, &list); - } - else + for (compunit_symtab *cu : objfile_compunits (objfile)) { - /* NOTE: We allow the user to type a base name when the - debug info records leading directories, but not the other - way around. This is what subroutines of breakpoint - command do when they parse file names. */ - base_name = lbasename (s->filename); - if (base_name != s->filename - && !filenames_seen.seen (base_name) - && filename_ncmp (base_name, text, text_len) == 0) - add_filename_to_list (base_name, text, word, &list); + for (symtab *s : compunit_filetabs (cu)) + { + if (not_interesting_fname (s->filename)) + continue; + if (!filenames_seen.seen (s->filename) + && filename_ncmp (s->filename, text, text_len) == 0) + { + /* This file matches for a completion; add it to the current + list of matches. */ + add_filename_to_list (s->filename, text, word, &list); + } + else + { + /* NOTE: We allow the user to type a base name when the + debug info records leading directories, but not the other + way around. This is what subroutines of breakpoint + command do when they parse file names. */ + base_name = lbasename (s->filename); + if (base_name != s->filename + && !filenames_seen.seen (base_name) + && filename_ncmp (base_name, text, text_len) == 0) + add_filename_to_list (base_name, text, word, &list); + } + } } } @@ -5570,7 +5710,6 @@ static void find_main_name (void) { const char *new_main_name; - struct objfile *objfile; /* First check the objfiles to see whether a debuginfo reader has picked up the appropriate main name. Historically the main name @@ -5578,15 +5717,15 @@ find_main_name (void) relies on the order of objfile creation -- which still isn't guaranteed to get the correct answer, but is just probably more accurate. */ - ALL_OBJFILES (objfile) - { - if (objfile->per_bfd->name_of_main != NULL) - { - set_main_name (objfile->per_bfd->name_of_main, - objfile->per_bfd->language_of_main); - return; - } - } + for (objfile *objfile : all_objfiles (current_program_space)) + { + if (objfile->per_bfd->name_of_main != NULL) + { + set_main_name (objfile->per_bfd->name_of_main, + objfile->per_bfd->language_of_main); + return; + } + } /* Try to see if the main procedure is in Ada. */ /* FIXME: brobecker/2005-03-07: Another way of doing this would @@ -5901,14 +6040,26 @@ _initialize_symtab (void) symbol_cache_key = register_program_space_data_with_cleanup (NULL, symbol_cache_cleanup); - add_info ("variables", info_variables_command, _("\ -All global and static variable names, or those matching REGEXP.")); + add_info ("variables", info_variables_command, + info_print_args_help (_("\ +All global and static variable names or those matching REGEXPs.\n\ +Usage: info variables [-q] [-t TYPEREGEXP] [NAMEREGEXP]\n\ +Prints the global and static variables.\n"), + _("global and static variables"))); if (dbx_commands) - add_com ("whereis", class_info, info_variables_command, _("\ -All global and static variable names, or those matching REGEXP.")); + add_com ("whereis", class_info, info_variables_command, + info_print_args_help (_("\ +All global and static variable names, or those matching REGEXPs.\n\ +Usage: whereis [-q] [-t TYPEREGEXP] [NAMEREGEXP]\n\ +Prints the global and static variables.\n"), + _("global and static variables"))); add_info ("functions", info_functions_command, - _("All function names, or those matching REGEXP.")); + info_print_args_help (_("\ +All function names or those matching REGEXPs.\n\ +Usage: info functions [-q] [-t TYPEREGEXP] [NAMEREGEXP]\n\ +Prints the functions.\n"), + _("functions"))); /* FIXME: This command has at least the following problems: 1. It prints builtin types (in a very strange and confusing fashion).