d12307c199
As Pedro suggested on gdb-patches@ (see https://sourceware.org/ml/gdb-patches/2015-05/msg00714.html), this change makes symbol lookup functions return a structure that includes both the symbol found and the block in which it was found. This makes it possible to get rid of the block_found global variable and thus makes block hunting explicit. gdb/ * ada-exp.y (write_object_renaming): Replace struct ada_symbol_info with struct block_symbol. Update field references accordingly. (block_lookup, select_possible_type_sym): Likewise. (find_primitive_type): Likewise. Also update call to ada_lookup_symbol to extract the symbol itself. (write_var_or_type, write_name_assoc): Likewise. * ada-lang.h (struct ada_symbol_info): Remove. (ada_lookup_symbol_list): Replace struct ada_symbol_info with struct block_symbol. (ada_lookup_encoded_symbol, user_select_syms): Likewise. (ada_lookup_symbol): Return struct block_symbol instead of a mere symbol. * ada-lang.c (defns_collected): Replace struct ada_symbol_info with struct block_symbol. (resolve_subexp, ada_resolve_function, sort_choices, user_select_syms, is_nonfunction, add_defn_to_vec, num_defns_collected, defns_collected, symbols_are_identical_enums, remove_extra_symbols, remove_irrelevant_renamings, add_lookup_symbol_list_worker, ada_lookup_symbol_list, ada_iterate_over_symbols, ada_lookup_encoded_symbol, get_var_value): Likewise. (ada_lookup_symbol): Return a block_symbol instead of a mere symbol. Replace struct ada_symbol_info with struct block_symbol. (ada_lookup_symbol_nonlocal): Likewise. (standard_lookup): Make block passing explicit through lookup_symbol_in_language. * ada-tasks.c (get_tcb_types_info): Update the calls to lookup_symbol_in_language to extract the mere symbol out of the returned value. (ada_tasks_inferior_data_sniffer): Likewise. * ax-gdb.c (gen_static_field): Likewise for the call to lookup_symbol. (gen_maybe_namespace_elt): Deal with struct symbol_in_block from lookup functions. (gen_expr): Likewise. * c-exp.y: Likewise. Remove uses of block_found. (lex_one_token, classify_inner_name, c_print_token): Likewise. (classify_name): Likewise. Rename the "sym" local variable to "bsym". * c-valprint.c (print_unpacked_pointer): Likewise. * compile/compile-c-symbols.c (convert_symbol_sym): Promote the "sym" parameter from struct symbol * to struct block_symbol. Use it to remove uses of block_found. Deal with struct symbol_in_block from lookup functions. (gcc_convert_symbol): Likewise. Update the call to convert_symbol_sym. * compile/compile-object-load.c (compile_object_load): Deal with struct symbol_in_block from lookup functions. * cp-namespace.c (cp_lookup_nested_symbol_1, cp_lookup_nested_symbol, cp_lookup_bare_symbol, cp_search_static_and_baseclasses, cp_lookup_symbol_in_namespace, cp_lookup_symbol_via_imports, cp_lookup_symbol_imports_or_template, cp_lookup_symbol_via_all_imports, cp_lookup_symbol_namespace, lookup_namespace_scope, cp_lookup_nonlocal, find_symbol_in_baseclass): Return struct symbol_in_block instead of mere symbols and deal with struct symbol_in_block from lookup functions. * cp-support.c (inspect_type, replace_typedefs, cp_lookup_rtti_type): Deal with struct symbol_in_block from lookup functions. * cp-support.h (cp_lookup_symbol_nonlocal, cp_lookup_symbol_from_namespace, cp_lookup_symbol_imports_or_template, cp_lookup_nested_symbol): Return struct symbol_in_block instead of mere symbols. * d-exp.y (d_type_from_name, d_module_from_name, push_variable, push_module_name): Deal with struct symbol_in_block from lookup functions. Remove uses of block_found. * eval.c (evaluate_subexp_standard): Update call to cp_lookup_symbol_namespace. * f-exp.y: Deal with struct symbol_in_block from lookup functions. Remove uses of block_found. (yylex): Likewise. * gdbtypes.c (lookup_typename, lookup_struct, lookup_union, lookup_enum, lookup_template_type, check_typedef): Deal with struct symbol_in_block from lookup functions. * guile/scm-frame.c (gdbscm_frame_read_var): Likewise. * guile/scm-symbol.c (gdbscm_lookup_symbol): Likewise. (gdbscm_lookup_global_symbol): Likewise. * gnu-v3-abi.c (gnuv3_get_typeid_type): Likewise. * go-exp.y: Likewise. Remove uses of block_found. (package_name_p, classify_packaged_name, classify_name): Likewise. * infrun.c (insert_exception_resume_breakpoint): Likewise. * jv-exp.y (push_variable): Likewise. * jv-lang.c (java_lookup_class, get_java_object_type): Likewise. * language.c (language_bool_type): Likewise. * language.h (struct language_defn): Update la_lookup_symbol_nonlocal to return a struct symbol_in_block rather than a mere symbol. * linespec.c (find_label_symbols): Deal with struct symbol_in_block from lookup functions. * m2-exp.y: Likewise. Remove uses of block_found. (yylex): Likewise. * mi/mi-cmd-stack.c (list_args_or_locals): Likewise. * objc-lang.c (lookup_struct_typedef, find_imps): Likewise. * p-exp.y: Likewise. Remove uses of block_found. (yylex): Likewise. * p-valprint.c (pascal_val_print): Likewise. * parse.c (write_dollar_variable): Likewise. Remove uses of block_found. * parser-defs.h (struct symtoken): Turn the SYM field into a struct symbol_in_block. * printcmd.c (address_info): Deal with struct symbol_in_block from lookup functions. * python/py-frame.c (frapy_read_var): Likewise. * python/py-symbol.c (gdbpy_lookup_symbol, gdbpy_lookup_global_symbol): Likewise. * skip.c (skip_function_command): Likewise. * solib-darwin.c (darwin_lookup_lib_symbol): Return a struct symbol_in_block instead of a mere symbol. * solib-spu.c (spu_lookup_lib_symbol): Likewise. * solib-svr4.c (elf_lookup_lib_symbol): Likewise. * solib.c (solib_global_lookup): Likewise. * solist.h (solib_global_lookup): Likewise. (struct target_so_ops): Update lookup_lib_global_symbol to return a struct symbol_in_block rather than a mere symbol. * source.c (select_source_symtab): Deal with struct symbol_in_block from lookup functions. * stack.c (print_frame_args, iterate_over_block_arg_vars): Likewise. * symfile.c (set_initial_language): Likewise. * symtab.c (SYMBOL_LOOKUP_FAILED): Turn into a struct symbol_in_block. (SYMBOL_LOOKUP_FAILED_P): New predicate as a macro. (struct symbol_cache_slot): Turn the FOUND field into a struct symbol_in_block. (block_found): Remove. (eq_symbol_entry): Update to deal with struct symbol_in_block in cache slots. (symbol_cache_lookup): Return a struct symbol_in_block rather than a mere symbol. (symbol_cache_mark_found): Add a BLOCK parameter to fill appropriately the cache slots. Update callers. (symbol_cache_dump): Update cache slots handling to the type change. (lookup_symbol_in_language, lookup_symbol, lookup_language_this, lookup_symbol_aux, lookup_local_symbol, lookup_symbol_in_objfile, lookup_global_symbol_from_objfile, lookup_symbol_in_objfile_symtabs, lookup_symbol_in_objfile_from_linkage_name, lookup_symbol_via_quick_fns, basic_lookup_symbol_nonlocal, lookup_symbol_in_static_block, lookup_static_symbol, lookup_global_symbol): Return a struct symbol_in_block rather than a mere symbol. Deal with struct symbol_in_block from other lookup functions. Remove uses of block_found. (lookup_symbol_in_block): Remove uses of block_found. (struct global_sym_lookup_data): Turn the RESULT field into a struct symbol_in_block. (lookup_symbol_global_iterator_cb): Update references to the RESULT field. (search_symbols): Deal with struct symbol_in_block from lookup functions. * symtab.h (struct symbol_in_block): New structure. (block_found): Remove. (lookup_symbol_in_language, lookup_symbol, basic_lookup_symbol_nonlocal, lookup_symbol_in_static_block, looku_static_symbol, lookup_global_symbol, lookup_symbol_in_block, lookup_language_this, lookup_global_symbol_from_objfile): Return a struct symbol_in_block rather than just a mere symbol. Update comments to remove mentions of block_found. * valops.c (find_function_in_inferior, value_struct_elt_for_reference, value_maybe_namespace_elt, value_of_this): Deal with struct symbol_in_block from lookup functions. * value.c (value_static_field, value_fn_field): Likewise.
770 lines
20 KiB
C
770 lines
20 KiB
C
/* Convert symbols from GDB to GCC
|
||
|
||
Copyright (C) 2014-2015 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 "compile-internal.h"
|
||
#include "symtab.h"
|
||
#include "parser-defs.h"
|
||
#include "block.h"
|
||
#include "objfiles.h"
|
||
#include "compile.h"
|
||
#include "value.h"
|
||
#include "exceptions.h"
|
||
#include "gdbtypes.h"
|
||
#include "dwarf2loc.h"
|
||
|
||
|
||
|
||
/* Object of this type are stored in the compiler's symbol_err_map. */
|
||
|
||
struct symbol_error
|
||
{
|
||
/* The symbol. */
|
||
|
||
const struct symbol *sym;
|
||
|
||
/* The error message to emit. This is malloc'd and owned by the
|
||
hash table. */
|
||
|
||
char *message;
|
||
};
|
||
|
||
/* Hash function for struct symbol_error. */
|
||
|
||
static hashval_t
|
||
hash_symbol_error (const void *a)
|
||
{
|
||
const struct symbol_error *se = a;
|
||
|
||
return htab_hash_pointer (se->sym);
|
||
}
|
||
|
||
/* Equality function for struct symbol_error. */
|
||
|
||
static int
|
||
eq_symbol_error (const void *a, const void *b)
|
||
{
|
||
const struct symbol_error *sea = a;
|
||
const struct symbol_error *seb = b;
|
||
|
||
return sea->sym == seb->sym;
|
||
}
|
||
|
||
/* Deletion function for struct symbol_error. */
|
||
|
||
static void
|
||
del_symbol_error (void *a)
|
||
{
|
||
struct symbol_error *se = a;
|
||
|
||
xfree (se->message);
|
||
xfree (se);
|
||
}
|
||
|
||
/* Associate SYMBOL with some error text. */
|
||
|
||
static void
|
||
insert_symbol_error (htab_t hash, const struct symbol *sym, const char *text)
|
||
{
|
||
struct symbol_error e;
|
||
void **slot;
|
||
|
||
e.sym = sym;
|
||
slot = htab_find_slot (hash, &e, INSERT);
|
||
if (*slot == NULL)
|
||
{
|
||
struct symbol_error *e = XNEW (struct symbol_error);
|
||
|
||
e->sym = sym;
|
||
e->message = xstrdup (text);
|
||
*slot = e;
|
||
}
|
||
}
|
||
|
||
/* Emit the error message corresponding to SYM, if one exists, and
|
||
arrange for it not to be emitted again. */
|
||
|
||
static void
|
||
error_symbol_once (struct compile_c_instance *context,
|
||
const struct symbol *sym)
|
||
{
|
||
struct symbol_error search;
|
||
struct symbol_error *err;
|
||
char *message;
|
||
|
||
if (context->symbol_err_map == NULL)
|
||
return;
|
||
|
||
search.sym = sym;
|
||
err = htab_find (context->symbol_err_map, &search);
|
||
if (err == NULL || err->message == NULL)
|
||
return;
|
||
|
||
message = err->message;
|
||
err->message = NULL;
|
||
make_cleanup (xfree, message);
|
||
error (_("%s"), message);
|
||
}
|
||
|
||
|
||
|
||
/* Compute the name of the pointer representing a local symbol's
|
||
address. */
|
||
|
||
static char *
|
||
symbol_substitution_name (struct symbol *sym)
|
||
{
|
||
return concat ("__", SYMBOL_NATURAL_NAME (sym), "_ptr", (char *) NULL);
|
||
}
|
||
|
||
/* Convert a given symbol, SYM, to the compiler's representation.
|
||
CONTEXT is the compiler instance. IS_GLOBAL is true if the
|
||
symbol came from the global scope. IS_LOCAL is true if the symbol
|
||
came from a local scope. (Note that the two are not strictly
|
||
inverses because the symbol might have come from the static
|
||
scope.) */
|
||
|
||
static void
|
||
convert_one_symbol (struct compile_c_instance *context,
|
||
struct symbol *sym,
|
||
int is_global,
|
||
int is_local)
|
||
{
|
||
gcc_type sym_type;
|
||
const char *filename = symbol_symtab (sym)->filename;
|
||
unsigned short line = SYMBOL_LINE (sym);
|
||
|
||
error_symbol_once (context, sym);
|
||
|
||
if (SYMBOL_CLASS (sym) == LOC_LABEL)
|
||
sym_type = 0;
|
||
else
|
||
sym_type = convert_type (context, SYMBOL_TYPE (sym));
|
||
|
||
if (SYMBOL_DOMAIN (sym) == STRUCT_DOMAIN)
|
||
{
|
||
/* Binding a tag, so we don't need to build a decl. */
|
||
C_CTX (context)->c_ops->tagbind (C_CTX (context),
|
||
SYMBOL_NATURAL_NAME (sym),
|
||
sym_type, filename, line);
|
||
}
|
||
else
|
||
{
|
||
gcc_decl decl;
|
||
enum gcc_c_symbol_kind kind;
|
||
CORE_ADDR addr = 0;
|
||
char *symbol_name = NULL;
|
||
|
||
switch (SYMBOL_CLASS (sym))
|
||
{
|
||
case LOC_TYPEDEF:
|
||
kind = GCC_C_SYMBOL_TYPEDEF;
|
||
break;
|
||
|
||
case LOC_LABEL:
|
||
kind = GCC_C_SYMBOL_LABEL;
|
||
addr = SYMBOL_VALUE_ADDRESS (sym);
|
||
break;
|
||
|
||
case LOC_BLOCK:
|
||
kind = GCC_C_SYMBOL_FUNCTION;
|
||
addr = BLOCK_START (SYMBOL_BLOCK_VALUE (sym));
|
||
if (is_global && TYPE_GNU_IFUNC (SYMBOL_TYPE (sym)))
|
||
addr = gnu_ifunc_resolve_addr (target_gdbarch (), addr);
|
||
break;
|
||
|
||
case LOC_CONST:
|
||
if (TYPE_CODE (SYMBOL_TYPE (sym)) == TYPE_CODE_ENUM)
|
||
{
|
||
/* Already handled by convert_enum. */
|
||
return;
|
||
}
|
||
C_CTX (context)->c_ops->build_constant (C_CTX (context), sym_type,
|
||
SYMBOL_NATURAL_NAME (sym),
|
||
SYMBOL_VALUE (sym),
|
||
filename, line);
|
||
return;
|
||
|
||
case LOC_CONST_BYTES:
|
||
error (_("Unsupported LOC_CONST_BYTES for symbol \"%s\"."),
|
||
SYMBOL_PRINT_NAME (sym));
|
||
|
||
case LOC_UNDEF:
|
||
internal_error (__FILE__, __LINE__, _("LOC_UNDEF found for \"%s\"."),
|
||
SYMBOL_PRINT_NAME (sym));
|
||
|
||
case LOC_COMMON_BLOCK:
|
||
error (_("Fortran common block is unsupported for compilation "
|
||
"evaluaton of symbol \"%s\"."),
|
||
SYMBOL_PRINT_NAME (sym));
|
||
|
||
case LOC_OPTIMIZED_OUT:
|
||
error (_("Symbol \"%s\" cannot be used for compilation evaluation "
|
||
"as it is optimized out."),
|
||
SYMBOL_PRINT_NAME (sym));
|
||
|
||
case LOC_COMPUTED:
|
||
if (is_local)
|
||
goto substitution;
|
||
/* Probably TLS here. */
|
||
warning (_("Symbol \"%s\" is thread-local and currently can only "
|
||
"be referenced from the current thread in "
|
||
"compiled code."),
|
||
SYMBOL_PRINT_NAME (sym));
|
||
/* FALLTHROUGH */
|
||
case LOC_UNRESOLVED:
|
||
/* 'symbol_name' cannot be used here as that one is used only for
|
||
local variables from compile_dwarf_expr_to_c.
|
||
Global variables can be accessed by GCC only by their address, not
|
||
by their name. */
|
||
{
|
||
struct value *val;
|
||
struct frame_info *frame = NULL;
|
||
|
||
if (symbol_read_needs_frame (sym))
|
||
{
|
||
frame = get_selected_frame (NULL);
|
||
if (frame == NULL)
|
||
error (_("Symbol \"%s\" cannot be used because "
|
||
"there is no selected frame"),
|
||
SYMBOL_PRINT_NAME (sym));
|
||
}
|
||
|
||
val = read_var_value (sym, frame);
|
||
if (VALUE_LVAL (val) != lval_memory)
|
||
error (_("Symbol \"%s\" cannot be used for compilation "
|
||
"evaluation as its address has not been found."),
|
||
SYMBOL_PRINT_NAME (sym));
|
||
|
||
kind = GCC_C_SYMBOL_VARIABLE;
|
||
addr = value_address (val);
|
||
}
|
||
break;
|
||
|
||
|
||
case LOC_REGISTER:
|
||
case LOC_ARG:
|
||
case LOC_REF_ARG:
|
||
case LOC_REGPARM_ADDR:
|
||
case LOC_LOCAL:
|
||
substitution:
|
||
kind = GCC_C_SYMBOL_VARIABLE;
|
||
symbol_name = symbol_substitution_name (sym);
|
||
break;
|
||
|
||
case LOC_STATIC:
|
||
kind = GCC_C_SYMBOL_VARIABLE;
|
||
addr = SYMBOL_VALUE_ADDRESS (sym);
|
||
break;
|
||
|
||
case LOC_FINAL_VALUE:
|
||
default:
|
||
gdb_assert_not_reached ("Unreachable case in convert_one_symbol.");
|
||
|
||
}
|
||
|
||
/* Don't emit local variable decls for a raw expression. */
|
||
if (context->base.scope != COMPILE_I_RAW_SCOPE
|
||
|| symbol_name == NULL)
|
||
{
|
||
decl = C_CTX (context)->c_ops->build_decl (C_CTX (context),
|
||
SYMBOL_NATURAL_NAME (sym),
|
||
kind,
|
||
sym_type,
|
||
symbol_name, addr,
|
||
filename, line);
|
||
|
||
C_CTX (context)->c_ops->bind (C_CTX (context), decl, is_global);
|
||
}
|
||
|
||
xfree (symbol_name);
|
||
}
|
||
}
|
||
|
||
/* Convert a full symbol to its gcc form. CONTEXT is the compiler to
|
||
use, IDENTIFIER is the name of the symbol, SYM is the symbol
|
||
itself, and DOMAIN is the domain which was searched. */
|
||
|
||
static void
|
||
convert_symbol_sym (struct compile_c_instance *context, const char *identifier,
|
||
struct block_symbol sym, domain_enum domain)
|
||
{
|
||
const struct block *static_block;
|
||
int is_local_symbol;
|
||
|
||
/* If we found a symbol and it is not in the static or global
|
||
scope, then we should first convert any static or global scope
|
||
symbol of the same name. This lets this unusual case work:
|
||
|
||
int x; // Global.
|
||
int func(void)
|
||
{
|
||
int x;
|
||
// At this spot, evaluate "extern int x; x"
|
||
}
|
||
*/
|
||
|
||
static_block = block_static_block (sym.block);
|
||
/* STATIC_BLOCK is NULL if FOUND_BLOCK is the global block. */
|
||
is_local_symbol = (sym.block != static_block && static_block != NULL);
|
||
if (is_local_symbol)
|
||
{
|
||
struct block_symbol global_sym;
|
||
|
||
global_sym = lookup_symbol (identifier, NULL, domain, NULL);
|
||
/* If the outer symbol is in the static block, we ignore it, as
|
||
it cannot be referenced. */
|
||
if (global_sym.symbol != NULL
|
||
&& global_sym.block != block_static_block (global_sym.block))
|
||
{
|
||
if (compile_debug)
|
||
fprintf_unfiltered (gdb_stdlog,
|
||
"gcc_convert_symbol \"%s\": global symbol\n",
|
||
identifier);
|
||
convert_one_symbol (context, global_sym.symbol, 1, 0);
|
||
}
|
||
}
|
||
|
||
if (compile_debug)
|
||
fprintf_unfiltered (gdb_stdlog,
|
||
"gcc_convert_symbol \"%s\": local symbol\n",
|
||
identifier);
|
||
convert_one_symbol (context, sym.symbol, 0, is_local_symbol);
|
||
}
|
||
|
||
/* Convert a minimal symbol to its gcc form. CONTEXT is the compiler
|
||
to use and BMSYM is the minimal symbol to convert. */
|
||
|
||
static void
|
||
convert_symbol_bmsym (struct compile_c_instance *context,
|
||
struct bound_minimal_symbol bmsym)
|
||
{
|
||
struct minimal_symbol *msym = bmsym.minsym;
|
||
struct objfile *objfile = bmsym.objfile;
|
||
struct type *type;
|
||
enum gcc_c_symbol_kind kind;
|
||
gcc_type sym_type;
|
||
gcc_decl decl;
|
||
CORE_ADDR addr;
|
||
|
||
addr = MSYMBOL_VALUE_ADDRESS (objfile, msym);
|
||
|
||
/* Conversion copied from write_exp_msymbol. */
|
||
switch (MSYMBOL_TYPE (msym))
|
||
{
|
||
case mst_text:
|
||
case mst_file_text:
|
||
case mst_solib_trampoline:
|
||
type = objfile_type (objfile)->nodebug_text_symbol;
|
||
kind = GCC_C_SYMBOL_FUNCTION;
|
||
break;
|
||
|
||
case mst_text_gnu_ifunc:
|
||
/* nodebug_text_gnu_ifunc_symbol would cause:
|
||
function return type cannot be function */
|
||
type = objfile_type (objfile)->nodebug_text_symbol;
|
||
kind = GCC_C_SYMBOL_FUNCTION;
|
||
addr = gnu_ifunc_resolve_addr (target_gdbarch (), addr);
|
||
break;
|
||
|
||
case mst_data:
|
||
case mst_file_data:
|
||
case mst_bss:
|
||
case mst_file_bss:
|
||
type = objfile_type (objfile)->nodebug_data_symbol;
|
||
kind = GCC_C_SYMBOL_VARIABLE;
|
||
break;
|
||
|
||
case mst_slot_got_plt:
|
||
type = objfile_type (objfile)->nodebug_got_plt_symbol;
|
||
kind = GCC_C_SYMBOL_FUNCTION;
|
||
break;
|
||
|
||
default:
|
||
type = objfile_type (objfile)->nodebug_unknown_symbol;
|
||
kind = GCC_C_SYMBOL_VARIABLE;
|
||
break;
|
||
}
|
||
|
||
sym_type = convert_type (context, type);
|
||
decl = C_CTX (context)->c_ops->build_decl (C_CTX (context),
|
||
MSYMBOL_NATURAL_NAME (msym),
|
||
kind, sym_type, NULL, addr,
|
||
NULL, 0);
|
||
C_CTX (context)->c_ops->bind (C_CTX (context), decl, 1 /* is_global */);
|
||
}
|
||
|
||
/* See compile-internal.h. */
|
||
|
||
void
|
||
gcc_convert_symbol (void *datum,
|
||
struct gcc_c_context *gcc_context,
|
||
enum gcc_c_oracle_request request,
|
||
const char *identifier)
|
||
{
|
||
struct compile_c_instance *context = datum;
|
||
domain_enum domain;
|
||
int found = 0;
|
||
|
||
switch (request)
|
||
{
|
||
case GCC_C_ORACLE_SYMBOL:
|
||
domain = VAR_DOMAIN;
|
||
break;
|
||
case GCC_C_ORACLE_TAG:
|
||
domain = STRUCT_DOMAIN;
|
||
break;
|
||
case GCC_C_ORACLE_LABEL:
|
||
domain = LABEL_DOMAIN;
|
||
break;
|
||
default:
|
||
gdb_assert_not_reached ("Unrecognized oracle request.");
|
||
}
|
||
|
||
/* We can't allow exceptions to escape out of this callback. Safest
|
||
is to simply emit a gcc error. */
|
||
TRY
|
||
{
|
||
struct block_symbol sym;
|
||
|
||
sym = lookup_symbol (identifier, context->base.block, domain, NULL);
|
||
if (sym.symbol != NULL)
|
||
{
|
||
convert_symbol_sym (context, identifier, sym, domain);
|
||
found = 1;
|
||
}
|
||
else if (domain == VAR_DOMAIN)
|
||
{
|
||
struct bound_minimal_symbol bmsym;
|
||
|
||
bmsym = lookup_minimal_symbol (identifier, NULL, NULL);
|
||
if (bmsym.minsym != NULL)
|
||
{
|
||
convert_symbol_bmsym (context, bmsym);
|
||
found = 1;
|
||
}
|
||
}
|
||
}
|
||
|
||
CATCH (e, RETURN_MASK_ALL)
|
||
{
|
||
C_CTX (context)->c_ops->error (C_CTX (context), e.message);
|
||
}
|
||
END_CATCH
|
||
|
||
if (compile_debug && !found)
|
||
fprintf_unfiltered (gdb_stdlog,
|
||
"gcc_convert_symbol \"%s\": lookup_symbol failed\n",
|
||
identifier);
|
||
return;
|
||
}
|
||
|
||
/* See compile-internal.h. */
|
||
|
||
gcc_address
|
||
gcc_symbol_address (void *datum, struct gcc_c_context *gcc_context,
|
||
const char *identifier)
|
||
{
|
||
struct compile_c_instance *context = datum;
|
||
gcc_address result = 0;
|
||
int found = 0;
|
||
|
||
/* We can't allow exceptions to escape out of this callback. Safest
|
||
is to simply emit a gcc error. */
|
||
TRY
|
||
{
|
||
struct symbol *sym;
|
||
|
||
/* We only need global functions here. */
|
||
sym = lookup_symbol (identifier, NULL, VAR_DOMAIN, NULL).symbol;
|
||
if (sym != NULL && SYMBOL_CLASS (sym) == LOC_BLOCK)
|
||
{
|
||
if (compile_debug)
|
||
fprintf_unfiltered (gdb_stdlog,
|
||
"gcc_symbol_address \"%s\": full symbol\n",
|
||
identifier);
|
||
result = BLOCK_START (SYMBOL_BLOCK_VALUE (sym));
|
||
if (TYPE_GNU_IFUNC (SYMBOL_TYPE (sym)))
|
||
result = gnu_ifunc_resolve_addr (target_gdbarch (), result);
|
||
found = 1;
|
||
}
|
||
else
|
||
{
|
||
struct bound_minimal_symbol msym;
|
||
|
||
msym = lookup_bound_minimal_symbol (identifier);
|
||
if (msym.minsym != NULL)
|
||
{
|
||
if (compile_debug)
|
||
fprintf_unfiltered (gdb_stdlog,
|
||
"gcc_symbol_address \"%s\": minimal "
|
||
"symbol\n",
|
||
identifier);
|
||
result = BMSYMBOL_VALUE_ADDRESS (msym);
|
||
if (MSYMBOL_TYPE (msym.minsym) == mst_text_gnu_ifunc)
|
||
result = gnu_ifunc_resolve_addr (target_gdbarch (), result);
|
||
found = 1;
|
||
}
|
||
}
|
||
}
|
||
|
||
CATCH (e, RETURN_MASK_ERROR)
|
||
{
|
||
C_CTX (context)->c_ops->error (C_CTX (context), e.message);
|
||
}
|
||
END_CATCH
|
||
|
||
if (compile_debug && !found)
|
||
fprintf_unfiltered (gdb_stdlog,
|
||
"gcc_symbol_address \"%s\": failed\n",
|
||
identifier);
|
||
return result;
|
||
}
|
||
|
||
|
||
|
||
/* A hash function for symbol names. */
|
||
|
||
static hashval_t
|
||
hash_symname (const void *a)
|
||
{
|
||
const struct symbol *sym = a;
|
||
|
||
return htab_hash_string (SYMBOL_NATURAL_NAME (sym));
|
||
}
|
||
|
||
/* A comparison function for hash tables that just looks at symbol
|
||
names. */
|
||
|
||
static int
|
||
eq_symname (const void *a, const void *b)
|
||
{
|
||
const struct symbol *syma = a;
|
||
const struct symbol *symb = b;
|
||
|
||
return strcmp (SYMBOL_NATURAL_NAME (syma), SYMBOL_NATURAL_NAME (symb)) == 0;
|
||
}
|
||
|
||
/* If a symbol with the same name as SYM is already in HASHTAB, return
|
||
1. Otherwise, add SYM to HASHTAB and return 0. */
|
||
|
||
static int
|
||
symbol_seen (htab_t hashtab, struct symbol *sym)
|
||
{
|
||
void **slot;
|
||
|
||
slot = htab_find_slot (hashtab, sym, INSERT);
|
||
if (*slot != NULL)
|
||
return 1;
|
||
|
||
*slot = sym;
|
||
return 0;
|
||
}
|
||
|
||
/* Generate C code to compute the length of a VLA. */
|
||
|
||
static void
|
||
generate_vla_size (struct compile_c_instance *compiler,
|
||
struct ui_file *stream,
|
||
struct gdbarch *gdbarch,
|
||
unsigned char *registers_used,
|
||
CORE_ADDR pc,
|
||
struct type *type,
|
||
struct symbol *sym)
|
||
{
|
||
type = check_typedef (type);
|
||
|
||
if (TYPE_CODE (type) == TYPE_CODE_REF)
|
||
type = check_typedef (TYPE_TARGET_TYPE (type));
|
||
|
||
switch (TYPE_CODE (type))
|
||
{
|
||
case TYPE_CODE_RANGE:
|
||
{
|
||
if (TYPE_HIGH_BOUND_KIND (type) == PROP_LOCEXPR
|
||
|| TYPE_HIGH_BOUND_KIND (type) == PROP_LOCLIST)
|
||
{
|
||
const struct dynamic_prop *prop = &TYPE_RANGE_DATA (type)->high;
|
||
char *name = c_get_range_decl_name (prop);
|
||
struct cleanup *cleanup = make_cleanup (xfree, name);
|
||
|
||
dwarf2_compile_property_to_c (stream, name,
|
||
gdbarch, registers_used,
|
||
prop, pc, sym);
|
||
do_cleanups (cleanup);
|
||
}
|
||
}
|
||
break;
|
||
|
||
case TYPE_CODE_ARRAY:
|
||
generate_vla_size (compiler, stream, gdbarch, registers_used, pc,
|
||
TYPE_INDEX_TYPE (type), sym);
|
||
generate_vla_size (compiler, stream, gdbarch, registers_used, pc,
|
||
TYPE_TARGET_TYPE (type), sym);
|
||
break;
|
||
|
||
case TYPE_CODE_UNION:
|
||
case TYPE_CODE_STRUCT:
|
||
{
|
||
int i;
|
||
|
||
for (i = 0; i < TYPE_NFIELDS (type); ++i)
|
||
if (!field_is_static (&TYPE_FIELD (type, i)))
|
||
generate_vla_size (compiler, stream, gdbarch, registers_used, pc,
|
||
TYPE_FIELD_TYPE (type, i), sym);
|
||
}
|
||
break;
|
||
}
|
||
}
|
||
|
||
/* Generate C code to compute the address of SYM. */
|
||
|
||
static void
|
||
generate_c_for_for_one_variable (struct compile_c_instance *compiler,
|
||
struct ui_file *stream,
|
||
struct gdbarch *gdbarch,
|
||
unsigned char *registers_used,
|
||
CORE_ADDR pc,
|
||
struct symbol *sym)
|
||
{
|
||
|
||
TRY
|
||
{
|
||
if (is_dynamic_type (SYMBOL_TYPE (sym)))
|
||
{
|
||
struct ui_file *size_file = mem_fileopen ();
|
||
struct cleanup *cleanup = make_cleanup_ui_file_delete (size_file);
|
||
|
||
generate_vla_size (compiler, size_file, gdbarch, registers_used, pc,
|
||
SYMBOL_TYPE (sym), sym);
|
||
ui_file_put (size_file, ui_file_write_for_put, stream);
|
||
|
||
do_cleanups (cleanup);
|
||
}
|
||
|
||
if (SYMBOL_COMPUTED_OPS (sym) != NULL)
|
||
{
|
||
char *generated_name = symbol_substitution_name (sym);
|
||
struct cleanup *cleanup = make_cleanup (xfree, generated_name);
|
||
/* We need to emit to a temporary buffer in case an error
|
||
occurs in the middle. */
|
||
struct ui_file *local_file = mem_fileopen ();
|
||
|
||
make_cleanup_ui_file_delete (local_file);
|
||
SYMBOL_COMPUTED_OPS (sym)->generate_c_location (sym, local_file,
|
||
gdbarch,
|
||
registers_used,
|
||
pc, generated_name);
|
||
ui_file_put (local_file, ui_file_write_for_put, stream);
|
||
|
||
do_cleanups (cleanup);
|
||
}
|
||
else
|
||
{
|
||
switch (SYMBOL_CLASS (sym))
|
||
{
|
||
case LOC_REGISTER:
|
||
case LOC_ARG:
|
||
case LOC_REF_ARG:
|
||
case LOC_REGPARM_ADDR:
|
||
case LOC_LOCAL:
|
||
error (_("Local symbol unhandled when generating C code."));
|
||
|
||
case LOC_COMPUTED:
|
||
gdb_assert_not_reached (_("LOC_COMPUTED variable "
|
||
"missing a method."));
|
||
|
||
default:
|
||
/* Nothing to do for all other cases, as they don't represent
|
||
local variables. */
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
CATCH (e, RETURN_MASK_ERROR)
|
||
{
|
||
if (compiler->symbol_err_map == NULL)
|
||
compiler->symbol_err_map = htab_create_alloc (10,
|
||
hash_symbol_error,
|
||
eq_symbol_error,
|
||
del_symbol_error,
|
||
xcalloc,
|
||
xfree);
|
||
insert_symbol_error (compiler->symbol_err_map, sym, e.message);
|
||
}
|
||
END_CATCH
|
||
}
|
||
|
||
/* See compile-internal.h. */
|
||
|
||
unsigned char *
|
||
generate_c_for_variable_locations (struct compile_c_instance *compiler,
|
||
struct ui_file *stream,
|
||
struct gdbarch *gdbarch,
|
||
const struct block *block,
|
||
CORE_ADDR pc)
|
||
{
|
||
struct cleanup *cleanup, *outer;
|
||
htab_t symhash;
|
||
const struct block *static_block = block_static_block (block);
|
||
unsigned char *registers_used;
|
||
|
||
/* If we're already in the static or global block, there is nothing
|
||
to write. */
|
||
if (static_block == NULL || block == static_block)
|
||
return NULL;
|
||
|
||
registers_used = XCNEWVEC (unsigned char, gdbarch_num_regs (gdbarch));
|
||
outer = make_cleanup (xfree, registers_used);
|
||
|
||
/* Ensure that a given name is only entered once. This reflects the
|
||
reality of shadowing. */
|
||
symhash = htab_create_alloc (1, hash_symname, eq_symname, NULL,
|
||
xcalloc, xfree);
|
||
cleanup = make_cleanup_htab_delete (symhash);
|
||
|
||
while (1)
|
||
{
|
||
struct symbol *sym;
|
||
struct block_iterator iter;
|
||
|
||
/* Iterate over symbols in this block, generating code to
|
||
compute the location of each local variable. */
|
||
for (sym = block_iterator_first (block, &iter);
|
||
sym != NULL;
|
||
sym = block_iterator_next (&iter))
|
||
{
|
||
if (!symbol_seen (symhash, sym))
|
||
generate_c_for_for_one_variable (compiler, stream, gdbarch,
|
||
registers_used, pc, sym);
|
||
}
|
||
|
||
/* If we just finished the outermost block of a function, we're
|
||
done. */
|
||
if (BLOCK_FUNCTION (block) != NULL)
|
||
break;
|
||
block = BLOCK_SUPERBLOCK (block);
|
||
}
|
||
|
||
do_cleanups (cleanup);
|
||
discard_cleanups (outer);
|
||
return registers_used;
|
||
}
|