C++ compile support

This patch adds *basic* support for C++ to the compile feature.  It does
most simple type conversions, including everything that C compile does and
your basic "with-classes" type of C++.

I've written a new compile-support.exp support file which adds a new test
facility for automating and simplifying "compile print" vs "compile code"
testing.  See testsuite/lib/compile-support.exp and CompileExpression
for more on that.  The tests use this facility extensively.

This initial support has several glaring omissions:
- No template support at all
  I have follow-on patches for this, but they add much complexity
  to this "basic" support.  Consequently, they will be submitted separately.
- Cannot print functions
  The code template needs tweaking, and I simply haven't gotten to it yet.
- So-called "special function" support is not included
  Using constructors, destructors, operators, etc will not work. I have
  follow-on patches for that, but they require some work because of the
  recent churn in symbol searching.
- There are several test suite references to "compile/1234" bugs.
  I will file bugs and update the test suite's bug references before pushing
  these patches.

The test suite started as a copy of the original C-language support, but
I have written tests to exercise the basic functionality of the plug-in.

I've added a new option for outputting debug messages for C++ type-conversion
("debug compile-cplus-types").

gdb/ChangeLog:

	* Makefile.in (SUBDIR_GCC_COMPILE_SRCS): Add compile-cplus-symbols.c
	and compile-cplus-types.c.
	(HFILES_NO_SRCDIR): Add gcc-cp-plugin.h.
	* c-lang.c (cplus_language_defn): Set C++ compile functions.
	* c-lang.h (cplus_get_compile_context, cplus_compute_program):
	Declare.
	* compile/compile-c-support.c: Include compile-cplus.h.
	(load_libcompile): Templatize.
	(get_compile_context): "New" function.
	(c_get_compile_context): Use get_compile_context.
	(cplus_get_compile_context): New function.
	(cplus_push_user_expression, cplus_pop_user_expression)
	(cplus_add_code_header, cplus_add_input, cplus_compile_program)
	(cplus_compute_program): Define new structs/functions.
	* compile/compile-cplus-symmbols.c: New file.
	* compile/compile-cplus-types.c: New file.
	* compile/compile-cplus.h: New file.
	* compile/compile-internal.h (debug_compile_oracle, GCC_TYPE_NONE):
	Declare.
	* compile/compile-object-load.c (get_out_value_type): Use
	strncmp_iw when comparing symbol names.
	(compile_object_load): Add mst_bss and mst_data.
	* compile/compile.c (_initialize_compile): Remove
	-Wno-implicit-function-declaration from `compile_args'.
	* compile/gcc-cp-plugin.h: New file.
	* NEWS: Mention C++ compile support and new debug options.

gdb/testsuite/ChangeLog:

	* gdb.compile/compile-cplus-anonymous.cc: New file.
	* gdb.compile/compile-cplus-anonymous.exp: New file.
	* gdb.compile/compile-cplus-array-decay.cc: New file.
	* gdb.compile/compile-cplus-array-decay.exp: New file.
	* gdb.compile/compile-cplus-inherit.cc: New file.
	* gdb.compile/compile-cplus-inherit.exp: New file.
	* gdb.compile/compile-cplus-member.cc: New file.
	* gdb.compile/compile-cplus-member.exp: New file.
	* gdb.compile/compile-cplus-method.cc: New file.
	* gdb.compile/compile-cplus-method.exp: New file.
	* gdb.compile/compile-cplus-mod.c: "New" file.
	* gdb.compile/compile-cplus-namespace.cc: New file.
	* gdb.compile/compile-cplus-namespace.exp: New file.
	* gdb.compile/compile-cplus-nested.cc: New file.
	* gdb.compile/compile-cplus-nested.exp: New file.
	* gdb.compile/compile-cplus-print.c: "New" file.
	* gdb.compile/compile-cplus-print.exp: "New" file.
	* gdb.compile/compile-cplus-virtual.cc: New file.
	* gdb.compile/compile-cplus-virtual.exp: New file.
	* gdb.compile/compile-cplus.c: "New" file.
	* gdb.compile/compile-cplus.exp: "New" file.
	* lib/compile-support.exp: New file.

doc/ChangeLog:

	* gdb.texinfo (Compiling and injecting code in GDB): Document
	set/show "compile-oracle" and "compile-cplus-types" commands.
This commit is contained in:
Keith Seitz
2018-08-29 15:12:24 -07:00
parent fcaad03cc0
commit 078a020797
38 changed files with 4449 additions and 30 deletions

View File

@@ -1,4 +1,4 @@
/* C language support for compilation.
/* C/C++ language support for compilation.
Copyright (C) 2014-2018 Free Software Foundation, Inc.
@@ -20,6 +20,7 @@
#include "defs.h"
#include "compile-internal.h"
#include "compile-c.h"
#include "compile-cplus.h"
#include "compile.h"
#include "gdb-dlfcn.h"
#include "c-lang.h"
@@ -67,25 +68,22 @@ c_get_range_decl_name (const struct dynamic_prop *prop)
/* Helper function for c_get_compile_context. Open the GCC front-end
shared library and return the symbol specified by the current
GCC_C_FE_CONTEXT. */
/* Load the plug-in library FE_LIBCC and return the initialization function
FE_CONTEXT. */
static gcc_c_fe_context_function *
load_libcc (void)
template <typename FUNCTYPE>
FUNCTYPE *
load_libcompile (const char *fe_libcc, const char *fe_context)
{
gcc_c_fe_context_function *func;
FUNCTYPE *func;
/* gdb_dlopen will call error () on an error, so no need to check
value. */
gdb_dlhandle_up handle = gdb_dlopen (STRINGIFY (GCC_C_FE_LIBCC));
func = (gcc_c_fe_context_function *) gdb_dlsym (handle,
STRINGIFY (GCC_C_FE_CONTEXT));
/* gdb_dlopen will call error () on an error, so no need to check
value. */
gdb_dlhandle_up handle = gdb_dlopen (fe_libcc);
func = (FUNCTYPE *) gdb_dlsym (handle, fe_context);
if (func == NULL)
error (_("could not find symbol %s in library %s"),
STRINGIFY (GCC_C_FE_CONTEXT),
STRINGIFY (GCC_C_FE_LIBCC));
error (_("could not find symbol %s in library %s"), fe_context, fe_libcc);
/* Leave the library open. */
handle.release ();
@@ -93,28 +91,57 @@ load_libcc (void)
}
/* Return the compile instance associated with the current context.
This function calls the symbol returned from the load_libcc
function. This will provide the gcc_c_context. */
This function calls the symbol returned from the load_libcompile
function. FE_LIBCC is the library to load. BASE_VERSION is the
base compile plug-in version we support. API_VERSION is the
API version supported. */
template <typename INSTTYPE, typename FUNCTYPE, typename CTXTYPE,
typename BASE_VERSION_TYPE, typename API_VERSION_TYPE>
compile_instance *
c_get_compile_context (void)
get_compile_context (const char *fe_libcc, const char *fe_context,
BASE_VERSION_TYPE base_version,
API_VERSION_TYPE api_version)
{
static gcc_c_fe_context_function *func;
struct gcc_c_context *context;
static FUNCTYPE *func;
static CTXTYPE *context;
if (func == NULL)
{
func = load_libcc ();
func = load_libcompile<FUNCTYPE> (fe_libcc, fe_context);
gdb_assert (func != NULL);
}
context = (*func) (GCC_FE_VERSION_0, GCC_C_FE_VERSION_0);
context = (*func) (base_version, api_version);
if (context == NULL)
error (_("The loaded version of GCC does not support the required version "
"of the API."));
return new compile_c_instance (context);
return new INSTTYPE (context);
}
/* A C-language implementation of get_compile_context. */
compile_instance *
c_get_compile_context ()
{
return get_compile_context
<compile_c_instance, gcc_c_fe_context_function, gcc_c_context,
gcc_base_api_version, gcc_c_api_version>
(STRINGIFY (GCC_C_FE_LIBCC), STRINGIFY (GCC_C_FE_CONTEXT),
GCC_FE_VERSION_0, GCC_C_FE_VERSION_0);
}
/* A C++-language implementation of get_compile_context. */
compile_instance *
cplus_get_compile_context ()
{
return get_compile_context
<compile_cplus_instance, gcc_cp_fe_context_function, gcc_cp_context,
gcc_base_api_version, gcc_cp_api_version>
(STRINGIFY (GCC_CP_FE_LIBCC), STRINGIFY (GCC_CP_FE_CONTEXT),
GCC_FE_VERSION_0, GCC_CP_FE_VERSION_0);
}
@@ -384,6 +411,113 @@ struct c_add_input
}
};
/* C++-language policy to emit a push user expression pragma into
BUF. */
struct cplus_push_user_expression
{
void push_user_expression (struct ui_file *buf)
{
fputs_unfiltered ("#pragma GCC push_user_expression\n", buf);
}
};
/* C++-language policy to emit a pop user expression pragma into BUF. */
struct cplus_pop_user_expression
{
void pop_user_expression (struct ui_file *buf)
{
fputs_unfiltered ("#pragma GCC pop_user_expression\n", buf);
}
};
/* C++-language policy to construct a code header for a block of code.
Takes a scope TYPE argument which selects the correct header to
insert into BUF. */
struct cplus_add_code_header
{
void add_code_header (enum compile_i_scope_types type, struct ui_file *buf)
{
switch (type)
{
case COMPILE_I_SIMPLE_SCOPE:
fputs_unfiltered ("void "
GCC_FE_WRAPPER_FUNCTION
" (struct "
COMPILE_I_SIMPLE_REGISTER_STRUCT_TAG
" *"
COMPILE_I_SIMPLE_REGISTER_ARG_NAME
") {\n",
buf);
break;
case COMPILE_I_PRINT_ADDRESS_SCOPE:
case COMPILE_I_PRINT_VALUE_SCOPE:
fputs_unfiltered (
"#include <cstring>\n"
"#include <bits/move.h>\n"
"void "
GCC_FE_WRAPPER_FUNCTION
" (struct "
COMPILE_I_SIMPLE_REGISTER_STRUCT_TAG
" *"
COMPILE_I_SIMPLE_REGISTER_ARG_NAME
", "
COMPILE_I_PRINT_OUT_ARG_TYPE
" "
COMPILE_I_PRINT_OUT_ARG
") {\n",
buf);
break;
case COMPILE_I_RAW_SCOPE:
break;
default:
gdb_assert_not_reached (_("Unknown compiler scope reached."));
}
}
};
/* C++-language policy to emit the user code snippet INPUT into BUF based on
the scope TYPE. */
struct cplus_add_input
{
void add_input (enum compile_i_scope_types type, const char *input,
struct ui_file *buf)
{
switch (type)
{
case COMPILE_I_PRINT_VALUE_SCOPE:
case COMPILE_I_PRINT_ADDRESS_SCOPE:
fprintf_unfiltered
(buf,
/* "auto" strips ref- and cv- qualifiers, so we need to also strip
those from COMPILE_I_EXPR_PTR_TYPE. */
"auto " COMPILE_I_EXPR_VAL " = %s;\n"
"typedef "
"std::add_pointer<std::remove_cv<decltype (%s)>::type>::type "
" __gdb_expr_ptr;\n"
"__gdb_expr_ptr " COMPILE_I_EXPR_PTR_TYPE ";\n"
"std::memcpy (" COMPILE_I_PRINT_OUT_ARG ", %s ("
COMPILE_I_EXPR_VAL "),\n"
"\tsizeof (*" COMPILE_I_EXPR_PTR_TYPE "));\n"
,input, input,
(type == COMPILE_I_PRINT_ADDRESS_SCOPE
? "__builtin_addressof" : ""));
break;
default:
fputs_unfiltered (input, buf);
break;
}
fputs_unfiltered ("\n", buf);
}
};
/* A host class representing a compile program.
CompileInstanceType is the type of the compile_instance for the
@@ -513,13 +647,18 @@ private:
struct gdbarch *m_arch;
};
/* Type used for C program computations. */
/* The types used for C and C++ program computations. */
typedef compile_program<compile_c_instance,
c_push_user_expression, pop_user_expression_nop,
c_add_code_header, c_add_code_footer,
c_add_input> c_compile_program;
typedef compile_program<compile_cplus_instance,
cplus_push_user_expression, cplus_pop_user_expression,
cplus_add_code_header, c_add_code_footer,
cplus_add_input> cplus_compile_program;
/* The la_compute_program method for C. */
std::string
@@ -534,3 +673,19 @@ c_compute_program (compile_instance *inst,
return program.compute (input, expr_block, expr_pc);
}
/* The la_compute_program method for C++. */
std::string
cplus_compute_program (compile_instance *inst,
const char *input,
struct gdbarch *gdbarch,
const struct block *expr_block,
CORE_ADDR expr_pc)
{
compile_cplus_instance *cplus_inst
= static_cast<compile_cplus_instance *> (inst);
cplus_compile_program program (cplus_inst, gdbarch);
return program.compute (input, expr_block, expr_pc);
}

View File

@@ -0,0 +1,493 @@
/* Convert symbols from GDB to GCC
Copyright (C) 2014-2018 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 "compile-cplus.h"
#include "gdb_assert.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"
#include "cp-support.h"
#include "gdbcmd.h"
#include "compile-c.h"
/* Convert a given symbol, SYM, to the compiler's representation.
INSTANCE 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 (compile_cplus_instance *instance,
struct block_symbol sym, bool is_global, bool is_local)
{
/* Squash compiler warning. */
gcc_type sym_type = 0;
const char *filename = symbol_symtab (sym.symbol)->filename;
unsigned short line = SYMBOL_LINE (sym.symbol);
instance->error_symbol_once (sym.symbol);
if (SYMBOL_CLASS (sym.symbol) == LOC_LABEL)
sym_type = 0;
else
sym_type = instance->convert_type (SYMBOL_TYPE (sym.symbol));
if (SYMBOL_DOMAIN (sym.symbol) == STRUCT_DOMAIN)
{
/* Nothing to do. */
}
else
{
/* Squash compiler warning. */
gcc_cp_symbol_kind_flags kind = GCC_CP_FLAG_BASE;
CORE_ADDR addr = 0;
std::string name;
gdb::unique_xmalloc_ptr<char> symbol_name;
switch (SYMBOL_CLASS (sym.symbol))
{
case LOC_TYPEDEF:
if (TYPE_CODE (SYMBOL_TYPE (sym.symbol)) == TYPE_CODE_TYPEDEF)
kind = GCC_CP_SYMBOL_TYPEDEF;
else if (TYPE_CODE (SYMBOL_TYPE (sym.symbol)) == TYPE_CODE_NAMESPACE)
return;
break;
case LOC_LABEL:
kind = GCC_CP_SYMBOL_LABEL;
addr = SYMBOL_VALUE_ADDRESS (sym.symbol);
break;
case LOC_BLOCK:
{
kind = GCC_CP_SYMBOL_FUNCTION;
addr = BLOCK_START (SYMBOL_BLOCK_VALUE (sym.symbol));
if (is_global && TYPE_GNU_IFUNC (SYMBOL_TYPE (sym.symbol)))
addr = gnu_ifunc_resolve_addr (target_gdbarch (), addr);
}
break;
case LOC_CONST:
if (TYPE_CODE (SYMBOL_TYPE (sym.symbol)) == TYPE_CODE_ENUM)
{
/* Already handled by convert_enum. */
return;
}
instance->plugin ().build_constant
(sym_type, SYMBOL_NATURAL_NAME (sym.symbol),
SYMBOL_VALUE (sym.symbol), filename, line);
return;
case LOC_CONST_BYTES:
error (_("Unsupported LOC_CONST_BYTES for symbol \"%s\"."),
SYMBOL_PRINT_NAME (sym.symbol));
case LOC_UNDEF:
internal_error (__FILE__, __LINE__, _("LOC_UNDEF found for \"%s\"."),
SYMBOL_PRINT_NAME (sym.symbol));
case LOC_COMMON_BLOCK:
error (_("Fortran common block is unsupported for compilation "
"evaluaton of symbol \"%s\"."),
SYMBOL_PRINT_NAME (sym.symbol));
case LOC_OPTIMIZED_OUT:
error (_("Symbol \"%s\" cannot be used for compilation evaluation "
"as it is optimized out."),
SYMBOL_PRINT_NAME (sym.symbol));
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.symbol));
/* 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 = nullptr;
if (symbol_read_needs_frame (sym.symbol))
{
frame = get_selected_frame (nullptr);
if (frame == nullptr)
error (_("Symbol \"%s\" cannot be used because "
"there is no selected frame"),
SYMBOL_PRINT_NAME (sym.symbol));
}
val = read_var_value (sym.symbol, sym.block, 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.symbol));
kind = GCC_CP_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_CP_SYMBOL_VARIABLE;
symbol_name = c_symbol_substitution_name (sym.symbol);
break;
case LOC_STATIC:
kind = GCC_CP_SYMBOL_VARIABLE;
addr = SYMBOL_VALUE_ADDRESS (sym.symbol);
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 (instance->scope () != COMPILE_I_RAW_SCOPE || symbol_name == nullptr)
{
compile_scope scope;
/* For non-local symbols, create/push a new scope so that the
symbol is properly scoped to the plug-in. */
if (!is_local)
{
scope
= instance->new_scope (SYMBOL_NATURAL_NAME (sym.symbol),
SYMBOL_TYPE (sym.symbol));
if (scope.nested_type () != GCC_TYPE_NONE)
{
/* We found a symbol for this type that was defined inside
some other symbol, e.g., a class tyepdef defined. */
return;
}
instance->enter_scope (scope);
}
/* Get the `raw' name of the symbol. */
if (name.empty () && SYMBOL_NATURAL_NAME (sym.symbol) != nullptr)
name = compile_cplus_instance::decl_name
(SYMBOL_NATURAL_NAME (sym.symbol)).get ();
/* Define the decl. */
instance->plugin ().build_decl
("variable", name.c_str (), kind, sym_type,
symbol_name.get (), addr, filename, line);
/* Pop scope for non-local symbols. */
if (!is_local)
instance->leave_scope ();
}
}
}
/* 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 (compile_cplus_instance *instance,
const char *identifier, struct block_symbol sym,
domain_enum domain)
{
/* 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"
}
*/
const struct block *static_block = block_static_block (sym.block);
/* STATIC_BLOCK is NULL if FOUND_BLOCK is the global block. */
bool is_local_symbol = (sym.block != static_block && static_block != nullptr);
if (is_local_symbol)
{
struct block_symbol global_sym;
global_sym = lookup_symbol (identifier, nullptr, domain, nullptr);
/* If the outer symbol is in the static block, we ignore it, as
it cannot be referenced. */
if (global_sym.symbol != nullptr
&& 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 (instance, global_sym, true, false);
}
}
if (compile_debug)
fprintf_unfiltered (gdb_stdlog,
"gcc_convert_symbol \"%s\": local symbol\n",
identifier);
convert_one_symbol (instance, sym, false, 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 (compile_cplus_instance *instance,
struct bound_minimal_symbol bmsym)
{
struct minimal_symbol *msym = bmsym.minsym;
struct objfile *objfile = bmsym.objfile;
struct type *type;
gcc_cp_symbol_kind_flags kind;
gcc_type sym_type;
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_CP_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_CP_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_CP_SYMBOL_VARIABLE;
break;
case mst_slot_got_plt:
type = objfile_type (objfile)->nodebug_got_plt_symbol;
kind = GCC_CP_SYMBOL_FUNCTION;
break;
default:
type = objfile_type (objfile)->nodebug_unknown_symbol;
kind = GCC_CP_SYMBOL_VARIABLE;
break;
}
sym_type = instance->convert_type (type);
instance->plugin ().push_namespace ("");
instance->plugin ().build_decl
("minsym", MSYMBOL_NATURAL_NAME (msym), kind, sym_type, nullptr, addr,
nullptr, 0);
instance->plugin ().pop_binding_level ("");
}
/* See compile-cplus.h. */
void
gcc_cplus_convert_symbol (void *datum,
struct gcc_cp_context *gcc_context,
enum gcc_cp_oracle_request request ATTRIBUTE_UNUSED,
const char *identifier)
{
if (compile_debug)
fprintf_unfiltered (gdb_stdlog,
"got oracle request for \"%s\"\n", identifier);
bool found = false;
compile_cplus_instance *instance = (compile_cplus_instance *) datum;
TRY
{
/* Symbol searching is a three part process unfortunately. */
/* First do a "standard" lookup, converting any found symbols.
This will find variables in the current scope. */
struct block_symbol sym
= lookup_symbol (identifier, instance->block (), VAR_DOMAIN, nullptr);
if (sym.symbol != nullptr)
{
found = true;
convert_symbol_sym (instance, identifier, sym, VAR_DOMAIN);
}
/* Then use linespec.c's multi-symbol search. This should find
all non-variable symbols for which we have debug info. */
symbol_searcher searcher;
searcher.find_all_symbols (identifier, current_language,
ALL_DOMAIN, nullptr, nullptr);
/* Convert any found symbols. */
for (const auto &it : searcher.matching_symbols ())
{
/* Don't convert the symbol found above, if any, twice! */
if (it.symbol != sym.symbol)
{
found = true;
convert_symbol_sym (instance, identifier, it,
SYMBOL_DOMAIN (it.symbol));
}
}
/* Finally, if no symbols have been found, fall back to minsyms. */
if (!found)
{
for (const auto &it : searcher.matching_msymbols ())
{
found = true;
convert_symbol_bmsym (instance, it);
}
}
}
CATCH (e, RETURN_MASK_ALL)
{
/* We can't allow exceptions to escape out of this callback. Safest
is to simply emit a gcc error. */
instance->plugin ().error (e.message);
}
END_CATCH
if (compile_debug && !found)
fprintf_unfiltered (gdb_stdlog,
"gcc_convert_symbol \"%s\": lookup_symbol failed\n",
identifier);
if (compile_debug)
{
if (found)
fprintf_unfiltered (gdb_stdlog, "found type for %s\n", identifier);
else
{
fprintf_unfiltered (gdb_stdlog, "did not find type for %s\n",
identifier);
}
}
return;
}
/* See compile-cplus.h. */
gcc_address
gcc_cplus_symbol_address (void *datum, struct gcc_cp_context *gcc_context,
const char *identifier)
{
compile_cplus_instance *instance = (compile_cplus_instance *) datum;
gcc_address result = 0;
int found = 0;
if (compile_debug)
fprintf_unfiltered (gdb_stdlog,
"got oracle request for address of %s\n", identifier);
/* We can't allow exceptions to escape out of this callback. Safest
is to simply emit a gcc error. */
TRY
{
struct symbol *sym
= lookup_symbol (identifier, nullptr, VAR_DOMAIN, nullptr).symbol;
if (sym != nullptr && 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 != nullptr)
{
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)
{
instance->plugin ().error (e.message);
}
END_CATCH
if (compile_debug && !found)
fprintf_unfiltered (gdb_stdlog,
"gcc_symbol_address \"%s\": failed\n",
identifier);
if (compile_debug)
{
if (found)
fprintf_unfiltered (gdb_stdlog, "found address for %s!\n", identifier);
else
fprintf_unfiltered (gdb_stdlog,
"did not find address for %s\n", identifier);
}
return result;
}

File diff suppressed because it is too large Load Diff

205
gdb/compile/compile-cplus.h Normal file
View File

@@ -0,0 +1,205 @@
/* Header file for GDB compile C++ language support.
Copyright (C) 2016-2018 Free Software Foundation, Inc.
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/>. */
#ifndef GDB_COMPILE_CPLUS_H
#define GDB_COMPILE_CPLUS_H
#include "common/enum-flags.h"
#include "gcc-cp-plugin.h"
struct type;
struct block;
/* enum-flags wrapper */
DEF_ENUM_FLAGS_TYPE (enum gcc_cp_qualifiers, gcc_cp_qualifiers_flags);
DEF_ENUM_FLAGS_TYPE (enum gcc_cp_ref_qualifiers, gcc_cp_ref_qualifiers_flags);
DEF_ENUM_FLAGS_TYPE (enum gcc_cp_symbol_kind, gcc_cp_symbol_kind_flags);
class compile_cplus_instance;
/* A single component of a type's scope. Type names are broken into
"components," a series of unqualified names comprising the type name,
e.g., "namespace1", "namespace2", "myclass". */
struct scope_component
{
/* The unqualified name of this scope. */
std::string name;
/* The block symbol for this type/scope. */
struct block_symbol bsymbol;
};
/* Comparison operators for scope_components. */
bool operator== (const scope_component &lhs, const scope_component &rhs);
bool operator!= (const scope_component &lhs, const scope_component &rhs);
/* A single compiler scope used to define a type.
A compile_scope is a list of scope_components, where all leading
scope_components are namespaces, followed by a single non-namespace
type component (the actual type we are converting). */
class compile_scope : private std::vector<scope_component>
{
public:
using std::vector<scope_component>::push_back;
using std::vector<scope_component>::pop_back;
using std::vector<scope_component>::back;
using std::vector<scope_component>::empty;
using std::vector<scope_component>::size;
using std::vector<scope_component>::begin;
using std::vector<scope_component>::end;
using std::vector<scope_component>::operator[];
compile_scope ()
: m_nested_type (GCC_TYPE_NONE), m_pushed (false)
{
}
/* Return the gcc_type of the type if it is a nested definition.
Returns GCC_TYPE_NONE if this type was not nested. */
gcc_type nested_type ()
{
return m_nested_type;
}
private:
/* compile_cplus_instance is a friend class so that it can set the
following private members when compile_scopes are created. */
friend compile_cplus_instance;
/* If the type was actually a nested type, this will hold that nested
type after the scope is pushed. */
gcc_type m_nested_type;
/* If true, this scope was pushed to the compiler and all namespaces
must be popped when leaving the scope. */
bool m_pushed;
};
/* Comparison operators for compile_scopes. */
bool operator== (const compile_scope &lhs, const compile_scope &rhs);
bool operator!= (const compile_scope &lhs, const compile_scope &rhs);
/* Convert TYPENAME into a vector of namespace and top-most/super
composite scopes.
For example, for the input "Namespace::classB::classInner", the
resultant vector will contain the tokens "Namespace" and
"classB". */
compile_scope type_name_to_scope (const char *type_name,
const struct block *block);
/* A callback suitable for use as the GCC C++ symbol oracle. */
extern gcc_cp_oracle_function gcc_cplus_convert_symbol;
/* A callback suitable for use as the GCC C++ address oracle. */
extern gcc_cp_symbol_address_function gcc_cplus_symbol_address;
/* A subclass of compile_instance that is specific to the C++ front
end. */
class compile_cplus_instance : public compile_instance
{
public:
explicit compile_cplus_instance (struct gcc_cp_context *gcc_cp)
: compile_instance (&gcc_cp->base, m_default_cflags),
m_plugin (gcc_cp)
{
m_plugin.set_callbacks (gcc_cplus_convert_symbol,
gcc_cplus_symbol_address,
gcc_cplus_enter_scope, gcc_cplus_leave_scope,
this);
}
/* Convert a gdb type, TYPE, to a GCC type.
If this type was defined in another type, NESTED_ACCESS should indicate
the accessibility of this type (or GCC_CP_ACCESS_NONE if not a nested
type). GCC_CP_ACCESS_NONE is the default nested access.
The new GCC type is returned. */
gcc_type convert_type
(struct type *type,
enum gcc_cp_symbol_kind nested_access = GCC_CP_ACCESS_NONE);
/* Return a handle for the GCC plug-in. */
gcc_cp_plugin &plugin () { return m_plugin; }
/* Factory method to create a new scope based on TYPE with name TYPE_NAME.
[TYPE_NAME could be TYPE_NAME or SYMBOL_NATURAL_NAME.]
If TYPE is a nested or local definition, nested_type () will return
the gcc_type of the conversion.
Otherwise, nested_type () is GCC_TYPE_NONE. */
compile_scope new_scope (const char *type_name, struct type *type);
/* Enter the given NEW_SCOPE. */
void enter_scope (compile_scope &scope);
/* Leave the current scope. */
void leave_scope ();
/* Add the qualifiers given by QUALS to BASE. */
gcc_type convert_qualified_base (gcc_type base,
gcc_cp_qualifiers_flags quals);
/* Convert TARGET into a pointer type. */
gcc_type convert_pointer_base (gcc_type target);
/* Convert BASE into a reference type. RQUALS describes the reference. */
gcc_type convert_reference_base (gcc_type base,
enum gcc_cp_ref_qualifiers rquals);
/* Return the declaration name of the symbol named NATURAL.
This returns a name with no function arguments or template parameters,
suitable for passing to the compiler plug-in. */
static gdb::unique_xmalloc_ptr<char> decl_name (const char *natural);
private:
/* Callbacks suitable for use as the GCC C++ enter/leave scope requests. */
static gcc_cp_enter_leave_user_expr_scope_function gcc_cplus_enter_scope;
static gcc_cp_enter_leave_user_expr_scope_function gcc_cplus_leave_scope;
/* Default compiler flags for C++. */
static const char *m_default_cflags;
/* The GCC plug-in. */
gcc_cp_plugin m_plugin;
/* A list of scopes we are processing. */
std::vector<compile_scope> m_scopes;
};
/* Get the access flag for the NUM'th method of TYPE's FNI'th
fieldlist. */
enum gcc_cp_symbol_kind get_method_access_flag (const struct type *type,
int fni, int num);
#endif /* GDB_COMPILE_CPLUS_H */

View File

@@ -164,6 +164,10 @@ protected:
#define COMPILE_I_EXPR_VAL "__gdb_expr_val"
#define COMPILE_I_EXPR_PTR_TYPE "__gdb_expr_ptr_type"
/* A "type" to indicate a NULL type. */
const gcc_type GCC_TYPE_NONE = (gcc_type) -1;
/* Call gdbarch_register_name (GDBARCH, REGNUM) and convert its result
to a form suitable for the compiler source. The register names
should not clash with inferior defined macros. */

View File

@@ -459,7 +459,8 @@ get_out_value_type (struct symbol *func_sym, struct objfile *objfile,
if (function != NULL
&& (BLOCK_SUPERBLOCK (function_block)
== BLOCKVECTOR_BLOCK (bv, STATIC_BLOCK))
&& (strcmp (SYMBOL_LINKAGE_NAME (function), GCC_FE_WRAPPER_FUNCTION)
&& (strcmp_iw (SYMBOL_LINKAGE_NAME (function),
GCC_FE_WRAPPER_FUNCTION)
== 0))
break;
}
@@ -478,7 +479,7 @@ get_out_value_type (struct symbol *func_sym, struct objfile *objfile,
gdb_ptr_type = check_typedef (gdb_ptr_type);
if (TYPE_CODE (gdb_ptr_type) != TYPE_CODE_PTR)
error (_("Type of \"%s\" is not a pointer"), COMPILE_I_EXPR_PTR_TYPE);
gdb_type_from_ptr = TYPE_TARGET_TYPE (gdb_ptr_type);
gdb_type_from_ptr = check_typedef (TYPE_TARGET_TYPE (gdb_ptr_type));
if (types_deeply_equal (gdb_type, gdb_type_from_ptr))
{
@@ -741,6 +742,8 @@ compile_object_load (const compile_file_names &file_names,
? mst_unknown : MSYMBOL_TYPE (bmsym.minsym))
{
case mst_text:
case mst_bss:
case mst_data:
sym->value = BMSYMBOL_VALUE_ADDRESS (bmsym);
if (compile_debug)
fprintf_unfiltered (gdb_stdlog,

View File

@@ -995,7 +995,6 @@ String quoting is parsed like in shell, for example:\n\
" -fPIE"
/* We want warnings, except for some commonly happening for GDB commands. */
" -Wall "
" -Wno-implicit-function-declaration"
" -Wno-unused-but-set-variable"
" -Wno-unused-variable"
/* Override CU's possible -fstack-protector-strong. */

View File

@@ -0,0 +1,85 @@
/* GCC C++ plug-in wrapper for GDB.
Copyright (C) 2018 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/>. */
/* A class representing the GCC C++ plug-in. */
#include "gcc-cp-interface.h"
class gcc_cp_plugin
{
public:
explicit gcc_cp_plugin (struct gcc_cp_context *gcc_cp)
: m_context (gcc_cp)
{
}
/* Set the oracle callbacks to be used by the compiler plug-in. */
void set_callbacks (gcc_cp_oracle_function *binding_oracle,
gcc_cp_symbol_address_function *address_oracle,
gcc_cp_enter_leave_user_expr_scope_function *enter_scope,
gcc_cp_enter_leave_user_expr_scope_function *leave_scope,
void *datum)
{
m_context->cp_ops->set_callbacks (m_context, binding_oracle,
address_oracle, enter_scope, leave_scope,
datum);
}
/* Returns the interface version of the compiler plug-in. */
int version () const { return m_context->cp_ops->cp_version; }
#define GCC_METHOD0(R, N) R N () const;
#define GCC_METHOD1(R, N, A) R N (A) const;
#define GCC_METHOD2(R, N, A, B) R N (A, B) const;
#define GCC_METHOD3(R, N, A, B, C) R N (A, B, C) const;
#define GCC_METHOD4(R, N, A, B, C, D) R N (A, B, C, D) const;
#define GCC_METHOD5(R, N, A, B, C, D, E) R N (A, B, C, D, E) const;
#define GCC_METHOD7(R, N, A, B, C, D, E, F, G) R N (A, B, C, D, E, F, G) const;
#include "gcc-cp-fe.def"
#undef GCC_METHOD0
#undef GCC_METHOD1
#undef GCC_METHOD2
#undef GCC_METHOD3
#undef GCC_METHOD4
#undef GCC_METHOD5
#undef GCC_METHOD7
/* Special overloads of plug-in methods with added debugging information. */
gcc_expr build_decl (const char *debug_decltype, const char *name,
enum gcc_cp_symbol_kind sym_kind, gcc_type sym_type,
const char *substitution_name, gcc_address address,
const char *filename, unsigned int line_number);
gcc_type start_class_type (const char *debug_name, gcc_decl typedecl,
const struct gcc_vbase_array *base_classes,
const char *filename, unsigned int line_number);
int finish_class_type (const char *debug_name, unsigned long size_in_bytes);
int pop_binding_level (const char *debug_name);
private:
/* The GCC C++ context. */
struct gcc_cp_context *m_context;
};